@cimplify/sdk 0.103.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-DHBwvh7U.d.ts → catalogue-BlQ85Uma.d.mts} +492 -748
- package/dist/{client-BfpNjJ_a.d.mts → catalogue-C8TqOj9K.d.ts} +492 -748
- package/dist/{payment-H5LoIvXU.d.mts → checkout-BqK9XUz5.d.mts} +4338 -1495
- package/dist/{payment-H5LoIvXU.d.ts → checkout-BqK9XUz5.d.ts} +4338 -1495
- package/dist/{chunk-GOHSXBKW.mjs → chunk-33VCYWVL.mjs} +25 -1
- package/dist/{chunk-C2JSNJUC.mjs → chunk-6G3ANKQA.mjs} +1080 -369
- package/dist/{chunk-QOWPGS7Z.js → chunk-BWEIMKLF.js} +572 -17
- package/dist/{chunk-JSWJ4XDE.js → chunk-DQEXY542.js} +1630 -824
- package/dist/{chunk-CNN7Z2IP.js → chunk-EV2EVOYS.js} +27 -0
- package/dist/{chunk-VIL6IQCG.js → chunk-HYFA67A7.js} +1084 -373
- package/dist/{chunk-H7ACMHM3.mjs → chunk-L5SNEU2O.mjs} +553 -16
- package/dist/{chunk-JG5CQNCB.js → chunk-RBNBSQI7.mjs} +221 -19
- package/dist/{chunk-VNPEYLB2.mjs → chunk-SFUJMS5E.js} +265 -2
- package/dist/{chunk-M4URVKHE.mjs → chunk-U54CWUUT.mjs} +11 -2
- package/dist/{chunk-GERXZQSX.mjs → chunk-UFOWPN3D.mjs} +967 -582
- package/dist/{chunk-J6PNHDHL.mjs → chunk-V4457OKB.mjs} +1580 -785
- package/dist/{chunk-R6OLQ33I.js → chunk-WXREIBFW.js} +1041 -654
- package/dist/{chunk-NNG6IFFX.js → chunk-XAUSDMMZ.js} +13 -3
- package/dist/{client-DpqRobY9.d.mts → client-DhXeiUrf.d.ts} +2 -2
- package/dist/{client-Dqg2mc-7.d.ts → client-mXiUrV4X.d.mts} +2 -2
- package/dist/{index-C8uDqLwJ.d.ts → index-B0AdZvrM.d.mts} +9 -4
- package/dist/{index-e2y6AK70.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 +34 -15
- package/dist/index.d.ts +34 -15
- package/dist/index.js +306 -133
- package/dist/index.mjs +7 -6
- package/dist/mock/cli.mjs +1494 -395
- package/dist/mock/library.js +1220 -361
- package/dist/mock/library.mjs +1220 -361
- package/dist/mock/msw.js +1220 -361
- package/dist/mock/msw.mjs +1220 -361
- package/dist/{price-C2RqscMY.d.ts → price-6hQIIac9.d.ts} +1 -1
- package/dist/{price-BvePgDXe.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 +279 -225
- package/dist/react.mjs +140 -86
- package/dist/{server-DoXIpSd7.d.ts → server-DJ0mSs9i.d.mts} +33 -57
- package/dist/{server-C7FyLdrz.d.mts → server-DSTX76Ki.d.ts} +33 -57
- package/dist/server.d.mts +3 -4
- package/dist/server.d.ts +3 -4
- package/dist/server.js +12 -11
- package/dist/server.mjs +6 -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 +2217 -14
- package/dist/testing.d.ts +2217 -14
- package/dist/testing.js +173 -83
- package/dist/testing.mjs +28 -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/chat-widget.json +1 -1
- package/registry/order-history.json +1 -1
- package/registry/order-summary.json +1 -1
- package/dist/link-cuNVYc2s.d.mts +0 -297
- package/dist/link-cuNVYc2s.d.ts +0 -297
package/dist/mock/cli.mjs
CHANGED
|
@@ -7,16 +7,164 @@ import { Http2ServerRequest, constants } from 'http2';
|
|
|
7
7
|
import { Readable } from 'stream';
|
|
8
8
|
import { createHmac } from 'crypto';
|
|
9
9
|
|
|
10
|
-
// ../node_modules/.bun/@hono+node-server@2.
|
|
10
|
+
// ../node_modules/.bun/@hono+node-server@2.1.1+804d2c5c04916069/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs
|
|
11
11
|
var X_ALREADY_SENT = "x-hono-already-sent";
|
|
12
12
|
|
|
13
|
-
// ../node_modules/.bun/@hono+node-server@2.
|
|
13
|
+
// ../node_modules/.bun/@hono+node-server@2.1.1+804d2c5c04916069/node_modules/@hono/node-server/dist/index.mjs
|
|
14
14
|
var RequestError = class extends Error {
|
|
15
15
|
constructor(message, options) {
|
|
16
16
|
super(message, options);
|
|
17
17
|
this.name = "RequestError";
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
+
var nonJoinedHeaders = /* @__PURE__ */ new Set([
|
|
21
|
+
"age",
|
|
22
|
+
"authorization",
|
|
23
|
+
"content-length",
|
|
24
|
+
"content-type",
|
|
25
|
+
"etag",
|
|
26
|
+
"expires",
|
|
27
|
+
"from",
|
|
28
|
+
"host",
|
|
29
|
+
"if-modified-since",
|
|
30
|
+
"if-unmodified-since",
|
|
31
|
+
"last-modified",
|
|
32
|
+
"location",
|
|
33
|
+
"max-forwards",
|
|
34
|
+
"proxy-authorization",
|
|
35
|
+
"referer",
|
|
36
|
+
"retry-after",
|
|
37
|
+
"server",
|
|
38
|
+
"user-agent"
|
|
39
|
+
]);
|
|
40
|
+
var validHeaderName = /^[!#$%&'*+\-.^_`|~\dA-Za-z]+$/;
|
|
41
|
+
var isHttpWhitespace = (code) => code === 9 || code === 10 || code === 13 || code === 32;
|
|
42
|
+
var normalizeHeaderValue = (value) => {
|
|
43
|
+
if (!isHttpWhitespace(value.charCodeAt(0)) && !isHttpWhitespace(value.charCodeAt(value.length - 1))) return value;
|
|
44
|
+
let start = 0;
|
|
45
|
+
let end = value.length;
|
|
46
|
+
while (start < end && isHttpWhitespace(value.charCodeAt(start))) start++;
|
|
47
|
+
while (end > start && isHttpWhitespace(value.charCodeAt(end - 1))) end--;
|
|
48
|
+
return value.slice(start, end);
|
|
49
|
+
};
|
|
50
|
+
var forbiddenHeaderValue = /[\0\r\n]/;
|
|
51
|
+
var GlobalHeaders = globalThis.Headers;
|
|
52
|
+
var materializeHeaders = (rawHeaders, HeadersCtor = GlobalHeaders) => {
|
|
53
|
+
const headers = new HeadersCtor();
|
|
54
|
+
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
55
|
+
const name = rawHeaders[i];
|
|
56
|
+
if (!name.startsWith(":")) headers.append(name, rawHeaders[i + 1]);
|
|
57
|
+
}
|
|
58
|
+
return headers;
|
|
59
|
+
};
|
|
60
|
+
var RequestHeaders = class {
|
|
61
|
+
#incoming;
|
|
62
|
+
#rawHeaders;
|
|
63
|
+
#headers;
|
|
64
|
+
#invalidValue;
|
|
65
|
+
constructor(incoming) {
|
|
66
|
+
this.#incoming = incoming;
|
|
67
|
+
if (incoming instanceof Http2ServerRequest) this.#rawHeaders = incoming.rawHeaders.slice();
|
|
68
|
+
}
|
|
69
|
+
get #lazyRawHeaders() {
|
|
70
|
+
return this.#rawHeaders ??= this.#incoming.rawHeaders.slice();
|
|
71
|
+
}
|
|
72
|
+
get #native() {
|
|
73
|
+
if (!this.#headers) {
|
|
74
|
+
this.#headers = materializeHeaders(this.#lazyRawHeaders);
|
|
75
|
+
this.#rawHeaders = void 0;
|
|
76
|
+
}
|
|
77
|
+
return this.#headers;
|
|
78
|
+
}
|
|
79
|
+
#normalizedName(name) {
|
|
80
|
+
if (typeof name !== "string") return;
|
|
81
|
+
if (!validHeaderName.test(name)) throw new TypeError(`Invalid header name: ${name}`);
|
|
82
|
+
return name.toLowerCase();
|
|
83
|
+
}
|
|
84
|
+
#lookupHttp1(lowerName) {
|
|
85
|
+
const headers = this.#incoming instanceof Http2ServerRequest ? void 0 : this.#incoming.headers;
|
|
86
|
+
if (!headers || nonJoinedHeaders.has(lowerName) || lowerName === "set-cookie" || lowerName === "__proto__") return;
|
|
87
|
+
if (!Object.hasOwn(headers, lowerName)) return null;
|
|
88
|
+
const rawValue = headers[lowerName];
|
|
89
|
+
if (typeof rawValue === "string") {
|
|
90
|
+
const value = normalizeHeaderValue(rawValue);
|
|
91
|
+
return forbiddenHeaderValue.test(value) ? void 0 : value;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
#lookup(rawHeaders, lowerName) {
|
|
95
|
+
const separator = lowerName === "cookie" ? "; " : ", ";
|
|
96
|
+
let value = null;
|
|
97
|
+
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
98
|
+
const rawName = rawHeaders[i];
|
|
99
|
+
if (rawName.length === lowerName.length && rawName.toLowerCase() === lowerName) {
|
|
100
|
+
const rawValue = normalizeHeaderValue(rawHeaders[i + 1]);
|
|
101
|
+
if (forbiddenHeaderValue.test(rawValue)) {
|
|
102
|
+
this.#invalidValue = true;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
value = value === null ? rawValue : value + separator + rawValue;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
append(name, value) {
|
|
111
|
+
this.#native.append(name, value);
|
|
112
|
+
}
|
|
113
|
+
delete(name) {
|
|
114
|
+
this.#native.delete(name);
|
|
115
|
+
}
|
|
116
|
+
get(name) {
|
|
117
|
+
const lowerName = this.#normalizedName(name);
|
|
118
|
+
if (lowerName && !this.#headers && !this.#invalidValue) {
|
|
119
|
+
const http1Value = this.#lookupHttp1(lowerName);
|
|
120
|
+
if (http1Value !== void 0) return http1Value;
|
|
121
|
+
const value = this.#lookup(this.#lazyRawHeaders, lowerName);
|
|
122
|
+
if (value !== void 0) return value;
|
|
123
|
+
}
|
|
124
|
+
return this.#native.get(name);
|
|
125
|
+
}
|
|
126
|
+
has(name) {
|
|
127
|
+
const lowerName = this.#normalizedName(name);
|
|
128
|
+
if (lowerName && !this.#headers && !this.#invalidValue) {
|
|
129
|
+
const http1Value = this.#lookupHttp1(lowerName);
|
|
130
|
+
if (http1Value !== void 0) return http1Value !== null;
|
|
131
|
+
const value = this.#lookup(this.#lazyRawHeaders, lowerName);
|
|
132
|
+
if (value !== void 0) return value !== null;
|
|
133
|
+
}
|
|
134
|
+
return this.#native.has(name);
|
|
135
|
+
}
|
|
136
|
+
set(name, value) {
|
|
137
|
+
this.#native.set(name, value);
|
|
138
|
+
}
|
|
139
|
+
getSetCookie() {
|
|
140
|
+
return this.#native.getSetCookie();
|
|
141
|
+
}
|
|
142
|
+
keys() {
|
|
143
|
+
return this.#native.keys();
|
|
144
|
+
}
|
|
145
|
+
values() {
|
|
146
|
+
return this.#native.values();
|
|
147
|
+
}
|
|
148
|
+
entries() {
|
|
149
|
+
return this.#native.entries();
|
|
150
|
+
}
|
|
151
|
+
forEach(callback, thisArg) {
|
|
152
|
+
this.#native.forEach((value, key) => {
|
|
153
|
+
callback.call(thisArg, value, key, this);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
[Symbol.iterator]() {
|
|
157
|
+
return this.entries();
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
Object.defineProperty(RequestHeaders.prototype, /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
|
|
161
|
+
return `Headers (lightweight) ${inspectFn(Object.fromEntries(this), {
|
|
162
|
+
...options,
|
|
163
|
+
depth: depth == null ? null : depth - 1
|
|
164
|
+
})}`;
|
|
165
|
+
} });
|
|
166
|
+
Object.setPrototypeOf(RequestHeaders.prototype, GlobalHeaders.prototype);
|
|
167
|
+
var newHeadersFromIncoming = (incoming) => globalThis.Headers === GlobalHeaders ? new RequestHeaders(incoming) : materializeHeaders(incoming.rawHeaders, globalThis.Headers);
|
|
20
168
|
var reValidRequestUrl = /^\/[!#$&-;=?-\[\]_a-z~]*$/;
|
|
21
169
|
var reDotSegment = /\/\.\.?(?:[/?#]|$)/;
|
|
22
170
|
var reValidHost = /^[a-z0-9._-]+(?::(?:[1-5]\d{3,4}|[6-9]\d{3}))?$/;
|
|
@@ -49,16 +197,55 @@ var Request$1 = class extends GlobalRequest {
|
|
|
49
197
|
super(input, options);
|
|
50
198
|
}
|
|
51
199
|
};
|
|
52
|
-
var newHeadersFromIncoming = (incoming) => {
|
|
53
|
-
const headerRecord = [];
|
|
54
|
-
const rawHeaders = incoming.rawHeaders;
|
|
55
|
-
for (let i = 0, len = rawHeaders.length; i < len; i += 2) {
|
|
56
|
-
const key = rawHeaders[i];
|
|
57
|
-
if (key.charCodeAt(0) !== 58) headerRecord.push([key, rawHeaders[i + 1]]);
|
|
58
|
-
}
|
|
59
|
-
return new Headers(headerRecord);
|
|
60
|
-
};
|
|
61
200
|
var wrapBodyStream = /* @__PURE__ */ Symbol("wrapBodyStream");
|
|
201
|
+
var byteExactEncodings = /* @__PURE__ */ new Set([
|
|
202
|
+
"latin1",
|
|
203
|
+
"binary",
|
|
204
|
+
"hex",
|
|
205
|
+
"base64",
|
|
206
|
+
"base64url"
|
|
207
|
+
]);
|
|
208
|
+
var isByteExactEncoding = (encoding) => encoding === null || byteExactEncodings.has(encoding);
|
|
209
|
+
var bodyBufferedBeforeDisconnectKey = /* @__PURE__ */ Symbol("bodyBufferedBeforeDisconnect");
|
|
210
|
+
var bodyBufferedLengthBeforeDisconnectKey = /* @__PURE__ */ Symbol("bodyBufferedLengthBeforeDisconnect");
|
|
211
|
+
var toBufferChunk = (chunk, encoding) => Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding ?? "utf8");
|
|
212
|
+
var isRecoverableDisconnectedIncoming = (incoming) => !(incoming instanceof Http2ServerRequest) && !!incoming.complete && !!incoming.readableAborted && typeof incoming.read === "function" && isByteExactEncoding(incoming.readableEncoding);
|
|
213
|
+
var recordBodyBufferedBeforeDisconnect = (incoming) => {
|
|
214
|
+
if (incoming.readableDidRead || !isRecoverableDisconnectedIncoming(incoming)) return;
|
|
215
|
+
const incomingWithRecovery = incoming;
|
|
216
|
+
incomingWithRecovery[bodyBufferedLengthBeforeDisconnectKey] ??= incoming.readableLength;
|
|
217
|
+
};
|
|
218
|
+
var readBodyBufferedBeforeDisconnect = (incoming, chunks) => {
|
|
219
|
+
if (incoming.readableDidRead && !chunks || !isRecoverableDisconnectedIncoming(incoming)) return;
|
|
220
|
+
const incomingWithRecovery = incoming;
|
|
221
|
+
if (incomingWithRecovery[bodyBufferedBeforeDisconnectKey] !== void 0) return incomingWithRecovery[bodyBufferedBeforeDisconnectKey];
|
|
222
|
+
let result;
|
|
223
|
+
const errored = incoming.errored;
|
|
224
|
+
if (errored && errored.code !== "ECONNRESET") result = errored;
|
|
225
|
+
else if (incomingWithRecovery[bodyBufferedLengthBeforeDisconnectKey] !== void 0 && incoming.readableLength !== incomingWithRecovery[bodyBufferedLengthBeforeDisconnectKey]) result = newBodyUnusableError();
|
|
226
|
+
else {
|
|
227
|
+
const bodyChunks = chunks ?? [];
|
|
228
|
+
const chunk = incoming.read();
|
|
229
|
+
if (chunk !== null) bodyChunks.push(toBufferChunk(chunk, incoming.readableEncoding));
|
|
230
|
+
const buffer = bodyChunks.length === 1 ? bodyChunks[0] : Buffer.concat(bodyChunks);
|
|
231
|
+
result = buffer;
|
|
232
|
+
const contentLength = incoming.headers["content-length"];
|
|
233
|
+
if (typeof contentLength === "string" && /^\d+$/.test(contentLength)) {
|
|
234
|
+
const expectedLength = Number(contentLength);
|
|
235
|
+
if (Number.isSafeInteger(expectedLength) && buffer.length !== expectedLength) result = newBodyUnusableError();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
incomingWithRecovery[bodyBufferedBeforeDisconnectKey] = result;
|
|
239
|
+
return result;
|
|
240
|
+
};
|
|
241
|
+
var enqueueBufferedBody = (controller, buffered) => {
|
|
242
|
+
if (buffered instanceof Error) {
|
|
243
|
+
controller.error(buffered);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (buffered.length > 0) controller.enqueue(buffered);
|
|
247
|
+
controller.close();
|
|
248
|
+
};
|
|
62
249
|
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
|
63
250
|
const init = {
|
|
64
251
|
method,
|
|
@@ -81,6 +268,13 @@ var newRequestFromIncoming = (method, url, headers, incoming, abortController) =
|
|
|
81
268
|
let reader;
|
|
82
269
|
init.body = new ReadableStream({ async pull(controller) {
|
|
83
270
|
try {
|
|
271
|
+
if (!reader) {
|
|
272
|
+
const buffered = readBodyBufferedBeforeDisconnect(incoming);
|
|
273
|
+
if (buffered !== void 0) {
|
|
274
|
+
enqueueBufferedBody(controller, buffered);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
84
278
|
reader ||= Readable.toWeb(incoming).getReader();
|
|
85
279
|
const { done, value } = await reader.read();
|
|
86
280
|
if (done) controller.close();
|
|
@@ -89,7 +283,13 @@ var newRequestFromIncoming = (method, url, headers, incoming, abortController) =
|
|
|
89
283
|
controller.error(error);
|
|
90
284
|
}
|
|
91
285
|
} });
|
|
92
|
-
} else
|
|
286
|
+
} else {
|
|
287
|
+
const buffered = readBodyBufferedBeforeDisconnect(incoming);
|
|
288
|
+
if (buffered !== void 0) init.body = new ReadableStream({ start(controller) {
|
|
289
|
+
enqueueBufferedBody(controller, buffered);
|
|
290
|
+
} });
|
|
291
|
+
else init.body = Readable.toWeb(incoming);
|
|
292
|
+
}
|
|
93
293
|
return new Request$1(url, init);
|
|
94
294
|
};
|
|
95
295
|
var getRequestCache = /* @__PURE__ */ Symbol("getRequestCache");
|
|
@@ -131,8 +331,10 @@ var normalizeIncomingMethod = (method) => {
|
|
|
131
331
|
case "GET":
|
|
132
332
|
case "HEAD":
|
|
133
333
|
case "OPTIONS":
|
|
334
|
+
case "PATCH":
|
|
134
335
|
case "POST":
|
|
135
336
|
case "PUT":
|
|
337
|
+
case "QUERY":
|
|
136
338
|
return method;
|
|
137
339
|
}
|
|
138
340
|
const upper = method.toUpperCase();
|
|
@@ -180,11 +382,23 @@ var readRawBodyIfAvailable = (request) => {
|
|
|
180
382
|
const incoming = request[incomingKey];
|
|
181
383
|
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) return incoming.rawBody;
|
|
182
384
|
};
|
|
385
|
+
var normalizeAbortError = (request, incoming) => {
|
|
386
|
+
if (incoming.errored) return incoming.errored;
|
|
387
|
+
const reason = request[abortReasonKey];
|
|
388
|
+
if (reason !== void 0) return reason instanceof Error ? reason : new Error(String(reason));
|
|
389
|
+
return /* @__PURE__ */ new Error("Client connection prematurely closed.");
|
|
390
|
+
};
|
|
183
391
|
var readBodyDirect = (request) => {
|
|
184
392
|
if (request[bodyBufferKey]) return Promise.resolve(request[bodyBufferKey]);
|
|
185
393
|
if (request[bodyReadPromiseKey]) return request[bodyReadPromiseKey];
|
|
186
394
|
const incoming = request[incomingKey];
|
|
187
|
-
if (
|
|
395
|
+
if (incoming.readableDidRead) return rejectBodyUnusable();
|
|
396
|
+
const buffered = readBodyBufferedBeforeDisconnect(incoming);
|
|
397
|
+
if (buffered !== void 0) {
|
|
398
|
+
if (buffered instanceof Error) return Promise.reject(buffered);
|
|
399
|
+
request[bodyBufferKey] = buffered;
|
|
400
|
+
return Promise.resolve(buffered);
|
|
401
|
+
}
|
|
188
402
|
const promise = new Promise((resolve2, reject) => {
|
|
189
403
|
const chunks = [];
|
|
190
404
|
let settled = false;
|
|
@@ -194,8 +408,22 @@ var readBodyDirect = (request) => {
|
|
|
194
408
|
cleanup();
|
|
195
409
|
callback();
|
|
196
410
|
};
|
|
411
|
+
const recoverCompleteBodyAfterDisconnect = (error) => {
|
|
412
|
+
const streamError = incoming.errored ?? error;
|
|
413
|
+
if (!isRecoverableDisconnectedIncoming(incoming) || streamError && streamError.code !== "ECONNRESET") return false;
|
|
414
|
+
finish(() => {
|
|
415
|
+
const recovered = readBodyBufferedBeforeDisconnect(incoming, chunks);
|
|
416
|
+
if (recovered instanceof Error) reject(recovered);
|
|
417
|
+
else if (recovered === void 0) reject(error ?? normalizeAbortError(request, incoming));
|
|
418
|
+
else {
|
|
419
|
+
request[bodyBufferKey] = recovered;
|
|
420
|
+
resolve2(recovered);
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
return true;
|
|
424
|
+
};
|
|
197
425
|
const onData = (chunk) => {
|
|
198
|
-
chunks.push(
|
|
426
|
+
chunks.push(toBufferChunk(chunk, incoming.readableEncoding));
|
|
199
427
|
};
|
|
200
428
|
const onEnd = () => {
|
|
201
429
|
finish(() => {
|
|
@@ -205,6 +433,7 @@ var readBodyDirect = (request) => {
|
|
|
205
433
|
});
|
|
206
434
|
};
|
|
207
435
|
const onError = (error) => {
|
|
436
|
+
if (recoverCompleteBodyAfterDisconnect(error)) return;
|
|
208
437
|
finish(() => {
|
|
209
438
|
reject(error);
|
|
210
439
|
});
|
|
@@ -214,17 +443,9 @@ var readBodyDirect = (request) => {
|
|
|
214
443
|
onEnd();
|
|
215
444
|
return;
|
|
216
445
|
}
|
|
446
|
+
if (recoverCompleteBodyAfterDisconnect()) return;
|
|
217
447
|
finish(() => {
|
|
218
|
-
|
|
219
|
-
reject(incoming.errored);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
const reason = request[abortReasonKey];
|
|
223
|
-
if (reason !== void 0) {
|
|
224
|
-
reject(reason instanceof Error ? reason : new Error(String(reason)));
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
reject(/* @__PURE__ */ new Error("Client connection prematurely closed."));
|
|
448
|
+
reject(normalizeAbortError(request, incoming));
|
|
228
449
|
});
|
|
229
450
|
};
|
|
230
451
|
const cleanup = () => {
|
|
@@ -403,23 +624,23 @@ var Response$1 = class Response$12 {
|
|
|
403
624
|
const liveHeaders = cache && cache[2] instanceof Headers ? cache[2] : void 0;
|
|
404
625
|
delete this[cacheKey];
|
|
405
626
|
return this[responseCache] ||= new GlobalResponse(this.#body, liveHeaders ? {
|
|
406
|
-
|
|
627
|
+
status: this.#init?.status,
|
|
628
|
+
statusText: this.#init?.statusText,
|
|
407
629
|
headers: liveHeaders
|
|
408
630
|
} : this.#init);
|
|
409
631
|
}
|
|
410
632
|
constructor(body, init) {
|
|
411
633
|
let headers;
|
|
412
634
|
this.#body = body;
|
|
413
|
-
if (init instanceof
|
|
635
|
+
if (init instanceof GlobalResponse) {
|
|
414
636
|
const cachedGlobalResponse = init[responseCache];
|
|
415
637
|
if (cachedGlobalResponse) {
|
|
416
638
|
this.#init = cachedGlobalResponse;
|
|
417
639
|
this[getResponseCache]();
|
|
418
640
|
return;
|
|
419
|
-
} else {
|
|
420
|
-
this.#init = init.#init;
|
|
421
|
-
headers = new Headers(init.headers);
|
|
422
641
|
}
|
|
642
|
+
this.#init = init instanceof Response$12 ? init.#init : init;
|
|
643
|
+
headers = new Headers(init.headers);
|
|
423
644
|
} else this.#init = init;
|
|
424
645
|
if (body == null || typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [
|
|
425
646
|
init?.status || 200,
|
|
@@ -597,7 +818,10 @@ var drainIncoming = (incoming) => {
|
|
|
597
818
|
const forceClose = () => {
|
|
598
819
|
cleanup();
|
|
599
820
|
const socket = incoming.socket;
|
|
600
|
-
if (socket && !socket.destroyed)
|
|
821
|
+
if (socket && !socket.destroyed) {
|
|
822
|
+
if (typeof socket.destroySoon === "function") socket.destroySoon();
|
|
823
|
+
else if (typeof socket.destroy === "function") socket.destroy();
|
|
824
|
+
}
|
|
601
825
|
};
|
|
602
826
|
const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS);
|
|
603
827
|
timer.unref?.();
|
|
@@ -611,8 +835,13 @@ var drainIncoming = (incoming) => {
|
|
|
611
835
|
incoming.resume();
|
|
612
836
|
};
|
|
613
837
|
var makeCloseHandler = (req, incoming, outgoing, needsBodyCleanup) => () => {
|
|
614
|
-
if (incoming.errored)
|
|
615
|
-
|
|
838
|
+
if (incoming.errored) {
|
|
839
|
+
recordBodyBufferedBeforeDisconnect(incoming);
|
|
840
|
+
req[abortRequest](incoming.errored.toString());
|
|
841
|
+
} else if (!outgoing.writableFinished) {
|
|
842
|
+
recordBodyBufferedBeforeDisconnect(incoming);
|
|
843
|
+
req[abortRequest]("Client connection prematurely closed.");
|
|
844
|
+
}
|
|
616
845
|
if (needsBodyCleanup && !incoming.readableEnded) setTimeout(() => {
|
|
617
846
|
if (!incoming.readableEnded) setTimeout(() => {
|
|
618
847
|
drainIncoming(incoming);
|
|
@@ -863,10 +1092,18 @@ var setupWebSocket = (options) => {
|
|
|
863
1092
|
waiterMap.delete(request);
|
|
864
1093
|
}
|
|
865
1094
|
});
|
|
1095
|
+
const rejectWaiter = (request) => {
|
|
1096
|
+
const waiter = waiterMap.get(request);
|
|
1097
|
+
if (waiter) {
|
|
1098
|
+
waiterMap.delete(request);
|
|
1099
|
+
waiter.reject(/* @__PURE__ */ new Error("WebSocket handshake aborted"));
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
866
1102
|
const waitForWebSocket = (request, connectionSymbol) => {
|
|
867
|
-
return new Promise((resolve2) => {
|
|
1103
|
+
return new Promise((resolve2, reject) => {
|
|
868
1104
|
waiterMap.set(request, {
|
|
869
1105
|
resolve: resolve2,
|
|
1106
|
+
reject,
|
|
870
1107
|
connectionSymbol
|
|
871
1108
|
});
|
|
872
1109
|
});
|
|
@@ -893,16 +1130,19 @@ var setupWebSocket = (options) => {
|
|
|
893
1130
|
}
|
|
894
1131
|
const waiter = waiterMap.get(request);
|
|
895
1132
|
if (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {
|
|
896
|
-
|
|
1133
|
+
rejectWaiter(request);
|
|
897
1134
|
if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, status, responseHeaders);
|
|
898
1135
|
return;
|
|
899
1136
|
}
|
|
900
1137
|
const addResponseHeaders = (headers) => {
|
|
901
1138
|
appendResponseHeaders(headers, responseHeaders);
|
|
902
1139
|
};
|
|
1140
|
+
const reclaimWaiterOnClose = () => rejectWaiter(request);
|
|
1141
|
+
socket.once("close", reclaimWaiterOnClose);
|
|
903
1142
|
wss.on("headers", addResponseHeaders);
|
|
904
1143
|
try {
|
|
905
1144
|
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
1145
|
+
socket.off("close", reclaimWaiterOnClose);
|
|
906
1146
|
wss.emit("connection", ws, request);
|
|
907
1147
|
});
|
|
908
1148
|
} finally {
|
|
@@ -940,7 +1180,7 @@ var serve = (options, listeningListener) => {
|
|
|
940
1180
|
return server;
|
|
941
1181
|
};
|
|
942
1182
|
|
|
943
|
-
// ../node_modules/.bun/hono@4.
|
|
1183
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/compose.js
|
|
944
1184
|
var compose = (middleware, onError, onNotFound) => {
|
|
945
1185
|
return (context, next) => {
|
|
946
1186
|
let index = -1;
|
|
@@ -984,21 +1224,46 @@ var compose = (middleware, onError, onNotFound) => {
|
|
|
984
1224
|
};
|
|
985
1225
|
};
|
|
986
1226
|
|
|
987
|
-
// ../node_modules/.bun/hono@4.
|
|
1227
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/request/constants.js
|
|
988
1228
|
var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
|
|
989
1229
|
|
|
990
|
-
// ../node_modules/.bun/hono@4.
|
|
1230
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/buffer.js
|
|
1231
|
+
var bufferToFormData = (arrayBuffer, contentType2) => {
|
|
1232
|
+
const response = new Response(arrayBuffer, {
|
|
1233
|
+
headers: {
|
|
1234
|
+
// Normalize the media type (case-insensitive) while keeping parameters like the boundary
|
|
1235
|
+
"Content-Type": contentType2.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase())
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
return response.formData();
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1241
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/body.js
|
|
1242
|
+
var isRawRequest = (request) => "headers" in request;
|
|
991
1243
|
var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
|
|
992
1244
|
const { all = false, dot = false } = options;
|
|
993
|
-
const headers = request
|
|
1245
|
+
const headers = isRawRequest(request) ? request.headers : request.raw.headers;
|
|
994
1246
|
const contentType2 = headers.get("Content-Type");
|
|
995
|
-
|
|
1247
|
+
const mediaType = contentType2?.split(";")[0].trim().toLowerCase();
|
|
1248
|
+
if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded") {
|
|
996
1249
|
return parseFormData(request, { all, dot });
|
|
997
1250
|
}
|
|
998
1251
|
return {};
|
|
999
1252
|
};
|
|
1000
1253
|
async function parseFormData(request, options) {
|
|
1001
|
-
|
|
1254
|
+
if (!isRawRequest(request) && request.bodyCache.formData) {
|
|
1255
|
+
return convertFormDataToBodyData(
|
|
1256
|
+
await request.bodyCache.formData,
|
|
1257
|
+
options
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
const headers = isRawRequest(request) ? request.headers : request.raw.headers;
|
|
1261
|
+
const arrayBuffer = await request.arrayBuffer();
|
|
1262
|
+
const formDataPromise = bufferToFormData(arrayBuffer, headers.get("Content-Type") || "");
|
|
1263
|
+
if (!isRawRequest(request)) {
|
|
1264
|
+
request.bodyCache.formData = formDataPromise;
|
|
1265
|
+
}
|
|
1266
|
+
const formData = await formDataPromise;
|
|
1002
1267
|
if (formData) {
|
|
1003
1268
|
return convertFormDataToBodyData(formData, options);
|
|
1004
1269
|
}
|
|
@@ -1058,7 +1323,7 @@ var handleParsingNestedValues = (form, key, value) => {
|
|
|
1058
1323
|
});
|
|
1059
1324
|
};
|
|
1060
1325
|
|
|
1061
|
-
// ../node_modules/.bun/hono@4.
|
|
1326
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/url.js
|
|
1062
1327
|
var splitPath = (path) => {
|
|
1063
1328
|
const paths = path.split("/");
|
|
1064
1329
|
if (paths[0] === "") {
|
|
@@ -1164,13 +1429,13 @@ var checkOptionalParameter = (path) => {
|
|
|
1164
1429
|
if (segment !== "" && !/\:/.test(segment)) {
|
|
1165
1430
|
basePath += "/" + segment;
|
|
1166
1431
|
} else if (/\:/.test(segment)) {
|
|
1167
|
-
if (
|
|
1432
|
+
if (segment.charCodeAt(segment.length - 1) === 63) {
|
|
1168
1433
|
if (results.length === 0 && basePath === "") {
|
|
1169
1434
|
results.push("/");
|
|
1170
1435
|
} else {
|
|
1171
1436
|
results.push(basePath);
|
|
1172
1437
|
}
|
|
1173
|
-
const optionalSegment = segment.
|
|
1438
|
+
const optionalSegment = segment.slice(0, -1);
|
|
1174
1439
|
basePath += "/" + optionalSegment;
|
|
1175
1440
|
results.push(basePath);
|
|
1176
1441
|
} else {
|
|
@@ -1180,18 +1445,16 @@ var checkOptionalParameter = (path) => {
|
|
|
1180
1445
|
});
|
|
1181
1446
|
return results.filter((v, i, a) => a.indexOf(v) === i);
|
|
1182
1447
|
};
|
|
1448
|
+
var tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
|
|
1183
1449
|
var _decodeURI = (value) => {
|
|
1184
|
-
if (!/[%+]/.test(value)) {
|
|
1185
|
-
return value;
|
|
1186
|
-
}
|
|
1187
1450
|
if (value.indexOf("+") !== -1) {
|
|
1188
1451
|
value = value.replace(/\+/g, " ");
|
|
1189
1452
|
}
|
|
1190
|
-
return
|
|
1453
|
+
return tryDecodeURIComponent(value);
|
|
1191
1454
|
};
|
|
1192
1455
|
var _getQueryParam = (url, key, multiple) => {
|
|
1193
1456
|
let encoded;
|
|
1194
|
-
if (!multiple && key &&
|
|
1457
|
+
if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
|
|
1195
1458
|
let keyIndex2 = url.indexOf("?", 8);
|
|
1196
1459
|
if (keyIndex2 === -1) {
|
|
1197
1460
|
return void 0;
|
|
@@ -1215,7 +1478,7 @@ var _getQueryParam = (url, key, multiple) => {
|
|
|
1215
1478
|
return void 0;
|
|
1216
1479
|
}
|
|
1217
1480
|
}
|
|
1218
|
-
const results =
|
|
1481
|
+
const results = /* @__PURE__ */ Object.create(null);
|
|
1219
1482
|
encoded ??= /[%+]/.test(url);
|
|
1220
1483
|
let keyIndex = url.indexOf("?", 8);
|
|
1221
1484
|
while (keyIndex !== -1) {
|
|
@@ -1261,8 +1524,7 @@ var getQueryParams = (url, key) => {
|
|
|
1261
1524
|
};
|
|
1262
1525
|
var decodeURIComponent_ = decodeURIComponent;
|
|
1263
1526
|
|
|
1264
|
-
// ../node_modules/.bun/hono@4.
|
|
1265
|
-
var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
|
|
1527
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/request.js
|
|
1266
1528
|
var HonoRequest = class {
|
|
1267
1529
|
/**
|
|
1268
1530
|
* `.raw` can get the raw Request object.
|
|
@@ -1301,7 +1563,6 @@ var HonoRequest = class {
|
|
|
1301
1563
|
this.raw = request;
|
|
1302
1564
|
this.path = path;
|
|
1303
1565
|
this.#matchResult = matchResult;
|
|
1304
|
-
this.#validatedData = {};
|
|
1305
1566
|
}
|
|
1306
1567
|
param(key) {
|
|
1307
1568
|
return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
|
|
@@ -1309,7 +1570,7 @@ var HonoRequest = class {
|
|
|
1309
1570
|
#getDecodedParam(key) {
|
|
1310
1571
|
const paramKey = this.#matchResult[0][this.routeIndex][1][key];
|
|
1311
1572
|
const param = this.#getParamValue(paramKey);
|
|
1312
|
-
return param &&
|
|
1573
|
+
return param && tryDecodeURIComponent(param);
|
|
1313
1574
|
}
|
|
1314
1575
|
#getAllDecodedParams() {
|
|
1315
1576
|
const decoded = {};
|
|
@@ -1317,7 +1578,7 @@ var HonoRequest = class {
|
|
|
1317
1578
|
for (const key of keys) {
|
|
1318
1579
|
const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
|
|
1319
1580
|
if (value !== void 0) {
|
|
1320
|
-
decoded[key] =
|
|
1581
|
+
decoded[key] = tryDecodeURIComponent(value);
|
|
1321
1582
|
}
|
|
1322
1583
|
}
|
|
1323
1584
|
return decoded;
|
|
@@ -1335,7 +1596,7 @@ var HonoRequest = class {
|
|
|
1335
1596
|
if (name) {
|
|
1336
1597
|
return this.raw.headers.get(name) ?? void 0;
|
|
1337
1598
|
}
|
|
1338
|
-
const headerData =
|
|
1599
|
+
const headerData = /* @__PURE__ */ Object.create(null);
|
|
1339
1600
|
this.raw.headers.forEach((value, key) => {
|
|
1340
1601
|
headerData[key] = value;
|
|
1341
1602
|
});
|
|
@@ -1350,8 +1611,7 @@ var HonoRequest = class {
|
|
|
1350
1611
|
if (cachedBody) {
|
|
1351
1612
|
return cachedBody;
|
|
1352
1613
|
}
|
|
1353
|
-
const anyCachedKey
|
|
1354
|
-
if (anyCachedKey) {
|
|
1614
|
+
for (const anyCachedKey in bodyCache) {
|
|
1355
1615
|
return bodyCache[anyCachedKey].then((body) => {
|
|
1356
1616
|
if (anyCachedKey === "json") {
|
|
1357
1617
|
body = JSON.stringify(body);
|
|
@@ -1454,10 +1714,10 @@ var HonoRequest = class {
|
|
|
1454
1714
|
* @param data - The validated data to add.
|
|
1455
1715
|
*/
|
|
1456
1716
|
addValidatedData(target, data) {
|
|
1457
|
-
this.#validatedData[target] = data;
|
|
1717
|
+
(this.#validatedData ??= {})[target] = data;
|
|
1458
1718
|
}
|
|
1459
1719
|
valid(target) {
|
|
1460
|
-
return this.#validatedData[target];
|
|
1720
|
+
return this.#validatedData?.[target];
|
|
1461
1721
|
}
|
|
1462
1722
|
/**
|
|
1463
1723
|
* `.url()` can get the request url strings.
|
|
@@ -1544,7 +1804,7 @@ var HonoRequest = class {
|
|
|
1544
1804
|
}
|
|
1545
1805
|
};
|
|
1546
1806
|
|
|
1547
|
-
// ../node_modules/.bun/hono@4.
|
|
1807
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/html.js
|
|
1548
1808
|
var HtmlEscapedCallbackPhase = {
|
|
1549
1809
|
Stringify: 1};
|
|
1550
1810
|
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
@@ -1575,7 +1835,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
|
|
|
1575
1835
|
}
|
|
1576
1836
|
};
|
|
1577
1837
|
|
|
1578
|
-
// ../node_modules/.bun/hono@4.
|
|
1838
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/context.js
|
|
1579
1839
|
var TEXT_PLAIN = "text/plain; charset=UTF-8";
|
|
1580
1840
|
var setDefaultContentType = (contentType2, headers) => {
|
|
1581
1841
|
return {
|
|
@@ -1848,11 +2108,11 @@ var Context = class {
|
|
|
1848
2108
|
return Object.fromEntries(this.#var);
|
|
1849
2109
|
}
|
|
1850
2110
|
#newResponse(data, arg, headers) {
|
|
1851
|
-
|
|
1852
|
-
if (typeof arg === "object" &&
|
|
1853
|
-
|
|
1854
|
-
for (const [key, value] of
|
|
1855
|
-
if (key
|
|
2111
|
+
let responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders;
|
|
2112
|
+
if (typeof arg === "object" && arg.headers) {
|
|
2113
|
+
responseHeaders ??= new Headers();
|
|
2114
|
+
for (const [key, value] of new Headers(arg.headers)) {
|
|
2115
|
+
if (key === "set-cookie") {
|
|
1856
2116
|
responseHeaders.append(key, value);
|
|
1857
2117
|
} else {
|
|
1858
2118
|
responseHeaders.set(key, value);
|
|
@@ -1860,19 +2120,34 @@ var Context = class {
|
|
|
1860
2120
|
}
|
|
1861
2121
|
}
|
|
1862
2122
|
if (headers) {
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2123
|
+
if (!responseHeaders) {
|
|
2124
|
+
let count = 0;
|
|
2125
|
+
for (const k in headers) {
|
|
2126
|
+
if (++count > 1 || typeof headers[k] !== "string") {
|
|
2127
|
+
responseHeaders = new Headers();
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
if (responseHeaders) {
|
|
2133
|
+
for (const k in headers) {
|
|
2134
|
+
const v = headers[k];
|
|
2135
|
+
if (typeof v === "string") {
|
|
2136
|
+
responseHeaders.set(k, v);
|
|
2137
|
+
} else {
|
|
2138
|
+
responseHeaders.delete(k);
|
|
2139
|
+
for (const v2 of v) {
|
|
2140
|
+
responseHeaders.append(k, v2);
|
|
2141
|
+
}
|
|
1870
2142
|
}
|
|
1871
2143
|
}
|
|
1872
2144
|
}
|
|
1873
2145
|
}
|
|
1874
2146
|
const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
|
|
1875
|
-
return createResponseInstance(data, {
|
|
2147
|
+
return createResponseInstance(data, {
|
|
2148
|
+
status,
|
|
2149
|
+
headers: responseHeaders ?? headers
|
|
2150
|
+
});
|
|
1876
2151
|
}
|
|
1877
2152
|
newResponse = (...args) => this.#newResponse(...args);
|
|
1878
2153
|
/**
|
|
@@ -1982,18 +2257,18 @@ var Context = class {
|
|
|
1982
2257
|
};
|
|
1983
2258
|
};
|
|
1984
2259
|
|
|
1985
|
-
// ../node_modules/.bun/hono@4.
|
|
2260
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router.js
|
|
1986
2261
|
var METHOD_NAME_ALL = "ALL";
|
|
1987
2262
|
var METHOD_NAME_ALL_LOWERCASE = "all";
|
|
1988
|
-
var METHODS = ["get", "post", "put", "delete", "options", "patch"];
|
|
2263
|
+
var METHODS = ["get", "post", "put", "delete", "options", "patch", "query"];
|
|
1989
2264
|
var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
|
|
1990
2265
|
var UnsupportedPathError = class extends Error {
|
|
1991
2266
|
};
|
|
1992
2267
|
|
|
1993
|
-
// ../node_modules/.bun/hono@4.
|
|
2268
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/utils/constants.js
|
|
1994
2269
|
var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
|
|
1995
2270
|
|
|
1996
|
-
// ../node_modules/.bun/hono@4.
|
|
2271
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/hono-base.js
|
|
1997
2272
|
var notFoundHandler = (c) => {
|
|
1998
2273
|
return c.text("404 Not Found", 404);
|
|
1999
2274
|
};
|
|
@@ -2012,6 +2287,7 @@ var Hono = class _Hono {
|
|
|
2012
2287
|
delete;
|
|
2013
2288
|
options;
|
|
2014
2289
|
patch;
|
|
2290
|
+
query;
|
|
2015
2291
|
all;
|
|
2016
2292
|
on;
|
|
2017
2293
|
use;
|
|
@@ -2311,8 +2587,8 @@ var Hono = class _Hono {
|
|
|
2311
2587
|
* @see {@link https://hono.dev/docs/api/hono#fetch}
|
|
2312
2588
|
*
|
|
2313
2589
|
* @param {Request} request - request Object of request
|
|
2314
|
-
* @param {Env}
|
|
2315
|
-
* @param {ExecutionContext} - context of execution
|
|
2590
|
+
* @param {Env} env - env Object
|
|
2591
|
+
* @param {ExecutionContext} executionCtx - context of execution
|
|
2316
2592
|
* @returns {Response | Promise<Response>} response of request
|
|
2317
2593
|
*
|
|
2318
2594
|
*/
|
|
@@ -2369,7 +2645,7 @@ var Hono = class _Hono {
|
|
|
2369
2645
|
};
|
|
2370
2646
|
};
|
|
2371
2647
|
|
|
2372
|
-
// ../node_modules/.bun/hono@4.
|
|
2648
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/reg-exp-router/matcher.js
|
|
2373
2649
|
var emptyParam = [];
|
|
2374
2650
|
function match(method, path) {
|
|
2375
2651
|
const matchers = this.buildAllMatchers();
|
|
@@ -2390,7 +2666,7 @@ function match(method, path) {
|
|
|
2390
2666
|
return match2(method, path);
|
|
2391
2667
|
}
|
|
2392
2668
|
|
|
2393
|
-
// ../node_modules/.bun/hono@4.
|
|
2669
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/reg-exp-router/node.js
|
|
2394
2670
|
var LABEL_REG_EXP_STR = "[^/]+";
|
|
2395
2671
|
var ONLY_WILDCARD_REG_EXP_STR = ".*";
|
|
2396
2672
|
var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
|
|
@@ -2404,7 +2680,7 @@ function compareKey(a, b) {
|
|
|
2404
2680
|
return 1;
|
|
2405
2681
|
}
|
|
2406
2682
|
if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
|
|
2407
|
-
return 1;
|
|
2683
|
+
return b === TAIL_WILDCARD_REG_EXP_STR ? -1 : 1;
|
|
2408
2684
|
} else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
|
|
2409
2685
|
return -1;
|
|
2410
2686
|
}
|
|
@@ -2416,76 +2692,75 @@ function compareKey(a, b) {
|
|
|
2416
2692
|
return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
|
|
2417
2693
|
}
|
|
2418
2694
|
var Node = class _Node {
|
|
2695
|
+
// handler index of a dynamic path, or -1 for a static path terminal
|
|
2419
2696
|
#index;
|
|
2420
2697
|
#varIndex;
|
|
2421
2698
|
#children = /* @__PURE__ */ Object.create(null);
|
|
2422
|
-
insert(tokens, index, paramMap, context,
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
}
|
|
2443
|
-
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
2444
|
-
if (/\((?!\?:)/.test(regexpStr)) {
|
|
2445
|
-
throw PATH_ERROR;
|
|
2446
|
-
}
|
|
2447
|
-
}
|
|
2448
|
-
node = this.#children[regexpStr];
|
|
2449
|
-
if (!node) {
|
|
2450
|
-
if (Object.keys(this.#children).some(
|
|
2451
|
-
(k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
2452
|
-
)) {
|
|
2453
|
-
throw PATH_ERROR;
|
|
2699
|
+
insert(tokens, index, paramMap, context, isStatic) {
|
|
2700
|
+
let node = this;
|
|
2701
|
+
for (let i = 0, len = tokens.length; i < len; i++) {
|
|
2702
|
+
const token = tokens[i];
|
|
2703
|
+
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(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
|
|
2704
|
+
let nextNode;
|
|
2705
|
+
if (pattern) {
|
|
2706
|
+
const name = pattern[1];
|
|
2707
|
+
let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
|
|
2708
|
+
if (name && pattern[2]) {
|
|
2709
|
+
if (regexpStr === ".*") {
|
|
2710
|
+
throw PATH_ERROR;
|
|
2711
|
+
}
|
|
2712
|
+
regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
|
|
2713
|
+
if (/\((?!\?:)/.test(regexpStr)) {
|
|
2714
|
+
throw PATH_ERROR;
|
|
2715
|
+
}
|
|
2716
|
+
if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) {
|
|
2717
|
+
throw PATH_ERROR;
|
|
2718
|
+
}
|
|
2454
2719
|
}
|
|
2455
|
-
|
|
2456
|
-
|
|
2720
|
+
nextNode = node.#children[regexpStr];
|
|
2721
|
+
if (!nextNode) {
|
|
2722
|
+
if (regexpStr !== ONLY_WILDCARD_REG_EXP_STR && regexpStr !== TAIL_WILDCARD_REG_EXP_STR) {
|
|
2723
|
+
for (const k in node.#children) {
|
|
2724
|
+
if (
|
|
2725
|
+
// a single-char pattern coexists with single-char literals as a literal does
|
|
2726
|
+
(regexpStr.length > 1 || k.length > 1) && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
2727
|
+
) {
|
|
2728
|
+
throw PATH_ERROR;
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
nextNode = node.#children[regexpStr] = new _Node();
|
|
2457
2733
|
}
|
|
2458
|
-
node = this.#children[regexpStr] = new _Node();
|
|
2459
2734
|
if (name !== "") {
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
}
|
|
2463
|
-
if (!pathErrorCheckOnly && name !== "") {
|
|
2464
|
-
paramMap.push([name, node.#varIndex]);
|
|
2465
|
-
}
|
|
2466
|
-
} else {
|
|
2467
|
-
node = this.#children[token];
|
|
2468
|
-
if (!node) {
|
|
2469
|
-
if (Object.keys(this.#children).some(
|
|
2470
|
-
(k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR
|
|
2471
|
-
)) {
|
|
2472
|
-
throw PATH_ERROR;
|
|
2735
|
+
nextNode.#varIndex ??= context.varIndex++;
|
|
2736
|
+
paramMap.push([name, nextNode.#varIndex]);
|
|
2473
2737
|
}
|
|
2474
|
-
|
|
2475
|
-
|
|
2738
|
+
} else {
|
|
2739
|
+
nextNode = node.#children[token];
|
|
2740
|
+
if (!nextNode) {
|
|
2741
|
+
for (const k in node.#children) {
|
|
2742
|
+
if (k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR) {
|
|
2743
|
+
throw PATH_ERROR;
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
nextNode = node.#children[token] = new _Node();
|
|
2476
2747
|
}
|
|
2477
|
-
node = this.#children[token] = new _Node();
|
|
2478
2748
|
}
|
|
2749
|
+
node = nextNode;
|
|
2479
2750
|
}
|
|
2480
|
-
node
|
|
2751
|
+
if (node.#index !== void 0) {
|
|
2752
|
+
throw PATH_ERROR;
|
|
2753
|
+
}
|
|
2754
|
+
node.#index = isStatic ? -1 : index;
|
|
2481
2755
|
}
|
|
2482
2756
|
buildRegExpStr() {
|
|
2483
2757
|
const childKeys = Object.keys(this.#children).sort(compareKey);
|
|
2484
2758
|
const strList = childKeys.map((k) => {
|
|
2485
2759
|
const c = this.#children[k];
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2760
|
+
const childStr = c.buildRegExpStr();
|
|
2761
|
+
return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + childStr;
|
|
2762
|
+
}).filter(Boolean);
|
|
2763
|
+
if (typeof this.#index === "number" && this.#index !== -1) {
|
|
2489
2764
|
strList.unshift(`#${this.#index}`);
|
|
2490
2765
|
}
|
|
2491
2766
|
if (strList.length === 0) {
|
|
@@ -2498,16 +2773,24 @@ var Node = class _Node {
|
|
|
2498
2773
|
}
|
|
2499
2774
|
};
|
|
2500
2775
|
|
|
2501
|
-
// ../node_modules/.bun/hono@4.
|
|
2776
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/reg-exp-router/trie.js
|
|
2502
2777
|
var Trie = class {
|
|
2503
2778
|
#context = { varIndex: 0 };
|
|
2504
2779
|
#root = new Node();
|
|
2505
|
-
|
|
2780
|
+
#index = 0;
|
|
2781
|
+
// dynamic path -> [handler index, param assoc]; static paths are not registered
|
|
2782
|
+
paths = /* @__PURE__ */ Object.create(null);
|
|
2783
|
+
insert(path, isStatic) {
|
|
2784
|
+
if (isStatic) {
|
|
2785
|
+
this.#root.insert(path.split(""), 0, [], this.#context, true);
|
|
2786
|
+
return;
|
|
2787
|
+
}
|
|
2506
2788
|
const paramAssoc = [];
|
|
2507
2789
|
const groups = [];
|
|
2790
|
+
let markedPath = path;
|
|
2508
2791
|
for (let i = 0; ; ) {
|
|
2509
2792
|
let replaced = false;
|
|
2510
|
-
|
|
2793
|
+
markedPath = markedPath.replace(/\{[^}]+\}/g, (m) => {
|
|
2511
2794
|
const mark = `@\\${i}`;
|
|
2512
2795
|
groups[i] = [mark, m];
|
|
2513
2796
|
i++;
|
|
@@ -2518,7 +2801,7 @@ var Trie = class {
|
|
|
2518
2801
|
break;
|
|
2519
2802
|
}
|
|
2520
2803
|
}
|
|
2521
|
-
const tokens =
|
|
2804
|
+
const tokens = markedPath.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
|
|
2522
2805
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
2523
2806
|
const [mark] = groups[i];
|
|
2524
2807
|
for (let j = tokens.length - 1; j >= 0; j--) {
|
|
@@ -2528,8 +2811,8 @@ var Trie = class {
|
|
|
2528
2811
|
}
|
|
2529
2812
|
}
|
|
2530
2813
|
}
|
|
2531
|
-
this.#root.insert(tokens, index, paramAssoc, this.#context,
|
|
2532
|
-
|
|
2814
|
+
this.#root.insert(tokens, this.#index, paramAssoc, this.#context, false);
|
|
2815
|
+
this.paths[path] = [this.#index++, paramAssoc];
|
|
2533
2816
|
}
|
|
2534
2817
|
buildRegExp() {
|
|
2535
2818
|
let regexp = this.#root.buildRegExpStr();
|
|
@@ -2554,8 +2837,7 @@ var Trie = class {
|
|
|
2554
2837
|
}
|
|
2555
2838
|
};
|
|
2556
2839
|
|
|
2557
|
-
// ../node_modules/.bun/hono@4.
|
|
2558
|
-
var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
|
|
2840
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/reg-exp-router/router.js
|
|
2559
2841
|
var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
2560
2842
|
function buildWildcardRegExp(path) {
|
|
2561
2843
|
return wildcardRegExpCache[path] ??= new RegExp(
|
|
@@ -2568,63 +2850,6 @@ function buildWildcardRegExp(path) {
|
|
|
2568
2850
|
function clearWildcardRegExpCache() {
|
|
2569
2851
|
wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
2570
2852
|
}
|
|
2571
|
-
function buildMatcherFromPreprocessedRoutes(routes) {
|
|
2572
|
-
const trie = new Trie();
|
|
2573
|
-
const handlerData = [];
|
|
2574
|
-
if (routes.length === 0) {
|
|
2575
|
-
return nullMatcher;
|
|
2576
|
-
}
|
|
2577
|
-
const routesWithStaticPathFlag = routes.map(
|
|
2578
|
-
(route) => [!/\*|\/:/.test(route[0]), ...route]
|
|
2579
|
-
).sort(
|
|
2580
|
-
([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
|
|
2581
|
-
);
|
|
2582
|
-
const staticMap = /* @__PURE__ */ Object.create(null);
|
|
2583
|
-
for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
|
|
2584
|
-
const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i];
|
|
2585
|
-
if (pathErrorCheckOnly) {
|
|
2586
|
-
staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
2587
|
-
} else {
|
|
2588
|
-
j++;
|
|
2589
|
-
}
|
|
2590
|
-
let paramAssoc;
|
|
2591
|
-
try {
|
|
2592
|
-
paramAssoc = trie.insert(path, j, pathErrorCheckOnly);
|
|
2593
|
-
} catch (e) {
|
|
2594
|
-
throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
|
|
2595
|
-
}
|
|
2596
|
-
if (pathErrorCheckOnly) {
|
|
2597
|
-
continue;
|
|
2598
|
-
}
|
|
2599
|
-
handlerData[j] = handlers.map(([h, paramCount]) => {
|
|
2600
|
-
const paramIndexMap = /* @__PURE__ */ Object.create(null);
|
|
2601
|
-
paramCount -= 1;
|
|
2602
|
-
for (; paramCount >= 0; paramCount--) {
|
|
2603
|
-
const [key, value] = paramAssoc[paramCount];
|
|
2604
|
-
paramIndexMap[key] = value;
|
|
2605
|
-
}
|
|
2606
|
-
return [h, paramIndexMap];
|
|
2607
|
-
});
|
|
2608
|
-
}
|
|
2609
|
-
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
2610
|
-
for (let i = 0, len = handlerData.length; i < len; i++) {
|
|
2611
|
-
for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
|
|
2612
|
-
const map = handlerData[i][j]?.[1];
|
|
2613
|
-
if (!map) {
|
|
2614
|
-
continue;
|
|
2615
|
-
}
|
|
2616
|
-
const keys = Object.keys(map);
|
|
2617
|
-
for (let k = 0, len3 = keys.length; k < len3; k++) {
|
|
2618
|
-
map[keys[k]] = paramReplacementMap[map[keys[k]]];
|
|
2619
|
-
}
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
const handlerMap = [];
|
|
2623
|
-
for (const i in indexReplacementMap) {
|
|
2624
|
-
handlerMap[i] = handlerData[indexReplacementMap[i]];
|
|
2625
|
-
}
|
|
2626
|
-
return [regexp, handlerMap, staticMap];
|
|
2627
|
-
}
|
|
2628
2853
|
function findMiddleware(middleware, path) {
|
|
2629
2854
|
if (!middleware) {
|
|
2630
2855
|
return void 0;
|
|
@@ -2640,9 +2865,18 @@ var RegExpRouter = class {
|
|
|
2640
2865
|
name = "RegExpRouter";
|
|
2641
2866
|
#middleware;
|
|
2642
2867
|
#routes;
|
|
2868
|
+
#tries;
|
|
2643
2869
|
constructor() {
|
|
2644
2870
|
this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
2645
2871
|
this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
2872
|
+
this.#tries = { [METHOD_NAME_ALL]: new Trie() };
|
|
2873
|
+
}
|
|
2874
|
+
#insertPath(method, path) {
|
|
2875
|
+
try {
|
|
2876
|
+
this.#tries[method].insert(path, !/\*|\/:/.test(path));
|
|
2877
|
+
} catch (e) {
|
|
2878
|
+
throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
|
|
2879
|
+
}
|
|
2646
2880
|
}
|
|
2647
2881
|
add(method, path, handler) {
|
|
2648
2882
|
const middleware = this.#middleware;
|
|
@@ -2651,10 +2885,12 @@ var RegExpRouter = class {
|
|
|
2651
2885
|
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
2652
2886
|
}
|
|
2653
2887
|
if (!middleware[method]) {
|
|
2888
|
+
this.#tries[method] = new Trie();
|
|
2654
2889
|
[middleware, routes].forEach((handlerMap) => {
|
|
2655
2890
|
handlerMap[method] = /* @__PURE__ */ Object.create(null);
|
|
2656
2891
|
Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => {
|
|
2657
2892
|
handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]];
|
|
2893
|
+
this.#insertPath(method, p);
|
|
2658
2894
|
});
|
|
2659
2895
|
});
|
|
2660
2896
|
}
|
|
@@ -2664,13 +2900,12 @@ var RegExpRouter = class {
|
|
|
2664
2900
|
const paramCount = (path.match(/\/:/g) || []).length;
|
|
2665
2901
|
if (/\*$/.test(path)) {
|
|
2666
2902
|
const re = buildWildcardRegExp(path);
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
}
|
|
2903
|
+
Object.keys(middleware).forEach((m) => {
|
|
2904
|
+
if ((method === METHOD_NAME_ALL || method === m) && !middleware[m][path]) {
|
|
2905
|
+
this.#insertPath(m, path);
|
|
2906
|
+
middleware[m][path] = findMiddleware(middleware[m], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || [];
|
|
2907
|
+
}
|
|
2908
|
+
});
|
|
2674
2909
|
Object.keys(middleware).forEach((m) => {
|
|
2675
2910
|
if (method === METHOD_NAME_ALL || method === m) {
|
|
2676
2911
|
Object.keys(middleware[m]).forEach((p) => {
|
|
@@ -2692,9 +2927,12 @@ var RegExpRouter = class {
|
|
|
2692
2927
|
const path2 = paths[i];
|
|
2693
2928
|
Object.keys(routes).forEach((m) => {
|
|
2694
2929
|
if (method === METHOD_NAME_ALL || method === m) {
|
|
2695
|
-
routes[m][path2]
|
|
2696
|
-
|
|
2697
|
-
|
|
2930
|
+
if (!routes[m][path2]) {
|
|
2931
|
+
this.#insertPath(m, path2);
|
|
2932
|
+
routes[m][path2] = [
|
|
2933
|
+
...findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || []
|
|
2934
|
+
];
|
|
2935
|
+
}
|
|
2698
2936
|
routes[m][path2].push([handler, paramCount - len + i + 1]);
|
|
2699
2937
|
}
|
|
2700
2938
|
});
|
|
@@ -2706,33 +2944,58 @@ var RegExpRouter = class {
|
|
|
2706
2944
|
Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
|
|
2707
2945
|
matchers[method] ||= this.#buildMatcher(method);
|
|
2708
2946
|
});
|
|
2709
|
-
this.#middleware = this.#routes = void 0;
|
|
2947
|
+
this.#middleware = this.#routes = this.#tries = void 0;
|
|
2710
2948
|
clearWildcardRegExpCache();
|
|
2711
2949
|
return matchers;
|
|
2712
2950
|
}
|
|
2713
2951
|
#buildMatcher(method) {
|
|
2714
|
-
const
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2952
|
+
const middleware = this.#middleware[method];
|
|
2953
|
+
const routes = this.#routes[method];
|
|
2954
|
+
const trie = this.#tries[method];
|
|
2955
|
+
const staticMap = /* @__PURE__ */ Object.create(null);
|
|
2956
|
+
const handlerData = [];
|
|
2957
|
+
[middleware, routes].forEach((r) => {
|
|
2958
|
+
for (const path in r) {
|
|
2959
|
+
const handlers = r[path];
|
|
2960
|
+
const pathData = trie.paths[path];
|
|
2961
|
+
if (!pathData) {
|
|
2962
|
+
staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
2963
|
+
continue;
|
|
2964
|
+
}
|
|
2965
|
+
const paramAssoc = pathData[1];
|
|
2966
|
+
handlerData[pathData[0]] = handlers.map(([h, paramCount]) => {
|
|
2967
|
+
const paramIndexMap = /* @__PURE__ */ Object.create(null);
|
|
2968
|
+
paramCount -= 1;
|
|
2969
|
+
for (; paramCount >= 0; paramCount--) {
|
|
2970
|
+
const [key, value] = paramAssoc[paramCount];
|
|
2971
|
+
paramIndexMap[key] = value;
|
|
2972
|
+
}
|
|
2973
|
+
return [h, paramIndexMap];
|
|
2974
|
+
});
|
|
2725
2975
|
}
|
|
2726
2976
|
});
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2977
|
+
const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
|
|
2978
|
+
for (let i = 0, len = handlerData.length; i < len; i++) {
|
|
2979
|
+
for (let j = 0, len2 = handlerData[i].length; j < len2; j++) {
|
|
2980
|
+
const map = handlerData[i][j]?.[1];
|
|
2981
|
+
if (!map) {
|
|
2982
|
+
continue;
|
|
2983
|
+
}
|
|
2984
|
+
const keys = Object.keys(map);
|
|
2985
|
+
for (let k = 0, len3 = keys.length; k < len3; k++) {
|
|
2986
|
+
map[keys[k]] = paramReplacementMap[map[keys[k]]];
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
const handlerMap = [];
|
|
2991
|
+
for (const i in indexReplacementMap) {
|
|
2992
|
+
handlerMap[i] = handlerData[indexReplacementMap[i]];
|
|
2731
2993
|
}
|
|
2994
|
+
return [regexp, handlerMap, staticMap];
|
|
2732
2995
|
}
|
|
2733
2996
|
};
|
|
2734
2997
|
|
|
2735
|
-
// ../node_modules/.bun/hono@4.
|
|
2998
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/smart-router/router.js
|
|
2736
2999
|
var SmartRouter = class {
|
|
2737
3000
|
name = "SmartRouter";
|
|
2738
3001
|
#routers = [];
|
|
@@ -2787,7 +3050,7 @@ var SmartRouter = class {
|
|
|
2787
3050
|
}
|
|
2788
3051
|
};
|
|
2789
3052
|
|
|
2790
|
-
// ../node_modules/.bun/hono@4.
|
|
3053
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/trie-router/node.js
|
|
2791
3054
|
var emptyParams = /* @__PURE__ */ Object.create(null);
|
|
2792
3055
|
var hasChildren = (children) => {
|
|
2793
3056
|
for (const _ in children) {
|
|
@@ -2921,9 +3184,18 @@ var Node2 = class _Node2 {
|
|
|
2921
3184
|
if (m) {
|
|
2922
3185
|
params[name] = m[0];
|
|
2923
3186
|
this.#pushHandlerSets(handlerSets, child, method, node.#params, params);
|
|
3187
|
+
if (m[0].length === restPathString.length && child.#children["*"]) {
|
|
3188
|
+
this.#pushHandlerSets(
|
|
3189
|
+
handlerSets,
|
|
3190
|
+
child.#children["*"],
|
|
3191
|
+
method,
|
|
3192
|
+
node.#params,
|
|
3193
|
+
params
|
|
3194
|
+
);
|
|
3195
|
+
}
|
|
2924
3196
|
if (hasChildren(child.#children)) {
|
|
2925
3197
|
child.#params = params;
|
|
2926
|
-
const componentCount = m[0].match(/\//)?.length ?? 0;
|
|
3198
|
+
const componentCount = m[0].match(/\//g)?.length ?? 0;
|
|
2927
3199
|
const targetCurNodes = curNodesQueue[componentCount] ||= [];
|
|
2928
3200
|
targetCurNodes.push(child);
|
|
2929
3201
|
}
|
|
@@ -2962,7 +3234,7 @@ var Node2 = class _Node2 {
|
|
|
2962
3234
|
}
|
|
2963
3235
|
};
|
|
2964
3236
|
|
|
2965
|
-
// ../node_modules/.bun/hono@4.
|
|
3237
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/router/trie-router/router.js
|
|
2966
3238
|
var TrieRouter = class {
|
|
2967
3239
|
name = "TrieRouter";
|
|
2968
3240
|
#node;
|
|
@@ -2984,7 +3256,7 @@ var TrieRouter = class {
|
|
|
2984
3256
|
}
|
|
2985
3257
|
};
|
|
2986
3258
|
|
|
2987
|
-
// ../node_modules/.bun/hono@4.
|
|
3259
|
+
// ../node_modules/.bun/hono@4.13.2/node_modules/hono/dist/hono.js
|
|
2988
3260
|
var Hono2 = class extends Hono {
|
|
2989
3261
|
/**
|
|
2990
3262
|
* Creates an instance of the Hono class.
|
|
@@ -3000,9 +3272,75 @@ var Hono2 = class extends Hono {
|
|
|
3000
3272
|
};
|
|
3001
3273
|
|
|
3002
3274
|
// src/types/common.ts
|
|
3275
|
+
var SUPPORTED_CURRENCY_CODES = /* @__PURE__ */ new Set([
|
|
3276
|
+
"USD",
|
|
3277
|
+
"EUR",
|
|
3278
|
+
"GBP",
|
|
3279
|
+
"JPY",
|
|
3280
|
+
"CNY",
|
|
3281
|
+
"CHF",
|
|
3282
|
+
"CAD",
|
|
3283
|
+
"AUD",
|
|
3284
|
+
"GHS",
|
|
3285
|
+
"NGN",
|
|
3286
|
+
"KES",
|
|
3287
|
+
"ZAR",
|
|
3288
|
+
"XOF",
|
|
3289
|
+
"XAF",
|
|
3290
|
+
"EGP",
|
|
3291
|
+
"TZS",
|
|
3292
|
+
"UGX",
|
|
3293
|
+
"RWF",
|
|
3294
|
+
"ETB",
|
|
3295
|
+
"ZMW",
|
|
3296
|
+
"BWP",
|
|
3297
|
+
"MUR",
|
|
3298
|
+
"NAD",
|
|
3299
|
+
"MWK",
|
|
3300
|
+
"AOA",
|
|
3301
|
+
"CDF",
|
|
3302
|
+
"GMD",
|
|
3303
|
+
"GNF",
|
|
3304
|
+
"LRD",
|
|
3305
|
+
"SLL",
|
|
3306
|
+
"MZN",
|
|
3307
|
+
"BIF",
|
|
3308
|
+
"INR",
|
|
3309
|
+
"BRL",
|
|
3310
|
+
"COP",
|
|
3311
|
+
"MXN",
|
|
3312
|
+
"KRW",
|
|
3313
|
+
"TRY",
|
|
3314
|
+
"THB",
|
|
3315
|
+
"MYR",
|
|
3316
|
+
"PHP",
|
|
3317
|
+
"IDR",
|
|
3318
|
+
"VND",
|
|
3319
|
+
"SGD",
|
|
3320
|
+
"HKD",
|
|
3321
|
+
"TWD",
|
|
3322
|
+
"AED",
|
|
3323
|
+
"SAR",
|
|
3324
|
+
"ILS"
|
|
3325
|
+
]);
|
|
3326
|
+
function isSupportedCurrency(code) {
|
|
3327
|
+
return SUPPORTED_CURRENCY_CODES.has(code);
|
|
3328
|
+
}
|
|
3329
|
+
var warnedCurrencies = /* @__PURE__ */ new Set();
|
|
3330
|
+
function currencyCode(value) {
|
|
3331
|
+
const normalized = value.trim().toUpperCase();
|
|
3332
|
+
if (!isSupportedCurrency(normalized) && !warnedCurrencies.has(normalized)) {
|
|
3333
|
+
warnedCurrencies.add(normalized);
|
|
3334
|
+
console.warn(
|
|
3335
|
+
`[Cimplify] Unrecognized currency code "${normalized}". It may not format correctly.`
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3338
|
+
return normalized;
|
|
3339
|
+
}
|
|
3003
3340
|
var ErrorCode = {
|
|
3004
3341
|
NOT_FOUND: "NOT_FOUND",
|
|
3005
|
-
VALIDATION_ERROR: "VALIDATION_ERROR"
|
|
3342
|
+
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
3343
|
+
CART_EMPTY: "CART_EMPTY"};
|
|
3006
3344
|
var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
|
|
3007
3345
|
function docsUrlForCode(code) {
|
|
3008
3346
|
return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
|
|
@@ -3040,6 +3378,8 @@ var ERROR_SUGGESTIONS = {
|
|
|
3040
3378
|
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
3041
3379
|
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
3042
3380
|
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
3381
|
+
OTP_CHALLENGE_EXHAUSTED: "This verification challenge has no attempts left. Continue checkout without saved details or request a fresh challenge.",
|
|
3382
|
+
OTP_CHALLENGE_CONSUMED: "This verification challenge has already been used. Continue with the established session or request a fresh challenge.",
|
|
3043
3383
|
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
3044
3384
|
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
3045
3385
|
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
@@ -3058,6 +3398,10 @@ var ERROR_SUGGESTIONS = {
|
|
|
3058
3398
|
CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
|
|
3059
3399
|
CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
|
|
3060
3400
|
REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
|
|
3401
|
+
CHECKOUT_AUTHORITY_REQUIRED: "Provide an exact cart or purchase-intent authority before starting checkout.",
|
|
3402
|
+
AUTH_CONFIG_REQUIRED: "Configure the OAuth client and redirect URI before mounting embedded authentication.",
|
|
3403
|
+
AUTH_CALLBACK_MISSING_TOKEN: "The authentication callback returned no access token. Restart sign-in before checkout.",
|
|
3404
|
+
AUTH_START_FAILED: "Embedded authentication could not start. Verify the OAuth configuration and retry.",
|
|
3061
3405
|
POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
|
|
3062
3406
|
FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
|
|
3063
3407
|
};
|
|
@@ -3101,7 +3445,7 @@ function authMiddleware(deps) {
|
|
|
3101
3445
|
await next();
|
|
3102
3446
|
};
|
|
3103
3447
|
}
|
|
3104
|
-
var IDEMPOTENT_PATH_RE = /\/(cart\/items|cart\/coupons|checkout|payments\/authorization|auth\/(request-otp|verify-otp|profile|logout))(\/|$)/;
|
|
3448
|
+
var IDEMPOTENT_PATH_RE = /\/(cart\/items|cart\/coupons|checkout|purchase-intents|payments\/authorization|auth\/(request-otp|verify-otp|profile|logout))(\/|$)/;
|
|
3105
3449
|
var IDEMPOTENCY_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
3106
3450
|
function idempotencyMiddleware(deps) {
|
|
3107
3451
|
return async (c, next) => {
|
|
@@ -3111,7 +3455,8 @@ function idempotencyMiddleware(deps) {
|
|
|
3111
3455
|
const key = c.req.header("idempotency-key") ?? c.req.header("Idempotency-Key");
|
|
3112
3456
|
if (!key || key.length > 200) return next();
|
|
3113
3457
|
const session = c.var.session;
|
|
3114
|
-
const
|
|
3458
|
+
const routeScope = c.req.path.includes("/purchase-intents") ? `:${c.req.path}` : "";
|
|
3459
|
+
const recordId = `${session.id}${routeScope}:${key}`;
|
|
3115
3460
|
const existing = deps.registry.idempotency.get(recordId);
|
|
3116
3461
|
if (existing) {
|
|
3117
3462
|
const expiresAt = Date.parse(existing.expires_at);
|
|
@@ -3189,8 +3534,89 @@ var PAYMENT_METHOD = {
|
|
|
3189
3534
|
MOBILE_MONEY: "mobile_money",
|
|
3190
3535
|
CARD: "card"
|
|
3191
3536
|
};
|
|
3537
|
+
var CHECKOUT_NEXT_ACTION = {
|
|
3538
|
+
NONE: "none"};
|
|
3539
|
+
var CHECKOUT_ORDER_RESULT_STATUS = {
|
|
3540
|
+
CONFIRMED: "confirmed"};
|
|
3541
|
+
var AUTHORIZATION_TYPE = {
|
|
3542
|
+
OTP: "otp"};
|
|
3543
|
+
var DEFAULT_CURRENCY = "GHS";
|
|
3544
|
+
|
|
3545
|
+
// src/types/purchase-intent.ts
|
|
3546
|
+
var PURCHASE_INTENT_SOURCE_KIND = {
|
|
3547
|
+
CART: "cart"};
|
|
3548
|
+
var PURCHASING_PRINCIPAL_KIND = {
|
|
3549
|
+
ACCOUNT: "account",
|
|
3550
|
+
BUSINESS: "business",
|
|
3551
|
+
GUEST: "guest"};
|
|
3552
|
+
var PURCHASE_INTENT_STATUS = {
|
|
3553
|
+
OPEN: "open",
|
|
3554
|
+
CONVERTED: "converted"};
|
|
3555
|
+
var PURCHASE_INTENT_SELLABLE_KIND = {
|
|
3556
|
+
PRODUCT: "product",
|
|
3557
|
+
VARIANT: "variant"
|
|
3558
|
+
};
|
|
3559
|
+
var PURCHASE_INTENT_LINE_CONFIGURATION_KIND = {
|
|
3560
|
+
SIMPLE: "simple"};
|
|
3561
|
+
var MOBILE_MONEY_TENDER_AUTHORITY_KIND = {
|
|
3562
|
+
TRANSIENT: "transient"};
|
|
3563
|
+
var PURCHASE_INTENT_MOBILE_MONEY_NETWORK = {
|
|
3564
|
+
MTN: "mtn",
|
|
3565
|
+
TELECEL: "telecel",
|
|
3566
|
+
AIRTEL: "airtel"
|
|
3567
|
+
};
|
|
3568
|
+
var CHECKOUT_COMPLIANCE_LANE = {
|
|
3569
|
+
NATIVE: "native"};
|
|
3570
|
+
var CHECKOUT_COMPLIANCE_REASON = {
|
|
3571
|
+
PHYSICAL_GOODS_NATIVE: "physical_goods_native"};
|
|
3572
|
+
var PURCHASE_INTENT_PAYMENT_METHOD = {
|
|
3573
|
+
CARD: "card",
|
|
3574
|
+
MOBILE_MONEY: "mobile_money"};
|
|
3575
|
+
var PAYMENT_COLLECTION_MODE = {
|
|
3576
|
+
REQUEST_TO_PAY: "request_to_pay",
|
|
3577
|
+
CREDENTIAL_CHARGE: "credential_charge"};
|
|
3578
|
+
var PURCHASE_INTENT_PAYMENT_PROVIDER = {
|
|
3579
|
+
PAYSTACK: "paystack"};
|
|
3580
|
+
var PAYMENT_OPTION_STATUS = {
|
|
3581
|
+
ELIGIBLE: "eligible"};
|
|
3582
|
+
var PAYMENT_OPTION_NEXT_ACTION = {
|
|
3583
|
+
PROVIDER_APPROVAL: "provider_approval"};
|
|
3584
|
+
var LEGACY_CHECKOUT_PAYMENT_STATUS = {
|
|
3585
|
+
SUCCEEDED: "succeeded"};
|
|
3586
|
+
var CHECKOUT_TERMS_COMPONENT = {
|
|
3587
|
+
DUE_NOW: "due_now"};
|
|
3588
|
+
var CHECKOUT_TERMS_DELTA_KIND = {
|
|
3589
|
+
MONEY: "money",
|
|
3590
|
+
PAYMENT_OPTION: "payment_option"
|
|
3591
|
+
};
|
|
3592
|
+
var CHECKOUT_INVALIDATION_REASON = {
|
|
3593
|
+
PAYMENT_OPTION_CHANGED: "payment_option_changed"
|
|
3594
|
+
};
|
|
3595
|
+
var PURCHASE_INTENT_CONFIRM_STATUS = {
|
|
3596
|
+
ORDER_CREATED: "order_created",
|
|
3597
|
+
CARD_POPUP_REQUIRED: "card_popup_required",
|
|
3598
|
+
AUTHORIZATION_REQUIRED: "authorization_required",
|
|
3599
|
+
TERMS_CHANGED: "terms_changed",
|
|
3600
|
+
SELECTION_UNAVAILABLE: "selection_unavailable",
|
|
3601
|
+
SOURCE_UNAVAILABLE: "source_unavailable"
|
|
3602
|
+
};
|
|
3192
3603
|
|
|
3193
3604
|
// src/mock/routes/v1.ts
|
|
3605
|
+
var PURCHASE_INTENT_ROUTE = {
|
|
3606
|
+
COLLECTION: "/purchase-intents",
|
|
3607
|
+
MEMBER: "/purchase-intents/:intent_id",
|
|
3608
|
+
REFRESH: "/purchase-intents/:intent_id/refresh",
|
|
3609
|
+
CONFIRM: "/purchase-intents/:intent_id/confirm",
|
|
3610
|
+
ACTION: "/purchase-intents/:intent_id/attempts/:attempt_id/actions"
|
|
3611
|
+
};
|
|
3612
|
+
var PURCHASE_INTENT_ROUTE_PARAM = {
|
|
3613
|
+
INTENT_ID: "intent_id",
|
|
3614
|
+
ATTEMPT_ID: "attempt_id"
|
|
3615
|
+
};
|
|
3616
|
+
var PAYMENT_ROUTE = {
|
|
3617
|
+
COLLECTION_OPTIONS: "/payments/collection-options",
|
|
3618
|
+
AUTHORIZATION: "/payments/authorization"
|
|
3619
|
+
};
|
|
3194
3620
|
function buildV1(deps) {
|
|
3195
3621
|
const app = new Hono2();
|
|
3196
3622
|
app.use("*", chaosMiddleware(deps));
|
|
@@ -3452,6 +3878,36 @@ function buildV1(deps) {
|
|
|
3452
3878
|
"/catalogue/quotes/:quote_id/refresh",
|
|
3453
3879
|
(c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
|
|
3454
3880
|
);
|
|
3881
|
+
app.get("/reviews/summary", (c) => {
|
|
3882
|
+
const productId = c.req.query("product_id");
|
|
3883
|
+
if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
|
|
3884
|
+
return fail(c, validation("product_id must be a non-empty canonical identifier"));
|
|
3885
|
+
}
|
|
3886
|
+
const response = {
|
|
3887
|
+
data: {
|
|
3888
|
+
ratings: {
|
|
3889
|
+
product_id: productId ?? null,
|
|
3890
|
+
review_count: 0,
|
|
3891
|
+
rating_sum: 0,
|
|
3892
|
+
average_rating: null,
|
|
3893
|
+
distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
|
|
3894
|
+
},
|
|
3895
|
+
trust_chips: {
|
|
3896
|
+
on_time_delivery_percent: null,
|
|
3897
|
+
delivery_sample_size: 0,
|
|
3898
|
+
average_first_response_seconds: null,
|
|
3899
|
+
support_sample_size: 0
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
};
|
|
3903
|
+
return c.json(response);
|
|
3904
|
+
});
|
|
3905
|
+
app.get("/reviews", (c) => {
|
|
3906
|
+
const response = {
|
|
3907
|
+
data: { items: [], next_cursor: null }
|
|
3908
|
+
};
|
|
3909
|
+
return c.json(response);
|
|
3910
|
+
});
|
|
3455
3911
|
app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
|
|
3456
3912
|
app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
|
|
3457
3913
|
app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
|
|
@@ -3533,28 +3989,81 @@ function buildV1(deps) {
|
|
|
3533
3989
|
"/subscriptions/:subscription_id/skip",
|
|
3534
3990
|
(c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id")))
|
|
3535
3991
|
);
|
|
3536
|
-
app.get(
|
|
3992
|
+
app.get(PAYMENT_ROUTE.COLLECTION_OPTIONS, async (c) => {
|
|
3537
3993
|
const currency = c.req.query("currency")?.trim().toUpperCase();
|
|
3538
3994
|
if (!currency || !/^[A-Z]{3}$/.test(currency)) {
|
|
3539
3995
|
return fail(c, validation("currency must be a canonical three-letter code"));
|
|
3540
3996
|
}
|
|
3541
3997
|
return tryRoute(c, () => ({
|
|
3542
3998
|
presentment_currency: currency,
|
|
3543
|
-
options: currency ===
|
|
3999
|
+
options: currency === DEFAULT_CURRENCY ? [
|
|
3544
4000
|
{ method: PAYMENT_METHOD.CARD, network: null },
|
|
3545
|
-
{
|
|
3546
|
-
|
|
3547
|
-
|
|
4001
|
+
{
|
|
4002
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
4003
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.MTN
|
|
4004
|
+
},
|
|
4005
|
+
{
|
|
4006
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
4007
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.TELECEL
|
|
4008
|
+
},
|
|
4009
|
+
{
|
|
4010
|
+
method: PAYMENT_METHOD.MOBILE_MONEY,
|
|
4011
|
+
network: PURCHASE_INTENT_MOBILE_MONEY_NETWORK.AIRTEL
|
|
4012
|
+
}
|
|
3548
4013
|
] : currency === "USD" ? [{ method: PAYMENT_METHOD.CARD, network: null }] : []
|
|
3549
4014
|
}));
|
|
3550
4015
|
});
|
|
3551
|
-
app.post(
|
|
4016
|
+
app.post(PURCHASE_INTENT_ROUTE.COLLECTION, async (c) => {
|
|
4017
|
+
const body = await c.req.json().catch(() => ({}));
|
|
4018
|
+
return tryRoute(c, () => deps.purchaseIntents.mint(c.var.session, body));
|
|
4019
|
+
});
|
|
4020
|
+
app.get(
|
|
4021
|
+
PURCHASE_INTENT_ROUTE.MEMBER,
|
|
4022
|
+
(c) => tryRoute(
|
|
4023
|
+
c,
|
|
4024
|
+
() => deps.purchaseIntents.get(
|
|
4025
|
+
c.var.session,
|
|
4026
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID)
|
|
4027
|
+
)
|
|
4028
|
+
)
|
|
4029
|
+
);
|
|
4030
|
+
app.post(PURCHASE_INTENT_ROUTE.REFRESH, async (c) => {
|
|
4031
|
+
const body = await c.req.json().catch(() => ({}));
|
|
4032
|
+
return tryRoute(
|
|
4033
|
+
c,
|
|
4034
|
+
() => deps.purchaseIntents.refresh(
|
|
4035
|
+
c.var.session,
|
|
4036
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
4037
|
+
body.expected_intent_revision
|
|
4038
|
+
)
|
|
4039
|
+
);
|
|
4040
|
+
});
|
|
4041
|
+
app.post(PURCHASE_INTENT_ROUTE.CONFIRM, async (c) => {
|
|
4042
|
+
const body = await c.req.json().catch(() => ({}));
|
|
4043
|
+
return tryRoute(
|
|
4044
|
+
c,
|
|
4045
|
+
() => deps.purchaseIntents.confirm(
|
|
4046
|
+
c.var.session,
|
|
4047
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
4048
|
+
body
|
|
4049
|
+
)
|
|
4050
|
+
);
|
|
4051
|
+
});
|
|
4052
|
+
app.post(PURCHASE_INTENT_ROUTE.ACTION, async (c) => {
|
|
3552
4053
|
const body = await c.req.json().catch(() => ({}));
|
|
3553
|
-
return tryRoute(
|
|
4054
|
+
return tryRoute(
|
|
4055
|
+
c,
|
|
4056
|
+
() => deps.purchaseIntents.submitAction(
|
|
4057
|
+
c.var.session,
|
|
4058
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.INTENT_ID),
|
|
4059
|
+
c.req.param(PURCHASE_INTENT_ROUTE_PARAM.ATTEMPT_ID),
|
|
4060
|
+
body
|
|
4061
|
+
)
|
|
4062
|
+
);
|
|
3554
4063
|
});
|
|
3555
|
-
app.post(
|
|
4064
|
+
app.post(PAYMENT_ROUTE.AUTHORIZATION, async (c) => {
|
|
3556
4065
|
const body = await c.req.json().catch(() => ({}));
|
|
3557
|
-
return tryRoute(c, () => deps.
|
|
4066
|
+
return tryRoute(c, () => deps.payments.authorize(body));
|
|
3558
4067
|
});
|
|
3559
4068
|
app.get("/auth/status", (c) => tryRoute(c, () => deps.auth.status(c.var.session.token)));
|
|
3560
4069
|
app.post("/auth/request-otp", async (c) => {
|
|
@@ -3860,6 +4369,7 @@ function createStateRegistry() {
|
|
|
3860
4369
|
collections: createMemoryStore(),
|
|
3861
4370
|
carts: createMemoryStore(),
|
|
3862
4371
|
orders: createMemoryStore(),
|
|
4372
|
+
purchaseIntents: createMemoryStore(),
|
|
3863
4373
|
subscriptions: createMemoryStore(),
|
|
3864
4374
|
bookings: createMemoryStore(),
|
|
3865
4375
|
services: createMemoryStore(),
|
|
@@ -4009,9 +4519,9 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4009
4519
|
// injected into the HTML page served by the mock. Edit this file directly \u2014
|
|
4010
4520
|
// type-check via tsgo + the IframeToParentMessage shape from the SDK.
|
|
4011
4521
|
(function () {
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4522
|
+
const TYPE = window.__CIMPLIFY_MOCK_ELEMENT__;
|
|
4523
|
+
const DEFAULT_BUSINESS = window.__CIMPLIFY_MOCK_BUSINESS__;
|
|
4524
|
+
const MSG = {
|
|
4015
4525
|
INIT: "init", SET_TOKEN: "set_token", SET_CART: "set_cart", GET_DATA: "get_data",
|
|
4016
4526
|
REFRESH_TOKEN: "refresh_token", LOGOUT: "logout",
|
|
4017
4527
|
PROCESS_CHECKOUT: "process_checkout", ABORT_CHECKOUT: "abort_checkout",
|
|
@@ -4024,12 +4534,36 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4024
4534
|
CHECKOUT_STATUS: "checkout_status", CHECKOUT_COMPLETE: "checkout_complete",
|
|
4025
4535
|
ORDER_TYPE_CHANGED: "order_type_changed", REQUEST_SUBMIT: "request_submit"
|
|
4026
4536
|
};
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4537
|
+
const PURCHASE_INTENT = {
|
|
4538
|
+
PATH: "/api/v1/purchase-intents",
|
|
4539
|
+
ORDER_CREATED: "order_created",
|
|
4540
|
+
CARD_POPUP_REQUIRED: "card_popup_required",
|
|
4541
|
+
AUTHORIZATION_REQUIRED: "authorization_required",
|
|
4542
|
+
ELIGIBLE: "eligible"
|
|
4543
|
+
};
|
|
4544
|
+
const CHECKOUT_STATUS = {
|
|
4545
|
+
PROCESSING: "processing",
|
|
4546
|
+
SUCCESS: "success",
|
|
4547
|
+
FAILED: "failed"
|
|
4548
|
+
};
|
|
4549
|
+
const CHECKOUT_ERROR = { FAILED: "CHECKOUT_FAILED" };
|
|
4550
|
+
const ORDER_STATUS = { CONFIRMED: "confirmed" };
|
|
4551
|
+
const TENDER = {
|
|
4552
|
+
CARD: "card",
|
|
4553
|
+
MOBILE_MONEY: "mobile_money",
|
|
4554
|
+
AUTHORITY_TRANSIENT: "transient",
|
|
4555
|
+
MTN: "mtn"
|
|
4556
|
+
};
|
|
4557
|
+
const PAYMENT_PROVIDER = { PAYSTACK: "paystack" };
|
|
4558
|
+
const SOURCE_KIND = { CART: "cart" };
|
|
4559
|
+
const AUTHORIZATION = { OTP: "otp" };
|
|
4560
|
+
const EXACT_ZERO_MONEY = /^[+-]?0+(?:\\.0+)?(?:[eE][+-]?\\d+)?$/;
|
|
4561
|
+
const qs = new URLSearchParams(location.search);
|
|
4562
|
+
const AUTO = qs.get("auto") === "true";
|
|
4563
|
+
const DEMO_OTP = qs.get("otp") || "123456";
|
|
4564
|
+
const ORIGIN = qs.get("origin") || "*";
|
|
4565
|
+
const NONCE = qs.get("nonce");
|
|
4566
|
+
const state = {
|
|
4033
4567
|
businessId: DEFAULT_BUSINESS,
|
|
4034
4568
|
token: null,
|
|
4035
4569
|
cart: null,
|
|
@@ -4040,15 +4574,33 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4040
4574
|
contact: null,
|
|
4041
4575
|
pendingOtp: null
|
|
4042
4576
|
};
|
|
4043
|
-
|
|
4044
|
-
|
|
4577
|
+
const content = document.getElementById("content");
|
|
4578
|
+
const title = document.getElementById("title");
|
|
4045
4579
|
|
|
4046
4580
|
function send(msg) {
|
|
4047
4581
|
if (NONCE) msg.nonce = NONCE;
|
|
4048
4582
|
parent.postMessage(msg, ORIGIN);
|
|
4049
4583
|
}
|
|
4584
|
+
function isExactlyZeroMoney(value) {
|
|
4585
|
+
return typeof value === "number"
|
|
4586
|
+
? Object.is(value, 0) || Object.is(value, -0)
|
|
4587
|
+
: EXACT_ZERO_MONEY.test(String(value).trim());
|
|
4588
|
+
}
|
|
4050
4589
|
function reportHeight() { send({ type: MSG.HEIGHT_CHANGE, height: document.documentElement.scrollHeight }); }
|
|
4051
4590
|
function ready() { send({ type: MSG.READY, height: document.documentElement.scrollHeight }); }
|
|
4591
|
+
function responseWithBody(response) {
|
|
4592
|
+
return response.json().then(function (body) {
|
|
4593
|
+
return { status: response.status, body: body };
|
|
4594
|
+
});
|
|
4595
|
+
}
|
|
4596
|
+
function assertSuccessfulResponse(response, fallbackMessage) {
|
|
4597
|
+
if (response.status >= 400) {
|
|
4598
|
+
throw new Error(
|
|
4599
|
+
(response.body && response.body.error && response.body.error.message) || fallbackMessage
|
|
4600
|
+
);
|
|
4601
|
+
}
|
|
4602
|
+
return response.body;
|
|
4603
|
+
}
|
|
4052
4604
|
|
|
4053
4605
|
function defaultAddress() {
|
|
4054
4606
|
return {
|
|
@@ -4058,9 +4610,20 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4058
4610
|
};
|
|
4059
4611
|
}
|
|
4060
4612
|
function defaultPayment(type) {
|
|
4061
|
-
if (type ===
|
|
4062
|
-
|
|
4063
|
-
|
|
4613
|
+
if (type === TENDER.CARD) {
|
|
4614
|
+
return {
|
|
4615
|
+
type: TENDER.CARD,
|
|
4616
|
+
provider: PAYMENT_PROVIDER.PAYSTACK,
|
|
4617
|
+
last_four: "4242",
|
|
4618
|
+
label: "Visa \u2022\u2022\u2022\u2022 4242"
|
|
4619
|
+
};
|
|
4620
|
+
}
|
|
4621
|
+
return {
|
|
4622
|
+
type: TENDER.MOBILE_MONEY,
|
|
4623
|
+
provider: TENDER.MTN,
|
|
4624
|
+
phone_number: "+233244000000",
|
|
4625
|
+
label: "MTN Mobile Money"
|
|
4626
|
+
};
|
|
4064
4627
|
}
|
|
4065
4628
|
|
|
4066
4629
|
function renderAuth() {
|
|
@@ -4085,12 +4648,12 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4085
4648
|
' <div class="option" data-key="lagos">5 Allen Ave, Ikeja, Lagos</div>' +
|
|
4086
4649
|
'</div>' +
|
|
4087
4650
|
'<button id="confirm">Use this address</button>';
|
|
4088
|
-
|
|
4651
|
+
const options = {
|
|
4089
4652
|
"default": defaultAddress(),
|
|
4090
4653
|
"east-legon": { street_address: "8 Ring Road", city: "Accra", region: "Greater Accra", country: "GH", latitude: 5.65, longitude: -0.16 },
|
|
4091
4654
|
"lagos": { street_address: "5 Allen Avenue", city: "Lagos", region: "Lagos", country: "NG", latitude: 6.5244, longitude: 3.3792 }
|
|
4092
4655
|
};
|
|
4093
|
-
|
|
4656
|
+
let picked = "default";
|
|
4094
4657
|
Array.prototype.forEach.call(document.querySelectorAll(".option"), function (el) {
|
|
4095
4658
|
el.onclick = function () {
|
|
4096
4659
|
picked = el.getAttribute("data-key");
|
|
@@ -4113,10 +4676,9 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4113
4676
|
'<div class="options" id="pay-options">' +
|
|
4114
4677
|
' <div class="option selected" data-method="mobile_money">\u{1F4F1} MTN Mobile Money</div>' +
|
|
4115
4678
|
' <div class="option" data-method="card">\u{1F4B3} Card (Paystack)</div>' +
|
|
4116
|
-
' <div class="option" data-method="cash">\u{1F4B5} Cash on delivery</div>' +
|
|
4117
4679
|
'</div>' +
|
|
4118
4680
|
'<button id="confirm">Use this method</button>';
|
|
4119
|
-
|
|
4681
|
+
let picked = TENDER.MOBILE_MONEY;
|
|
4120
4682
|
Array.prototype.forEach.call(document.querySelectorAll(".option"), function (el) {
|
|
4121
4683
|
el.onclick = function () {
|
|
4122
4684
|
picked = el.getAttribute("data-method");
|
|
@@ -4160,7 +4722,6 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4160
4722
|
'</div>' +
|
|
4161
4723
|
'<label>Payment method</label>' +
|
|
4162
4724
|
'<select id="pay-method">' +
|
|
4163
|
-
' <option value="cash">Cash</option>' +
|
|
4164
4725
|
' <option value="mobile_money">Mobile Money (MTN)</option>' +
|
|
4165
4726
|
' <option value="card">Card (Paystack)</option>' +
|
|
4166
4727
|
'</select>' +
|
|
@@ -4177,65 +4738,139 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4177
4738
|
}
|
|
4178
4739
|
|
|
4179
4740
|
function runCheckout() {
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4741
|
+
const statusEl = document.getElementById("status");
|
|
4742
|
+
const errEl = document.getElementById("err");
|
|
4743
|
+
const resultEl = document.getElementById("result");
|
|
4183
4744
|
if (errEl) errEl.textContent = "";
|
|
4184
4745
|
if (!state.cart) { errEl.textContent = "No cart provided"; return; }
|
|
4185
|
-
|
|
4746
|
+
const customer = {
|
|
4186
4747
|
name: document.getElementById("cust-name").value.trim() || "Customer",
|
|
4187
4748
|
email: document.getElementById("cust-email").value.trim() || "noemail@example.com",
|
|
4188
4749
|
phone: document.getElementById("cust-phone").value.trim() || "+233000000000",
|
|
4189
4750
|
save_details: false
|
|
4190
4751
|
};
|
|
4191
|
-
|
|
4192
|
-
|
|
4752
|
+
const paymentMethod = document.getElementById("pay-method").value;
|
|
4753
|
+
const orderType = document.getElementById("order-type").value;
|
|
4193
4754
|
statusEl.textContent = "Processing\u2026";
|
|
4194
|
-
send({ type: MSG.CHECKOUT_STATUS, status:
|
|
4755
|
+
send({ type: MSG.CHECKOUT_STATUS, status: CHECKOUT_STATUS.PROCESSING, context: {} });
|
|
4195
4756
|
|
|
4196
|
-
|
|
4757
|
+
const headers = { "content-type": "application/json" };
|
|
4197
4758
|
if (state.token) headers["x-session-token"] = state.token;
|
|
4198
4759
|
|
|
4199
|
-
|
|
4760
|
+
const preference = paymentMethod === TENDER.MOBILE_MONEY
|
|
4761
|
+
? {
|
|
4762
|
+
method_kind: TENDER.MOBILE_MONEY,
|
|
4763
|
+
authority: {
|
|
4764
|
+
authority_kind: TENDER.AUTHORITY_TRANSIENT,
|
|
4765
|
+
phone_number: customer.phone,
|
|
4766
|
+
network: TENDER.MTN
|
|
4767
|
+
}
|
|
4768
|
+
}
|
|
4769
|
+
: { method_kind: TENDER.CARD };
|
|
4770
|
+
const intentKey = "mock-element:" + state.cart.id;
|
|
4771
|
+
fetch(PURCHASE_INTENT.PATH, {
|
|
4200
4772
|
method: "POST",
|
|
4201
4773
|
headers: headers,
|
|
4202
4774
|
body: JSON.stringify({
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4775
|
+
client_intent_key: intentKey,
|
|
4776
|
+
source: { kind: SOURCE_KIND.CART, cart_id: state.cart.id },
|
|
4777
|
+
checkout: {
|
|
4778
|
+
customer: customer,
|
|
4779
|
+
order_type: orderType,
|
|
4780
|
+
address_info: state.address || {},
|
|
4781
|
+
tender_preference: preference
|
|
4782
|
+
}
|
|
4208
4783
|
})
|
|
4209
4784
|
})
|
|
4210
|
-
.then(
|
|
4785
|
+
.then(responseWithBody)
|
|
4211
4786
|
.then(function (resp) {
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4787
|
+
const intent = assertSuccessfulResponse(resp, "Intent creation failed");
|
|
4788
|
+
const terms = intent.current_terms;
|
|
4789
|
+
const option = terms && terms.payment_options && terms.payment_options.filter(function (candidate) {
|
|
4790
|
+
return candidate.status === PURCHASE_INTENT.ELIGIBLE && candidate.method_kind === preference.method_kind;
|
|
4791
|
+
})[0];
|
|
4792
|
+
if (!terms || (!option && !isExactlyZeroMoney(terms.money.rail_amount))) {
|
|
4793
|
+
throw new Error("No eligible payment option");
|
|
4794
|
+
}
|
|
4795
|
+
const confirmationPath = PURCHASE_INTENT.PATH + "/" + encodeURIComponent(intent.id) + "/confirm";
|
|
4796
|
+
const confirmationBody = JSON.stringify({
|
|
4797
|
+
accepted_intent_revision: terms.intent_revision,
|
|
4798
|
+
accepted_terms_version: terms.terms_version,
|
|
4799
|
+
accepted_due_now: terms.money.due_now,
|
|
4800
|
+
accepted_customer_debit_amount: option
|
|
4801
|
+
? option.customer_debit_amount
|
|
4802
|
+
: terms.money.rail_amount,
|
|
4803
|
+
currency: terms.money.currency,
|
|
4804
|
+
payment_option_id: option ? option.id : null,
|
|
4805
|
+
idempotency_key: "mock-confirm:" + intent.id
|
|
4806
|
+
});
|
|
4807
|
+
function confirmIntent() {
|
|
4808
|
+
return fetch(confirmationPath, {
|
|
4809
|
+
method: "POST",
|
|
4810
|
+
headers: headers,
|
|
4811
|
+
body: confirmationBody
|
|
4812
|
+
})
|
|
4813
|
+
.then(responseWithBody)
|
|
4814
|
+
.then(function (response) {
|
|
4815
|
+
return assertSuccessfulResponse(response, "Intent confirmation failed");
|
|
4816
|
+
});
|
|
4817
|
+
}
|
|
4818
|
+
|
|
4819
|
+
return confirmIntent().then(function (outcome) {
|
|
4820
|
+
// This mock has no external provider window. Replaying the exact
|
|
4821
|
+
// idempotent confirmation models the provider-approved callback.
|
|
4822
|
+
return outcome.status === PURCHASE_INTENT.CARD_POPUP_REQUIRED
|
|
4823
|
+
? confirmIntent()
|
|
4824
|
+
: outcome;
|
|
4825
|
+
});
|
|
4826
|
+
})
|
|
4827
|
+
.then(function (outcome) {
|
|
4828
|
+
if (outcome.status !== PURCHASE_INTENT.AUTHORIZATION_REQUIRED) return outcome;
|
|
4829
|
+
return fetch(
|
|
4830
|
+
PURCHASE_INTENT.PATH + "/" + encodeURIComponent(outcome.intent_id) +
|
|
4831
|
+
"/attempts/" + encodeURIComponent(outcome.attempt_id) + "/actions",
|
|
4832
|
+
{
|
|
4833
|
+
method: "POST",
|
|
4834
|
+
headers: headers,
|
|
4835
|
+
body: JSON.stringify({ authorization: { type: AUTHORIZATION.OTP, value: DEMO_OTP } })
|
|
4836
|
+
}
|
|
4837
|
+
)
|
|
4838
|
+
.then(responseWithBody)
|
|
4839
|
+
.then(function (response) {
|
|
4840
|
+
return assertSuccessfulResponse(response, "Authorization failed");
|
|
4841
|
+
});
|
|
4842
|
+
})
|
|
4843
|
+
.then(function (outcome) {
|
|
4844
|
+
if (outcome.status !== PURCHASE_INTENT.ORDER_CREATED) {
|
|
4845
|
+
throw new Error("Checkout requires " + outcome.status.replace(/_/g, " "));
|
|
4218
4846
|
}
|
|
4219
|
-
|
|
4220
|
-
|
|
4847
|
+
send({
|
|
4848
|
+
type: MSG.CHECKOUT_STATUS,
|
|
4849
|
+
status: CHECKOUT_STATUS.SUCCESS,
|
|
4850
|
+
context: { order_id: outcome.order_id }
|
|
4851
|
+
});
|
|
4221
4852
|
send({
|
|
4222
4853
|
type: MSG.CHECKOUT_COMPLETE,
|
|
4223
4854
|
success: true,
|
|
4224
4855
|
order: {
|
|
4225
|
-
id:
|
|
4226
|
-
order_number:
|
|
4227
|
-
status:
|
|
4856
|
+
id: outcome.order_id,
|
|
4857
|
+
order_number: outcome.order_number || outcome.order_id,
|
|
4858
|
+
status: ORDER_STATUS.CONFIRMED,
|
|
4228
4859
|
total: (state.cart && state.cart.total_price) || "0.00",
|
|
4229
4860
|
currency: (state.cart && state.cart.currency) || "GHS"
|
|
4230
4861
|
}
|
|
4231
4862
|
});
|
|
4232
|
-
statusEl.textContent = "Success \u2014 order " +
|
|
4863
|
+
statusEl.textContent = "Success \u2014 order " + outcome.order_id;
|
|
4233
4864
|
resultEl.style.display = "block";
|
|
4234
|
-
resultEl.textContent = JSON.stringify(
|
|
4865
|
+
resultEl.textContent = JSON.stringify(outcome, null, 2);
|
|
4235
4866
|
})
|
|
4236
4867
|
.catch(function (e) {
|
|
4237
|
-
send({
|
|
4238
|
-
|
|
4868
|
+
send({
|
|
4869
|
+
type: MSG.CHECKOUT_COMPLETE,
|
|
4870
|
+
success: false,
|
|
4871
|
+
error: { code: CHECKOUT_ERROR.FAILED, message: String(e), recoverable: true }
|
|
4872
|
+
});
|
|
4873
|
+
statusEl.textContent = "Failed";
|
|
4239
4874
|
errEl.textContent = String(e);
|
|
4240
4875
|
});
|
|
4241
4876
|
}
|
|
@@ -4252,7 +4887,7 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4252
4887
|
break;
|
|
4253
4888
|
case MSG.SET_CART:
|
|
4254
4889
|
state.cart = msg.cart;
|
|
4255
|
-
|
|
4890
|
+
const s = document.getElementById("status");
|
|
4256
4891
|
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");
|
|
4257
4892
|
reportHeight();
|
|
4258
4893
|
break;
|
|
@@ -4276,7 +4911,7 @@ var ELEMENT_HANDLER_JS = `/* eslint-disable */
|
|
|
4276
4911
|
}
|
|
4277
4912
|
break;
|
|
4278
4913
|
case MSG.ABORT_CHECKOUT:
|
|
4279
|
-
send({ type: MSG.CHECKOUT_STATUS, status:
|
|
4914
|
+
send({ type: MSG.CHECKOUT_STATUS, status: CHECKOUT_STATUS.FAILED, context: {} });
|
|
4280
4915
|
break;
|
|
4281
4916
|
}
|
|
4282
4917
|
}
|
|
@@ -4347,9 +4982,10 @@ function buildLink(deps) {
|
|
|
4347
4982
|
app.post("/auth/request-otp", async (c) => {
|
|
4348
4983
|
const body = await c.req.json().catch(() => ({}));
|
|
4349
4984
|
return tryRoute(c, () => {
|
|
4350
|
-
deps.auth.requestOtp(body.contact ?? "");
|
|
4985
|
+
const challenge = deps.auth.requestOtp(body.contact ?? "");
|
|
4351
4986
|
return {
|
|
4352
4987
|
success: true,
|
|
4988
|
+
challenge_id: challenge.otp_id,
|
|
4353
4989
|
message: `OTP sent to ${body.contact ?? "contact"}`,
|
|
4354
4990
|
expires_in: 300,
|
|
4355
4991
|
is_new_account: false
|
|
@@ -4359,7 +4995,11 @@ function buildLink(deps) {
|
|
|
4359
4995
|
app.post("/auth/verify-otp", async (c) => {
|
|
4360
4996
|
const body = await c.req.json().catch(() => ({}));
|
|
4361
4997
|
return tryRoute(c, () => {
|
|
4362
|
-
const session = deps.auth.verifyOtp(
|
|
4998
|
+
const session = deps.auth.verifyOtp(
|
|
4999
|
+
body.contact ?? "",
|
|
5000
|
+
body.otp_code ?? "",
|
|
5001
|
+
body.challenge_id
|
|
5002
|
+
);
|
|
4363
5003
|
c.header("x-session-token", session.token);
|
|
4364
5004
|
const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
|
|
4365
5005
|
email: body.contact?.includes("@") ? body.contact : void 0,
|
|
@@ -4453,10 +5093,7 @@ function buildLink(deps) {
|
|
|
4453
5093
|
};
|
|
4454
5094
|
});
|
|
4455
5095
|
});
|
|
4456
|
-
app.get(
|
|
4457
|
-
"/preferences",
|
|
4458
|
-
(c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
|
|
4459
|
-
);
|
|
5096
|
+
app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
|
|
4460
5097
|
app.post("/preferences", async (c) => {
|
|
4461
5098
|
const body = await c.req.json().catch(() => ({}));
|
|
4462
5099
|
return tryRoute(c, () => {
|
|
@@ -4888,6 +5525,7 @@ function createAuthService(opts) {
|
|
|
4888
5525
|
token: id,
|
|
4889
5526
|
business_id: options.defaultBusinessId,
|
|
4890
5527
|
is_authenticated: authenticated,
|
|
5528
|
+
account_id: authenticated ? ids.raw("account") : void 0,
|
|
4891
5529
|
customer_id: authenticated ? ids.customer() : void 0,
|
|
4892
5530
|
customer_name: profile?.name,
|
|
4893
5531
|
customer_email: profile?.email,
|
|
@@ -4933,9 +5571,16 @@ function createAuthService(opts) {
|
|
|
4933
5571
|
code_hint: options.mode === "permissive" ? code : void 0
|
|
4934
5572
|
};
|
|
4935
5573
|
},
|
|
4936
|
-
verifyOtp(contact, code) {
|
|
4937
|
-
|
|
4938
|
-
|
|
5574
|
+
verifyOtp(contact, code, challengeId) {
|
|
5575
|
+
let otp = challengeId ? registry.otps.get(challengeId) : void 0;
|
|
5576
|
+
if (!challengeId) {
|
|
5577
|
+
const matching = registry.otps.list((o) => o.contact === contact);
|
|
5578
|
+
otp = matching[matching.length - 1];
|
|
5579
|
+
}
|
|
5580
|
+
if (challengeId) {
|
|
5581
|
+
if (!otp) throw new Error("No OTP challenge found");
|
|
5582
|
+
if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
|
|
5583
|
+
}
|
|
4939
5584
|
if (options.mode === "strict") {
|
|
4940
5585
|
if (!otp) throw new Error("No OTP requested");
|
|
4941
5586
|
if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
|
|
@@ -4963,7 +5608,7 @@ function createAuthService(opts) {
|
|
|
4963
5608
|
if (!s) return { is_authenticated: false, user_type: "guest" };
|
|
4964
5609
|
return {
|
|
4965
5610
|
is_authenticated: s.is_authenticated,
|
|
4966
|
-
account_id: s.
|
|
5611
|
+
account_id: s.account_id,
|
|
4967
5612
|
user_type: s.is_authenticated ? "customer" : "guest",
|
|
4968
5613
|
session_expires_at: s.expires_at ? Math.floor(new Date(s.expires_at).getTime() / 1e3) : void 0,
|
|
4969
5614
|
session: s
|
|
@@ -6261,88 +6906,10 @@ function createCartService(opts) {
|
|
|
6261
6906
|
};
|
|
6262
6907
|
}
|
|
6263
6908
|
|
|
6264
|
-
// src/mock/domain/
|
|
6265
|
-
function
|
|
6266
|
-
const { registry, clock,
|
|
6909
|
+
// src/mock/domain/payment.ts
|
|
6910
|
+
function createPaymentService(options) {
|
|
6911
|
+
const { registry, clock, bus } = options;
|
|
6267
6912
|
return {
|
|
6268
|
-
process(session, body) {
|
|
6269
|
-
if (!body.cart_id) throw validation("cart_id required");
|
|
6270
|
-
const c = registry.carts.get(body.cart_id);
|
|
6271
|
-
if (!c) throw notFound(`Cart ${body.cart_id} not found`);
|
|
6272
|
-
if (c.items.length === 0) throw validation("Cart is empty", { code: "CART_EMPTY" });
|
|
6273
|
-
const orderId = ids.order();
|
|
6274
|
-
const orderNumber = ids.orderNumber();
|
|
6275
|
-
const paymentId = ids.payment();
|
|
6276
|
-
const reference = ids.payment();
|
|
6277
|
-
const requiresAuth = body.payment_method === "mobile_money";
|
|
6278
|
-
const isCard = body.payment_method === "card" || body.payment_method === "stripe";
|
|
6279
|
-
const cardProvider = body.payment_method === "stripe" || body.pay_currency?.toUpperCase() === "USD" ? "stripe" : "paystack";
|
|
6280
|
-
const order = {
|
|
6281
|
-
id: orderId,
|
|
6282
|
-
business_id: c.business_id,
|
|
6283
|
-
user_friendly_id: orderNumber,
|
|
6284
|
-
channel: c.channel,
|
|
6285
|
-
status: requiresAuth ? "pending" : "confirmed",
|
|
6286
|
-
payment_state: requiresAuth ? "not_paid" : "paid",
|
|
6287
|
-
order_type: body.order_type,
|
|
6288
|
-
customer_id: session.customer_id,
|
|
6289
|
-
customer_name: body.customer.name,
|
|
6290
|
-
customer_email: body.customer.email,
|
|
6291
|
-
customer_phone: body.customer.phone,
|
|
6292
|
-
delivery_address: body.address_info?.street_address,
|
|
6293
|
-
delivery_fee: c.delivery_fee,
|
|
6294
|
-
subtotal: c.subtotal,
|
|
6295
|
-
tax_amount: c.tax_amount,
|
|
6296
|
-
service_charge: c.service_charge,
|
|
6297
|
-
total_discounts: c.total_discounts,
|
|
6298
|
-
total_price: c.total_price,
|
|
6299
|
-
currency: c.currency,
|
|
6300
|
-
items: c.items,
|
|
6301
|
-
applied_discount_ids: c.applied_discount_ids,
|
|
6302
|
-
applied_discount_codes: c.applied_discount_codes,
|
|
6303
|
-
payment_id: paymentId,
|
|
6304
|
-
payment_reference: reference,
|
|
6305
|
-
metadata: body.metadata,
|
|
6306
|
-
created_at: clock.iso(),
|
|
6307
|
-
updated_at: clock.iso()
|
|
6308
|
-
};
|
|
6309
|
-
registry.orders.put(orderId, order);
|
|
6310
|
-
registry.carts.put(c.id, { ...c, status: "converted", updated_at: clock.iso() });
|
|
6311
|
-
bus.emit("order.created", { order_id: orderId, order_number: orderNumber }, c.business_id);
|
|
6312
|
-
if (!requiresAuth) {
|
|
6313
|
-
bus.emit("order.payment.captured", { order_id: orderId, reference }, c.business_id);
|
|
6314
|
-
bus.emit("order.confirmed", { order_id: orderId }, c.business_id);
|
|
6315
|
-
}
|
|
6316
|
-
const billToken = `bt_${reference.slice(-12)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
6317
|
-
const result = {
|
|
6318
|
-
order_id: orderId,
|
|
6319
|
-
order_number: orderNumber,
|
|
6320
|
-
payment_id: paymentId,
|
|
6321
|
-
payment_status: requiresAuth || isCard ? "pending" : "succeeded",
|
|
6322
|
-
payment_reference: reference,
|
|
6323
|
-
requires_authorization: requiresAuth,
|
|
6324
|
-
authorization_type: requiresAuth ? "otp" : void 0,
|
|
6325
|
-
next_action: requiresAuth ? {
|
|
6326
|
-
type: "authorization",
|
|
6327
|
-
authorization_type: "otp",
|
|
6328
|
-
display_text: "Approve on your mobile money app"
|
|
6329
|
-
} : { type: "none" },
|
|
6330
|
-
provider: isCard ? cardProvider : body.payment_method,
|
|
6331
|
-
bill_token: billToken
|
|
6332
|
-
};
|
|
6333
|
-
if (isCard) {
|
|
6334
|
-
const proc = globalThis.process;
|
|
6335
|
-
result.client_secret = cardProvider === "stripe" ? `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}` : `access_${reference}`;
|
|
6336
|
-
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";
|
|
6337
|
-
result.next_action = {
|
|
6338
|
-
type: "card_popup",
|
|
6339
|
-
provider: cardProvider,
|
|
6340
|
-
client_secret: result.client_secret,
|
|
6341
|
-
public_key: result.public_key
|
|
6342
|
-
};
|
|
6343
|
-
}
|
|
6344
|
-
return result;
|
|
6345
|
-
},
|
|
6346
6913
|
authorize(body) {
|
|
6347
6914
|
if (!body.payment_id?.trim()) throw validation("payment_id required");
|
|
6348
6915
|
if (!body.authorization) throw validation("authorization required");
|
|
@@ -6353,7 +6920,7 @@ function createCheckoutService(opts) {
|
|
|
6353
6920
|
const updated = {
|
|
6354
6921
|
...order,
|
|
6355
6922
|
payment_state: "paid",
|
|
6356
|
-
status:
|
|
6923
|
+
status: CHECKOUT_ORDER_RESULT_STATUS.CONFIRMED,
|
|
6357
6924
|
updated_at: clock.iso()
|
|
6358
6925
|
};
|
|
6359
6926
|
registry.orders.put(order.id, updated);
|
|
@@ -6364,14 +6931,542 @@ function createCheckoutService(opts) {
|
|
|
6364
6931
|
order_number: order.user_friendly_id,
|
|
6365
6932
|
payment_id: body.payment_id,
|
|
6366
6933
|
payment_reference: order.payment_reference,
|
|
6367
|
-
payment_status:
|
|
6934
|
+
payment_status: LEGACY_CHECKOUT_PAYMENT_STATUS.SUCCEEDED,
|
|
6368
6935
|
requires_authorization: false,
|
|
6369
|
-
next_action: { type:
|
|
6936
|
+
next_action: { type: CHECKOUT_NEXT_ACTION.NONE }
|
|
6370
6937
|
};
|
|
6371
6938
|
}
|
|
6372
6939
|
};
|
|
6373
6940
|
}
|
|
6374
6941
|
|
|
6942
|
+
// src/mock/domain/purchase-intent.ts
|
|
6943
|
+
var INTENT_LIFETIME_MS = 15 * 60 * 1e3;
|
|
6944
|
+
var ZERO_MONEY = "0.00";
|
|
6945
|
+
var PURCHASE_INTENT_MOBILE_MONEY_NETWORKS = new Set(
|
|
6946
|
+
Object.values(PURCHASE_INTENT_MOBILE_MONEY_NETWORK)
|
|
6947
|
+
);
|
|
6948
|
+
var MOCK_PURCHASE_INTENT = {
|
|
6949
|
+
OWNER_KIND: { ACCOUNT: "account", STOREFRONT_SESSION: "storefront_session" },
|
|
6950
|
+
CART_STATUS: { ACTIVE: "active", CONVERTED: "converted" },
|
|
6951
|
+
ORDER_STATUS: { PENDING: "pending", CONFIRMED: "confirmed" },
|
|
6952
|
+
PAYMENT_STATE: { NOT_PAID: "not_paid", PAID: "paid" },
|
|
6953
|
+
EVENT: {
|
|
6954
|
+
ORDER_CREATED: "order.created",
|
|
6955
|
+
PAYMENT_CAPTURED: "order.payment.captured",
|
|
6956
|
+
ORDER_CONFIRMED: "order.confirmed"
|
|
6957
|
+
},
|
|
6958
|
+
ID_PREFIX: { INTENT: "pi", ATTEMPT: "attempt" },
|
|
6959
|
+
DEFAULT_LOCATION_ID: "mock-location",
|
|
6960
|
+
MOCK_PAYSTACK_PUBLIC_KEY: "pk_test_mock_paystack",
|
|
6961
|
+
COMPLIANCE: {
|
|
6962
|
+
POLICY_NAME: "mock-storefront-commerce"
|
|
6963
|
+
}
|
|
6964
|
+
};
|
|
6965
|
+
var DECIMAL_WIRE_VALUE = /^([+-]?)(\d+)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
|
6966
|
+
function isExactlyZero(value) {
|
|
6967
|
+
if (typeof value === "number") return Object.is(value, 0) || Object.is(value, -0);
|
|
6968
|
+
const match2 = DECIMAL_WIRE_VALUE.exec(value.trim());
|
|
6969
|
+
return Boolean(match2 && [...match2[2], ...match2[3] ?? ""].every((digit) => digit === "0"));
|
|
6970
|
+
}
|
|
6971
|
+
function sameDecimal(left, right) {
|
|
6972
|
+
const canonical = (value) => {
|
|
6973
|
+
const wire = typeof value === "number" ? String(value) : value.trim();
|
|
6974
|
+
const match2 = DECIMAL_WIRE_VALUE.exec(wire);
|
|
6975
|
+
if (!match2) return null;
|
|
6976
|
+
let digits = `${match2[2]}${match2[3] ?? ""}`.replace(/^0+/, "");
|
|
6977
|
+
if (!digits) return "0";
|
|
6978
|
+
let scale = BigInt((match2[3] ?? "").length) - BigInt(match2[4] ?? "0");
|
|
6979
|
+
while (digits.endsWith("0")) {
|
|
6980
|
+
digits = digits.slice(0, -1);
|
|
6981
|
+
scale -= 1n;
|
|
6982
|
+
}
|
|
6983
|
+
const sign = match2[1] === "-" ? "-" : "";
|
|
6984
|
+
return `${sign}${digits}:${scale}`;
|
|
6985
|
+
};
|
|
6986
|
+
const normalizedLeft = canonical(left);
|
|
6987
|
+
return normalizedLeft !== null && normalizedLeft === canonical(right);
|
|
6988
|
+
}
|
|
6989
|
+
function wireMoney(value) {
|
|
6990
|
+
return typeof value === "string" ? value.trim() : String(value);
|
|
6991
|
+
}
|
|
6992
|
+
function decimal(value) {
|
|
6993
|
+
return wireMoney(value.toFixed(2));
|
|
6994
|
+
}
|
|
6995
|
+
function paymentOptions(intentId, currency, amount, expiresAt) {
|
|
6996
|
+
const normalizedCurrency = currencyCode(currency);
|
|
6997
|
+
const normalizedAmount = wireMoney(amount);
|
|
6998
|
+
return [
|
|
6999
|
+
{
|
|
7000
|
+
id: `${intentId}:${PURCHASE_INTENT_PAYMENT_METHOD.CARD}`,
|
|
7001
|
+
rank: 0,
|
|
7002
|
+
method_kind: PURCHASE_INTENT_PAYMENT_METHOD.CARD,
|
|
7003
|
+
collection_mode: PAYMENT_COLLECTION_MODE.CREDENTIAL_CHARGE,
|
|
7004
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
7005
|
+
principal_amount: normalizedAmount,
|
|
7006
|
+
fee_amount: wireMoney(ZERO_MONEY),
|
|
7007
|
+
customer_debit_amount: normalizedAmount,
|
|
7008
|
+
currency: normalizedCurrency,
|
|
7009
|
+
status: PAYMENT_OPTION_STATUS.ELIGIBLE,
|
|
7010
|
+
expected_next_action: PAYMENT_OPTION_NEXT_ACTION.PROVIDER_APPROVAL,
|
|
7011
|
+
expires_at: expiresAt
|
|
7012
|
+
},
|
|
7013
|
+
{
|
|
7014
|
+
id: `${intentId}:${PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY}`,
|
|
7015
|
+
rank: 1,
|
|
7016
|
+
method_kind: PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
|
|
7017
|
+
collection_mode: PAYMENT_COLLECTION_MODE.REQUEST_TO_PAY,
|
|
7018
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
7019
|
+
principal_amount: normalizedAmount,
|
|
7020
|
+
fee_amount: wireMoney(ZERO_MONEY),
|
|
7021
|
+
customer_debit_amount: normalizedAmount,
|
|
7022
|
+
currency: normalizedCurrency,
|
|
7023
|
+
status: PAYMENT_OPTION_STATUS.ELIGIBLE,
|
|
7024
|
+
expected_next_action: PAYMENT_OPTION_NEXT_ACTION.PROVIDER_APPROVAL,
|
|
7025
|
+
expires_at: expiresAt
|
|
7026
|
+
}
|
|
7027
|
+
];
|
|
7028
|
+
}
|
|
7029
|
+
function termsForCart(input) {
|
|
7030
|
+
const total = wireMoney(input.total);
|
|
7031
|
+
return {
|
|
7032
|
+
id: `${input.intentId}:terms:${input.version}`,
|
|
7033
|
+
intent_revision: input.revision,
|
|
7034
|
+
terms_version: input.version,
|
|
7035
|
+
terms_digest: `mock:${input.intentId}:${input.revision}:${input.version}`,
|
|
7036
|
+
money: {
|
|
7037
|
+
currency: currencyCode(input.currency),
|
|
7038
|
+
subtotal: wireMoney(input.subtotal),
|
|
7039
|
+
discount_total: wireMoney(input.discount),
|
|
7040
|
+
tax_total: wireMoney(input.tax),
|
|
7041
|
+
delivery_total: wireMoney(input.delivery),
|
|
7042
|
+
statutory_total: wireMoney(ZERO_MONEY),
|
|
7043
|
+
total_obligation: total,
|
|
7044
|
+
due_now: total,
|
|
7045
|
+
rail_amount: total,
|
|
7046
|
+
store_credit_consumed: wireMoney(ZERO_MONEY),
|
|
7047
|
+
voucher_credit_consumed: wireMoney(ZERO_MONEY)
|
|
7048
|
+
},
|
|
7049
|
+
material: {
|
|
7050
|
+
line_digest: `mock-lines:${input.intentId}`,
|
|
7051
|
+
destination_digest: `mock-destination:${input.intentId}`,
|
|
7052
|
+
delivery_promise_digest: `mock-delivery:${input.intentId}`,
|
|
7053
|
+
entitlement_digest: `mock-entitlement:${input.intentId}`,
|
|
7054
|
+
cancellation_terms_digest: `mock-cancellation:${input.intentId}`
|
|
7055
|
+
},
|
|
7056
|
+
compliance: {
|
|
7057
|
+
policy_name: MOCK_PURCHASE_INTENT.COMPLIANCE.POLICY_NAME,
|
|
7058
|
+
policy_version: 1,
|
|
7059
|
+
lane: CHECKOUT_COMPLIANCE_LANE.NATIVE,
|
|
7060
|
+
reason_code: CHECKOUT_COMPLIANCE_REASON.PHYSICAL_GOODS_NATIVE,
|
|
7061
|
+
evidence_digest: `mock-compliance:${input.intentId}`
|
|
7062
|
+
},
|
|
7063
|
+
payment_options: isExactlyZero(input.total) ? [] : paymentOptions(input.intentId, input.currency, input.total, input.validUntil),
|
|
7064
|
+
valid_until: input.validUntil,
|
|
7065
|
+
created_at: input.now
|
|
7066
|
+
};
|
|
7067
|
+
}
|
|
7068
|
+
function intentView(intent) {
|
|
7069
|
+
const {
|
|
7070
|
+
intent_owner: _owner,
|
|
7071
|
+
mint_request: _request,
|
|
7072
|
+
last_confirmation: _confirmation,
|
|
7073
|
+
...view
|
|
7074
|
+
} = intent;
|
|
7075
|
+
return view;
|
|
7076
|
+
}
|
|
7077
|
+
function purchasingPrincipal(session) {
|
|
7078
|
+
if (!session.is_authenticated) {
|
|
7079
|
+
return { kind: PURCHASING_PRINCIPAL_KIND.GUEST };
|
|
7080
|
+
}
|
|
7081
|
+
if (!session.account_id) throw validation("Authenticated mock session has no account authority");
|
|
7082
|
+
return {
|
|
7083
|
+
kind: PURCHASING_PRINCIPAL_KIND.ACCOUNT,
|
|
7084
|
+
account_id: session.account_id
|
|
7085
|
+
};
|
|
7086
|
+
}
|
|
7087
|
+
function assertSupportedTenderPreference(request) {
|
|
7088
|
+
if (request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) return;
|
|
7089
|
+
const checkout = request.checkout;
|
|
7090
|
+
if (!checkout) throw validation("Cart checkout input is required");
|
|
7091
|
+
const preference = checkout.tender_preference;
|
|
7092
|
+
if (preference?.method_kind !== PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY || preference.authority.authority_kind !== MOBILE_MONEY_TENDER_AUTHORITY_KIND.TRANSIENT) {
|
|
7093
|
+
return;
|
|
7094
|
+
}
|
|
7095
|
+
if (!PURCHASE_INTENT_MOBILE_MONEY_NETWORKS.has(preference.authority.network)) {
|
|
7096
|
+
throw validation("Mobile Money network is not available for PurchaseIntent checkout");
|
|
7097
|
+
}
|
|
7098
|
+
}
|
|
7099
|
+
function intentOwner(session) {
|
|
7100
|
+
if (!session.is_authenticated) {
|
|
7101
|
+
return { kind: MOCK_PURCHASE_INTENT.OWNER_KIND.STOREFRONT_SESSION, id: session.id };
|
|
7102
|
+
}
|
|
7103
|
+
if (!session.account_id) throw validation("Authenticated mock session has no account authority");
|
|
7104
|
+
return { kind: MOCK_PURCHASE_INTENT.OWNER_KIND.ACCOUNT, id: session.account_id };
|
|
7105
|
+
}
|
|
7106
|
+
function createPurchaseIntentMockService(options) {
|
|
7107
|
+
const { registry, clock, ids, bus } = options;
|
|
7108
|
+
function stored(session, intentId) {
|
|
7109
|
+
const intent = registry.purchaseIntents.get(intentId);
|
|
7110
|
+
if (!intent) throw notFound(`Purchase intent ${intentId} not found`);
|
|
7111
|
+
const owner = intentOwner(session);
|
|
7112
|
+
if (intent.intent_owner.kind !== owner.kind || intent.intent_owner.id !== owner.id) {
|
|
7113
|
+
throw notFound(`Purchase intent ${intentId} not found`);
|
|
7114
|
+
}
|
|
7115
|
+
return intent;
|
|
7116
|
+
}
|
|
7117
|
+
function completeProviderOrder(intent, order, attemptId) {
|
|
7118
|
+
const updated = {
|
|
7119
|
+
...order,
|
|
7120
|
+
payment_state: MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID,
|
|
7121
|
+
status: MOCK_PURCHASE_INTENT.ORDER_STATUS.CONFIRMED,
|
|
7122
|
+
updated_at: clock.iso()
|
|
7123
|
+
};
|
|
7124
|
+
registry.orders.put(order.id, updated);
|
|
7125
|
+
bus.emit(
|
|
7126
|
+
MOCK_PURCHASE_INTENT.EVENT.PAYMENT_CAPTURED,
|
|
7127
|
+
{ order_id: order.id, reference: order.payment_reference },
|
|
7128
|
+
order.business_id
|
|
7129
|
+
);
|
|
7130
|
+
bus.emit(MOCK_PURCHASE_INTENT.EVENT.ORDER_CONFIRMED, { order_id: order.id }, order.business_id);
|
|
7131
|
+
const completed = {
|
|
7132
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
7133
|
+
intent_id: intent.id,
|
|
7134
|
+
attempt_id: attemptId,
|
|
7135
|
+
order_id: order.id,
|
|
7136
|
+
order_number: order.user_friendly_id,
|
|
7137
|
+
payment_id: order.payment_id
|
|
7138
|
+
};
|
|
7139
|
+
registry.purchaseIntents.put(intent.id, {
|
|
7140
|
+
...intent,
|
|
7141
|
+
updated_at: clock.iso(),
|
|
7142
|
+
last_confirmation: completed
|
|
7143
|
+
});
|
|
7144
|
+
return completed;
|
|
7145
|
+
}
|
|
7146
|
+
return {
|
|
7147
|
+
mint(session, request) {
|
|
7148
|
+
if (!request.client_intent_key.trim()) throw validation("client_intent_key required");
|
|
7149
|
+
if (request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) {
|
|
7150
|
+
throw validation("The mock currently prepares cart purchase intents only");
|
|
7151
|
+
}
|
|
7152
|
+
const checkoutInput = request.checkout;
|
|
7153
|
+
if (!checkoutInput) throw validation("Cart checkout input is required");
|
|
7154
|
+
assertSupportedTenderPreference(request);
|
|
7155
|
+
const cart = registry.carts.get(request.source.cart_id);
|
|
7156
|
+
if (!cart) throw notFound(`Cart ${request.source.cart_id} not found`);
|
|
7157
|
+
if (cart.items.length === 0) {
|
|
7158
|
+
throw validation("Cart is empty", { code: ErrorCode.CART_EMPTY });
|
|
7159
|
+
}
|
|
7160
|
+
const principal = purchasingPrincipal(session);
|
|
7161
|
+
const owner = intentOwner(session);
|
|
7162
|
+
const existing = registry.purchaseIntents.list(
|
|
7163
|
+
(candidate) => candidate.mint_request.client_intent_key === request.client_intent_key && candidate.intent_owner.kind === owner.kind && candidate.intent_owner.id === owner.id
|
|
7164
|
+
)[0];
|
|
7165
|
+
if (existing) return intentView(existing);
|
|
7166
|
+
const now = clock.iso();
|
|
7167
|
+
const expiresAt = new Date(clock.nowMs() + INTENT_LIFETIME_MS).toISOString();
|
|
7168
|
+
const intentId = ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.INTENT);
|
|
7169
|
+
const terms = termsForCart({
|
|
7170
|
+
intentId,
|
|
7171
|
+
revision: 1,
|
|
7172
|
+
version: 1,
|
|
7173
|
+
currency: cart.currency,
|
|
7174
|
+
subtotal: cart.subtotal,
|
|
7175
|
+
discount: cart.total_discounts,
|
|
7176
|
+
tax: cart.tax_amount,
|
|
7177
|
+
delivery: cart.delivery_fee,
|
|
7178
|
+
total: cart.total_price,
|
|
7179
|
+
now,
|
|
7180
|
+
validUntil: expiresAt
|
|
7181
|
+
});
|
|
7182
|
+
const intent = {
|
|
7183
|
+
id: intentId,
|
|
7184
|
+
seller_business_id: cart.business_id,
|
|
7185
|
+
principal,
|
|
7186
|
+
revision: 1,
|
|
7187
|
+
status: PURCHASE_INTENT_STATUS.OPEN,
|
|
7188
|
+
source: {
|
|
7189
|
+
kind: PURCHASE_INTENT_SOURCE_KIND.CART,
|
|
7190
|
+
source_id: cart.id,
|
|
7191
|
+
source_version: cart.updated_at,
|
|
7192
|
+
seller_business_id: cart.business_id,
|
|
7193
|
+
subject: {
|
|
7194
|
+
kind: PURCHASING_PRINCIPAL_KIND.BUSINESS,
|
|
7195
|
+
business_id: cart.business_id
|
|
7196
|
+
},
|
|
7197
|
+
binding_digest: `mock-cart:${cart.id}:${cart.updated_at}`
|
|
7198
|
+
},
|
|
7199
|
+
lines: cart.items.map((line, ordinal) => ({
|
|
7200
|
+
id: line.id,
|
|
7201
|
+
ordinal,
|
|
7202
|
+
sellable: {
|
|
7203
|
+
kind: line.variant_id ? PURCHASE_INTENT_SELLABLE_KIND.VARIANT : PURCHASE_INTENT_SELLABLE_KIND.PRODUCT,
|
|
7204
|
+
product_id: line.item_id,
|
|
7205
|
+
variant_id: line.variant_id,
|
|
7206
|
+
location_id: checkoutInput.location_id || MOCK_PURCHASE_INTENT.DEFAULT_LOCATION_ID
|
|
7207
|
+
},
|
|
7208
|
+
quantity: line.quantity,
|
|
7209
|
+
configuration: {
|
|
7210
|
+
kind: PURCHASE_INTENT_LINE_CONFIGURATION_KIND.SIMPLE,
|
|
7211
|
+
variant_id: line.variant_id,
|
|
7212
|
+
customer_inputs: line.customer_inputs
|
|
7213
|
+
}
|
|
7214
|
+
})),
|
|
7215
|
+
line_pricing: cart.items.map((line) => {
|
|
7216
|
+
const unitPrice = Number(line.price) + Number(line.add_ons_price);
|
|
7217
|
+
const lineSubtotal = unitPrice * line.quantity - Number(line.item_discount_amount);
|
|
7218
|
+
return {
|
|
7219
|
+
intent_line_id: line.id,
|
|
7220
|
+
quantity: line.quantity,
|
|
7221
|
+
unit_price: decimal(unitPrice),
|
|
7222
|
+
line_subtotal: decimal(lineSubtotal),
|
|
7223
|
+
currency: currencyCode(cart.currency)
|
|
7224
|
+
};
|
|
7225
|
+
}),
|
|
7226
|
+
current_terms: terms,
|
|
7227
|
+
expires_at: expiresAt,
|
|
7228
|
+
created_at: now,
|
|
7229
|
+
updated_at: now,
|
|
7230
|
+
intent_owner: owner,
|
|
7231
|
+
mint_request: request
|
|
7232
|
+
};
|
|
7233
|
+
registry.purchaseIntents.put(intentId, intent);
|
|
7234
|
+
return intentView(intent);
|
|
7235
|
+
},
|
|
7236
|
+
get(session, intentId) {
|
|
7237
|
+
return intentView(stored(session, intentId));
|
|
7238
|
+
},
|
|
7239
|
+
refresh(session, intentId, expectedRevision) {
|
|
7240
|
+
const intent = stored(session, intentId);
|
|
7241
|
+
if (intent.revision !== expectedRevision) {
|
|
7242
|
+
throw validation("expected_intent_revision does not match current intent revision");
|
|
7243
|
+
}
|
|
7244
|
+
if (!intent.current_terms) throw validation("Purchase intent has no current terms");
|
|
7245
|
+
const previous = intent.current_terms;
|
|
7246
|
+
const nextDelivery = Number(previous.money.delivery_total) + 1;
|
|
7247
|
+
const nextTotal = Number(previous.money.total_obligation) + 1;
|
|
7248
|
+
const now = clock.iso();
|
|
7249
|
+
const replacement = termsForCart({
|
|
7250
|
+
intentId,
|
|
7251
|
+
revision: intent.revision,
|
|
7252
|
+
version: previous.terms_version + 1,
|
|
7253
|
+
currency: previous.money.currency,
|
|
7254
|
+
subtotal: String(previous.money.subtotal),
|
|
7255
|
+
discount: String(previous.money.discount_total),
|
|
7256
|
+
tax: String(previous.money.tax_total),
|
|
7257
|
+
delivery: nextDelivery.toFixed(2),
|
|
7258
|
+
total: nextTotal.toFixed(2),
|
|
7259
|
+
now,
|
|
7260
|
+
validUntil: intent.expires_at
|
|
7261
|
+
});
|
|
7262
|
+
const updated = { ...intent, current_terms: replacement, updated_at: now };
|
|
7263
|
+
registry.purchaseIntents.put(intentId, updated);
|
|
7264
|
+
return intentView(updated);
|
|
7265
|
+
},
|
|
7266
|
+
confirm(session, intentId, request) {
|
|
7267
|
+
const intent = stored(session, intentId);
|
|
7268
|
+
if (intent.status === PURCHASE_INTENT_STATUS.CONVERTED && intent.last_confirmation) {
|
|
7269
|
+
const orderId2 = "order_id" in intent.last_confirmation ? intent.last_confirmation.order_id : void 0;
|
|
7270
|
+
const order2 = orderId2 ? registry.orders.get(orderId2) : void 0;
|
|
7271
|
+
if (order2?.payment_state === MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID) {
|
|
7272
|
+
return {
|
|
7273
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
7274
|
+
intent_id: intent.id,
|
|
7275
|
+
attempt_id: "attempt_id" in intent.last_confirmation ? intent.last_confirmation.attempt_id : ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.ATTEMPT),
|
|
7276
|
+
order_id: order2.id
|
|
7277
|
+
};
|
|
7278
|
+
}
|
|
7279
|
+
if (order2?.payment_id && intent.last_confirmation.status === PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED) {
|
|
7280
|
+
return completeProviderOrder(intent, order2, intent.last_confirmation.attempt_id);
|
|
7281
|
+
}
|
|
7282
|
+
return intent.last_confirmation;
|
|
7283
|
+
}
|
|
7284
|
+
const terms = intent.current_terms;
|
|
7285
|
+
if (!terms) throw validation("Purchase intent has no current terms");
|
|
7286
|
+
const zeroRail = isExactlyZero(terms.money.rail_amount);
|
|
7287
|
+
const option = request.payment_option_id ? terms.payment_options.find(
|
|
7288
|
+
(candidate) => candidate.id === request.payment_option_id && candidate.status === PAYMENT_OPTION_STATUS.ELIGIBLE
|
|
7289
|
+
) : void 0;
|
|
7290
|
+
const acceptedBaseTermsChanged = !sameDecimal(request.accepted_due_now, terms.money.due_now) || request.currency !== terms.money.currency;
|
|
7291
|
+
if (request.accepted_intent_revision !== intent.revision || request.accepted_terms_version !== terms.terms_version || acceptedBaseTermsChanged) {
|
|
7292
|
+
const deltas = acceptedBaseTermsChanged ? [
|
|
7293
|
+
{
|
|
7294
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.MONEY,
|
|
7295
|
+
component: CHECKOUT_TERMS_COMPONENT.DUE_NOW,
|
|
7296
|
+
accepted: request.accepted_due_now,
|
|
7297
|
+
replacement: terms.money.due_now
|
|
7298
|
+
}
|
|
7299
|
+
] : [
|
|
7300
|
+
{
|
|
7301
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.PAYMENT_OPTION,
|
|
7302
|
+
accepted_option_id: request.payment_option_id ?? null,
|
|
7303
|
+
accepted_customer_debit_amount: request.accepted_customer_debit_amount,
|
|
7304
|
+
replacement_option_id: option?.id ?? null,
|
|
7305
|
+
replacement_customer_debit_amount: option?.customer_debit_amount ?? null
|
|
7306
|
+
}
|
|
7307
|
+
];
|
|
7308
|
+
return {
|
|
7309
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED,
|
|
7310
|
+
intent_id: intent.id,
|
|
7311
|
+
replacement: terms,
|
|
7312
|
+
deltas
|
|
7313
|
+
};
|
|
7314
|
+
}
|
|
7315
|
+
if (!zeroRail && !option || zeroRail && request.payment_option_id != null) {
|
|
7316
|
+
return {
|
|
7317
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE,
|
|
7318
|
+
intent_id: intent.id,
|
|
7319
|
+
lines: intent.lines.map((line) => ({
|
|
7320
|
+
line_id: line.id,
|
|
7321
|
+
reason: CHECKOUT_INVALIDATION_REASON.PAYMENT_OPTION_CHANGED
|
|
7322
|
+
}))
|
|
7323
|
+
};
|
|
7324
|
+
}
|
|
7325
|
+
const acceptedCustomerDebitMatches = zeroRail ? isExactlyZero(request.accepted_customer_debit_amount) : Boolean(
|
|
7326
|
+
option && sameDecimal(request.accepted_customer_debit_amount, option.customer_debit_amount)
|
|
7327
|
+
);
|
|
7328
|
+
if (!acceptedCustomerDebitMatches) {
|
|
7329
|
+
return {
|
|
7330
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED,
|
|
7331
|
+
intent_id: intent.id,
|
|
7332
|
+
replacement: terms,
|
|
7333
|
+
deltas: [
|
|
7334
|
+
{
|
|
7335
|
+
kind: CHECKOUT_TERMS_DELTA_KIND.PAYMENT_OPTION,
|
|
7336
|
+
accepted_option_id: request.payment_option_id ?? null,
|
|
7337
|
+
accepted_customer_debit_amount: request.accepted_customer_debit_amount,
|
|
7338
|
+
replacement_option_id: option?.id ?? null,
|
|
7339
|
+
replacement_customer_debit_amount: option?.customer_debit_amount ?? null
|
|
7340
|
+
}
|
|
7341
|
+
]
|
|
7342
|
+
};
|
|
7343
|
+
}
|
|
7344
|
+
if (intent.mint_request.source.kind !== PURCHASE_INTENT_SOURCE_KIND.CART) {
|
|
7345
|
+
throw validation("The mock currently confirms cart purchase intents only");
|
|
7346
|
+
}
|
|
7347
|
+
const checkoutInput = intent.mint_request.checkout;
|
|
7348
|
+
if (!checkoutInput) throw validation("Cart checkout input is required");
|
|
7349
|
+
const cart = registry.carts.get(intent.mint_request.source.cart_id);
|
|
7350
|
+
if (!cart || cart.status !== MOCK_PURCHASE_INTENT.CART_STATUS.ACTIVE) {
|
|
7351
|
+
return { status: PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE, intent_id: intent.id };
|
|
7352
|
+
}
|
|
7353
|
+
const attemptId = ids.raw(MOCK_PURCHASE_INTENT.ID_PREFIX.ATTEMPT);
|
|
7354
|
+
const orderId = ids.order();
|
|
7355
|
+
const orderNumber = ids.orderNumber();
|
|
7356
|
+
const paymentId = zeroRail ? void 0 : ids.payment();
|
|
7357
|
+
const paymentReference = zeroRail ? void 0 : ids.payment();
|
|
7358
|
+
const needsProvider = option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.CARD || option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY;
|
|
7359
|
+
const paid = zeroRail;
|
|
7360
|
+
const order = {
|
|
7361
|
+
id: orderId,
|
|
7362
|
+
business_id: cart.business_id,
|
|
7363
|
+
user_friendly_id: orderNumber,
|
|
7364
|
+
channel: cart.channel,
|
|
7365
|
+
status: paid ? MOCK_PURCHASE_INTENT.ORDER_STATUS.CONFIRMED : MOCK_PURCHASE_INTENT.ORDER_STATUS.PENDING,
|
|
7366
|
+
payment_state: paid ? MOCK_PURCHASE_INTENT.PAYMENT_STATE.PAID : MOCK_PURCHASE_INTENT.PAYMENT_STATE.NOT_PAID,
|
|
7367
|
+
order_type: checkoutInput.order_type,
|
|
7368
|
+
customer_id: session.customer_id,
|
|
7369
|
+
customer_name: checkoutInput.customer.name,
|
|
7370
|
+
customer_email: checkoutInput.customer.email,
|
|
7371
|
+
customer_phone: checkoutInput.customer.phone,
|
|
7372
|
+
delivery_address: checkoutInput.address_info.street_address,
|
|
7373
|
+
delivery_fee: cart.delivery_fee,
|
|
7374
|
+
subtotal: cart.subtotal,
|
|
7375
|
+
tax_amount: cart.tax_amount,
|
|
7376
|
+
service_charge: cart.service_charge,
|
|
7377
|
+
total_discounts: cart.total_discounts,
|
|
7378
|
+
total_price: cart.total_price,
|
|
7379
|
+
currency: cart.currency,
|
|
7380
|
+
items: cart.items,
|
|
7381
|
+
applied_discount_ids: cart.applied_discount_ids,
|
|
7382
|
+
applied_discount_codes: cart.applied_discount_codes,
|
|
7383
|
+
payment_id: paymentId,
|
|
7384
|
+
payment_reference: paymentReference,
|
|
7385
|
+
metadata: checkoutInput.metadata,
|
|
7386
|
+
created_at: clock.iso(),
|
|
7387
|
+
updated_at: clock.iso()
|
|
7388
|
+
};
|
|
7389
|
+
registry.orders.put(orderId, order);
|
|
7390
|
+
registry.carts.put(cart.id, {
|
|
7391
|
+
...cart,
|
|
7392
|
+
status: MOCK_PURCHASE_INTENT.CART_STATUS.CONVERTED,
|
|
7393
|
+
updated_at: clock.iso()
|
|
7394
|
+
});
|
|
7395
|
+
bus.emit(
|
|
7396
|
+
MOCK_PURCHASE_INTENT.EVENT.ORDER_CREATED,
|
|
7397
|
+
{ order_id: orderId, order_number: orderNumber },
|
|
7398
|
+
cart.business_id
|
|
7399
|
+
);
|
|
7400
|
+
if (paid) {
|
|
7401
|
+
if (paymentReference) {
|
|
7402
|
+
bus.emit(
|
|
7403
|
+
MOCK_PURCHASE_INTENT.EVENT.PAYMENT_CAPTURED,
|
|
7404
|
+
{ order_id: orderId, reference: paymentReference },
|
|
7405
|
+
cart.business_id
|
|
7406
|
+
);
|
|
7407
|
+
}
|
|
7408
|
+
bus.emit(
|
|
7409
|
+
MOCK_PURCHASE_INTENT.EVENT.ORDER_CONFIRMED,
|
|
7410
|
+
{ order_id: orderId },
|
|
7411
|
+
cart.business_id
|
|
7412
|
+
);
|
|
7413
|
+
}
|
|
7414
|
+
let confirmation;
|
|
7415
|
+
if (option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY) {
|
|
7416
|
+
confirmation = {
|
|
7417
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED,
|
|
7418
|
+
intent_id: intent.id,
|
|
7419
|
+
attempt_id: attemptId,
|
|
7420
|
+
order_id: orderId,
|
|
7421
|
+
authorization_type: AUTHORIZATION_TYPE.OTP,
|
|
7422
|
+
display_text: "Approve on your mobile money app"
|
|
7423
|
+
};
|
|
7424
|
+
} else if (option?.method_kind === PURCHASE_INTENT_PAYMENT_METHOD.CARD) {
|
|
7425
|
+
confirmation = {
|
|
7426
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED,
|
|
7427
|
+
intent_id: intent.id,
|
|
7428
|
+
attempt_id: attemptId,
|
|
7429
|
+
order_id: orderId,
|
|
7430
|
+
provider: PURCHASE_INTENT_PAYMENT_PROVIDER.PAYSTACK,
|
|
7431
|
+
client_secret: `access_${paymentReference}`,
|
|
7432
|
+
public_key: MOCK_PURCHASE_INTENT.MOCK_PAYSTACK_PUBLIC_KEY
|
|
7433
|
+
};
|
|
7434
|
+
} else {
|
|
7435
|
+
confirmation = {
|
|
7436
|
+
status: PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED,
|
|
7437
|
+
intent_id: intent.id,
|
|
7438
|
+
attempt_id: attemptId,
|
|
7439
|
+
order_id: orderId
|
|
7440
|
+
};
|
|
7441
|
+
}
|
|
7442
|
+
if (needsProvider && !paymentId) {
|
|
7443
|
+
throw validation("Provider-backed purchase intent has no payment authority");
|
|
7444
|
+
}
|
|
7445
|
+
registry.purchaseIntents.put(intent.id, {
|
|
7446
|
+
...intent,
|
|
7447
|
+
status: PURCHASE_INTENT_STATUS.CONVERTED,
|
|
7448
|
+
converted_order_id: orderId,
|
|
7449
|
+
updated_at: clock.iso(),
|
|
7450
|
+
last_confirmation: confirmation
|
|
7451
|
+
});
|
|
7452
|
+
return confirmation;
|
|
7453
|
+
},
|
|
7454
|
+
submitAction(session, intentId, attemptId, request) {
|
|
7455
|
+
const intent = stored(session, intentId);
|
|
7456
|
+
const previous = intent.last_confirmation;
|
|
7457
|
+
if (!previous || previous.status !== PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED || previous.attempt_id !== attemptId) {
|
|
7458
|
+
throw validation("Purchase-intent attempt is not awaiting authorization");
|
|
7459
|
+
}
|
|
7460
|
+
if (!request.authorization) throw validation("authorization required");
|
|
7461
|
+
const order = registry.orders.get(previous.order_id);
|
|
7462
|
+
if (!order || !order.payment_id) {
|
|
7463
|
+
throw notFound(`Purchase-intent attempt ${attemptId} not found`);
|
|
7464
|
+
}
|
|
7465
|
+
return completeProviderOrder(intent, order, attemptId);
|
|
7466
|
+
}
|
|
7467
|
+
};
|
|
7468
|
+
}
|
|
7469
|
+
|
|
6375
7470
|
// src/mock/domain/orders.ts
|
|
6376
7471
|
function createOrderService(opts) {
|
|
6377
7472
|
const { registry, clock, bus } = opts;
|
|
@@ -6750,6 +7845,7 @@ function createDeliveryService() {
|
|
|
6750
7845
|
rate_id: "dlvrt_mock_standard",
|
|
6751
7846
|
name: "Standard",
|
|
6752
7847
|
fee: standardFree ? money(0) : money(15),
|
|
7848
|
+
fee_status: "priced",
|
|
6753
7849
|
currency: "GHS",
|
|
6754
7850
|
free_delivery_applied: standardFree,
|
|
6755
7851
|
free_over_amount: money(200),
|
|
@@ -6763,6 +7859,7 @@ function createDeliveryService() {
|
|
|
6763
7859
|
name: "Express",
|
|
6764
7860
|
description: "Delivered within the hour",
|
|
6765
7861
|
fee: money(25),
|
|
7862
|
+
fee_status: "priced",
|
|
6766
7863
|
currency: "GHS",
|
|
6767
7864
|
free_delivery_applied: false,
|
|
6768
7865
|
eta_min_minutes: 30,
|
|
@@ -11681,7 +12778,7 @@ var ID_PREFIX = {
|
|
|
11681
12778
|
product: "prod_",
|
|
11682
12779
|
service: "svc_"
|
|
11683
12780
|
};
|
|
11684
|
-
var
|
|
12781
|
+
var DEFAULT_CURRENCY2 = "GHS";
|
|
11685
12782
|
function slugify(value) {
|
|
11686
12783
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
11687
12784
|
}
|
|
@@ -11716,7 +12813,7 @@ function makeSeedContext(registry) {
|
|
|
11716
12813
|
const business = {
|
|
11717
12814
|
business_type: "other",
|
|
11718
12815
|
email: `hello@${handle}.test`,
|
|
11719
|
-
default_currency:
|
|
12816
|
+
default_currency: DEFAULT_CURRENCY2,
|
|
11720
12817
|
default_offers_table_service: false,
|
|
11721
12818
|
default_accepts_online_orders: true,
|
|
11722
12819
|
status: "active",
|
|
@@ -11895,7 +12992,8 @@ function createDeps(options = {}) {
|
|
|
11895
12992
|
const inventory = createInventoryService({ registry });
|
|
11896
12993
|
const cart = createCartService({ registry, clock, ids, bus, inventory });
|
|
11897
12994
|
const orders = createOrderService({ registry, clock, bus });
|
|
11898
|
-
const
|
|
12995
|
+
const payments = createPaymentService({ registry, clock, bus });
|
|
12996
|
+
const purchaseIntents = createPurchaseIntentMockService({ registry, clock, ids, bus });
|
|
11899
12997
|
const subscriptions = createSubscriptionService({ registry, clock, bus });
|
|
11900
12998
|
const scheduling = createSchedulingService({ registry, clock, bus });
|
|
11901
12999
|
const fx = createFxService({ registry, clock, ids });
|
|
@@ -11916,7 +13014,8 @@ function createDeps(options = {}) {
|
|
|
11916
13014
|
business,
|
|
11917
13015
|
catalogue,
|
|
11918
13016
|
cart,
|
|
11919
|
-
|
|
13017
|
+
payments,
|
|
13018
|
+
purchaseIntents,
|
|
11920
13019
|
orders,
|
|
11921
13020
|
subscriptions,
|
|
11922
13021
|
scheduling,
|