@porulle/core 0.24.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/identity-free-routes.d.ts +1 -1
- package/dist/auth/identity-free-routes.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/interfaces/rest/route-coverage.js +1 -1
- package/dist/interfaces/rest/routes/payments.d.ts.map +1 -1
- package/dist/interfaces/rest/routes/payments.js +11 -4
- package/dist/kernel/state-machine/machine.d.ts +11 -0
- package/dist/kernel/state-machine/machine.d.ts.map +1 -1
- package/dist/kernel/state-machine/machine.js +17 -1
- package/dist/modules/orders/service.d.ts +1 -0
- package/dist/modules/orders/service.d.ts.map +1 -1
- package/dist/modules/orders/service.js +29 -4
- package/dist/modules/payments/service.d.ts +1 -1
- package/dist/modules/payments/service.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/auth/identity-free-routes.ts +1 -1
- package/src/index.ts +1 -0
- package/src/interfaces/rest/route-coverage.ts +1 -1
- package/src/interfaces/rest/routes/payments.ts +11 -4
- package/src/kernel/state-machine/machine.ts +29 -1
- package/src/modules/orders/service.ts +34 -4
- package/src/modules/payments/service.ts +1 -1
|
@@ -35,7 +35,7 @@ export declare const IDENTITY_FREE_ROUTES: readonly IdentityFreeRoute[];
|
|
|
35
35
|
* The routes that want this are app-local by nature — a signed payment notify,
|
|
36
36
|
* a tracked click-out — and they have no session, taking their organization
|
|
37
37
|
* from the payload they verified rather than from a resolver, which is what
|
|
38
|
-
* core's own `POST /api/payments/webhook` already does.
|
|
38
|
+
* core's own `POST /api/payments/webhook/:provider` already does.
|
|
39
39
|
*
|
|
40
40
|
* WHAT AN ENTRY COSTS: `authMiddleware` is followed by the wrapper that opens
|
|
41
41
|
* the plugin database scope FROM THE RESOLVED ACTOR. A route listed here gets
|
|
@@ -30,7 +30,7 @@ function normalize(entry) {
|
|
|
30
30
|
* The routes that want this are app-local by nature — a signed payment notify,
|
|
31
31
|
* a tracked click-out — and they have no session, taking their organization
|
|
32
32
|
* from the payload they verified rather than from a resolver, which is what
|
|
33
|
-
* core's own `POST /api/payments/webhook` already does.
|
|
33
|
+
* core's own `POST /api/payments/webhook/:provider` already does.
|
|
34
34
|
*
|
|
35
35
|
* WHAT AN ENTRY COSTS: `authMiddleware` is followed by the wrapper that opens
|
|
36
36
|
* the plugin database scope FROM THE RESOLVED ACTOR. A route listed here gets
|
package/dist/index.d.ts
CHANGED
|
@@ -57,7 +57,7 @@ export { withTiming } from "./kernel/service-timing.js";
|
|
|
57
57
|
export { CommerceNotFoundError, CommerceValidationError, CommerceForbiddenError, CommerceUnauthorizedError, CommerceReauthRequiredError, CommerceConflictError, CommerceInvalidTransitionError, OrgResolutionError, } from "./kernel/errors.js";
|
|
58
58
|
export { mapErrorToStatus } from "./kernel/error-mapper.js";
|
|
59
59
|
export { canTransition, assertTransition, orderStateMachine, extendOrderStateMachine, } from "./kernel/state-machine/machine.js";
|
|
60
|
-
export type { PaymentAdapter, PaymentCapture, PaymentIntent, PaymentRefund, PaymentWebhookEvent, } from "./modules/payments/adapter.js";
|
|
60
|
+
export type { PaymentAdapter, PaymentCapture, PaymentIntent, PaymentRefund, PaymentWebhookEvent, CreatePaymentIntentParams, } from "./modules/payments/adapter.js";
|
|
61
61
|
export { defineChannelConnector } from "./modules/channels/adapter.js";
|
|
62
62
|
export type { ChannelCatalogImage, ChannelCatalogItem, ChannelCatalogLocalizedAttributes, ChannelCatalogOptionType, ChannelCatalogPage, ChannelCatalogPrice, ChannelCatalogVariant, ChannelConnector, ChannelConnectorCapabilities, ChannelInventoryLevel, ChannelOrderLine, ChannelOrderSlice, ChannelConnectorError, ChannelPushCatalogField, ChannelPushCatalogImage, ChannelPushCatalogIntent, ChannelPushCatalogItem, ChannelPushCatalogImageOutcome, ChannelPushCatalogItemOutcome, ChannelPushCatalogPreviousField, ChannelPushCatalogResult, ChannelPushCatalogVariant, ChannelOrderStatus, ChannelPushOrderResult, ChannelRefundResult, ChannelReservation, ChannelStore, ChannelWebhookEvent, } from "./modules/channels/adapter.js";
|
|
63
63
|
export type { StorageAdapter } from "./modules/media/adapter.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,7 +12,7 @@ export const PUBLIC_ROUTES = [
|
|
|
12
12
|
{ method: "POST", path: "/api/checkout", justification: "Anonymous storefront checkout is authorized by the customer actor and cart/payment pipeline." },
|
|
13
13
|
{ method: "GET", path: "/api/media/:id", justification: "Public media assets redirect to their configured public storage URL; signed URLs still require an actor in the handler." },
|
|
14
14
|
{ method: "POST", path: "/api/promotions/validate", justification: "Storefront shoppers validate a promotion code before checkout; the route is rate-limited." },
|
|
15
|
-
{ method: "POST", path: "/api/payments/webhook", justification: "The payment provider authenticates this endpoint with its signed webhook payload." },
|
|
15
|
+
{ method: "POST", path: "/api/payments/webhook/:provider", justification: "The payment provider authenticates this endpoint with its signed webhook payload." },
|
|
16
16
|
];
|
|
17
17
|
function hasPermissionGuard(handler, method, seen = new Set()) {
|
|
18
18
|
if (typeof handler !== "function" || seen.has(handler))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payments.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/rest/routes/payments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,KAAK,MAAM,EAAwC,MAAM,aAAa,CAAC;AAOhF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"payments.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/rest/routes/payments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,KAAK,MAAM,EAAwC,MAAM,aAAa,CAAC;AAOhF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,gCA4E3C"}
|
|
@@ -4,8 +4,15 @@ import { processedWebhookEvents } from "../../../modules/webhooks/schema.js";
|
|
|
4
4
|
import { toCommerceError } from "../../../kernel/errors.js";
|
|
5
5
|
export function paymentRoutes(kernel) {
|
|
6
6
|
const router = new OpenAPIHono();
|
|
7
|
-
router.post("/webhook", async (c) => {
|
|
8
|
-
const
|
|
7
|
+
router.post("/webhook/:provider", async (c) => {
|
|
8
|
+
const provider = c.req.param("provider");
|
|
9
|
+
if (!provider)
|
|
10
|
+
return c.notFound();
|
|
11
|
+
const resolvedAdapter = kernel.services.payments.resolveAdapter(provider);
|
|
12
|
+
if (!resolvedAdapter.ok)
|
|
13
|
+
return c.notFound();
|
|
14
|
+
const adapter = resolvedAdapter.value;
|
|
15
|
+
const result = await adapter.verifyWebhook(c.req.raw);
|
|
9
16
|
if (!result.ok) {
|
|
10
17
|
return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
11
18
|
}
|
|
@@ -19,14 +26,14 @@ export function paymentRoutes(kernel) {
|
|
|
19
26
|
.insert(processedWebhookEvents)
|
|
20
27
|
.values({
|
|
21
28
|
eventId: event.id,
|
|
22
|
-
provider:
|
|
29
|
+
provider: adapter.providerId,
|
|
23
30
|
eventType: event.type,
|
|
24
31
|
})
|
|
25
32
|
.onConflictDoNothing()
|
|
26
33
|
.returning({ id: processedWebhookEvents.id });
|
|
27
34
|
if (!inserted)
|
|
28
35
|
return { duplicate: true };
|
|
29
|
-
if (event.type === "payment_intent.succeeded") {
|
|
36
|
+
if (adapter.providerId === "stripe" && event.type === "payment_intent.succeeded") {
|
|
30
37
|
const data = event.data;
|
|
31
38
|
const metadata = data?.metadata;
|
|
32
39
|
if (typeof metadata?.orderId === "string") {
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
export interface StateDefinition<TState extends string> {
|
|
2
2
|
states: readonly TState[];
|
|
3
3
|
initial: TState;
|
|
4
|
+
/**
|
|
5
|
+
* The states an entity may be CREATED in, as opposed to reach by transition.
|
|
6
|
+
*
|
|
7
|
+
* `states` is not this set and must never be used as it: it contains `fulfilled`, `refunded` and
|
|
8
|
+
* `cancelled`, so validating creation against it would let a caller create an order past its
|
|
9
|
+
* entire lifecycle — no transition recorded, no status-change hook fired, nothing to audit.
|
|
10
|
+
* `initial` alone is too narrow in the other direction: a hosted-redirect gateway produces an
|
|
11
|
+
* order that exists and is not yet paid, and that order must not spend a moment looking like a
|
|
12
|
+
* healthy `pending` one.
|
|
13
|
+
*/
|
|
14
|
+
initialStates: readonly TState[];
|
|
4
15
|
transitions: Record<TState, readonly TState[]>;
|
|
5
16
|
terminal: readonly TState[];
|
|
6
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../src/kernel/state-machine/machine.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe,CAAC,MAAM,SAAS,MAAM;IACpD,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IAC/C,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../src/kernel/state-machine/machine.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe,CAAC,MAAM,SAAS,MAAM;IACpD,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;OASG;IACH,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IAC/C,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AA+BhC,eAAO,MAAM,iBAAiB,EAAE,eAAe,CAAC,MAAM,CAMrD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAC1C,eAAe,CAAC,MAAM,CAAC,CAiCzB;AAED,wBAAgB,aAAa,CAAC,MAAM,SAAS,MAAM,EACjD,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,EAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,OAAO,CAET;AAED,wBAAgB,gBAAgB,CAAC,MAAM,SAAS,MAAM,EACpD,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,EAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACT,IAAI,CAQN"}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { CommerceInvalidTransitionError } from "../errors.js";
|
|
2
2
|
const DEFAULT_TRANSITIONS = {
|
|
3
3
|
pending: ["confirmed", "cancelled"],
|
|
4
|
+
// An order that exists but is not yet paid. Every hosted-redirect gateway produces one: the
|
|
5
|
+
// shopper has been sent to the gateway and nothing is owed to a merchant yet. It is a core
|
|
6
|
+
// state rather than something each application re-invents, because the alternative is every
|
|
7
|
+
// consumer inventing a different name for the same thing.
|
|
8
|
+
//
|
|
9
|
+
// There is no `expired`. An expiry is a cancellation carrying a reason, and `changeStatus`
|
|
10
|
+
// already carries one; a second terminal meaning "cancelled, but by a clock" would cost every
|
|
11
|
+
// query, filter and report a second name to remember for one outcome.
|
|
12
|
+
pending_payment: ["confirmed", "cancelled"],
|
|
4
13
|
confirmed: ["processing", "cancelled"],
|
|
5
14
|
processing: ["partially_fulfilled", "fulfilled", "cancelled"],
|
|
6
15
|
partially_fulfilled: ["fulfilled", "cancelled"],
|
|
@@ -9,13 +18,16 @@ const DEFAULT_TRANSITIONS = {
|
|
|
9
18
|
refunded: [],
|
|
10
19
|
};
|
|
11
20
|
const DEFAULT_STATES = [
|
|
12
|
-
"pending", "confirmed", "processing", "partially_fulfilled",
|
|
21
|
+
"pending", "pending_payment", "confirmed", "processing", "partially_fulfilled",
|
|
13
22
|
"fulfilled", "cancelled", "refunded",
|
|
14
23
|
];
|
|
24
|
+
/** The two ways an order may begin: paid-on-arrival, or awaiting a gateway. */
|
|
25
|
+
const DEFAULT_INITIAL_STATES = ["pending", "pending_payment"];
|
|
15
26
|
const DEFAULT_TERMINAL = ["cancelled", "refunded"];
|
|
16
27
|
export const orderStateMachine = {
|
|
17
28
|
states: DEFAULT_STATES,
|
|
18
29
|
initial: "pending",
|
|
30
|
+
initialStates: DEFAULT_INITIAL_STATES,
|
|
19
31
|
transitions: DEFAULT_TRANSITIONS,
|
|
20
32
|
terminal: DEFAULT_TERMINAL,
|
|
21
33
|
};
|
|
@@ -56,6 +68,10 @@ export function extendOrderStateMachine(customTransitions) {
|
|
|
56
68
|
return {
|
|
57
69
|
states: allStates,
|
|
58
70
|
initial: "pending",
|
|
71
|
+
// A custom transition adds states an order may REACH, never one it may start in — that would
|
|
72
|
+
// let `customTransitions` quietly widen what can be created. An application that needs a new
|
|
73
|
+
// starting point declares it deliberately, not as a side effect of describing a transition.
|
|
74
|
+
initialStates: DEFAULT_INITIAL_STATES.filter((state) => allStates.includes(state)),
|
|
59
75
|
transitions: merged,
|
|
60
76
|
terminal,
|
|
61
77
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/orders/service.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/orders/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAkB5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,OAAO,EACL,gBAAgB,EAChB,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,gBAAgB;IAC/B,kGAAkG;IAClG,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,SAAS,EAAE,KAAK,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,UAAU,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,kFAAkF;IAClF,YAAY,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,SAAS,GAAG,WAAW,CAAC;IACtC,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG;IAAE,SAAS,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC;AACnE,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AA+BF,qBAAa,YAAY;IAIX,OAAO,CAAC,IAAI;IAHxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;gBAE9B,IAAI,EAAE,gBAAgB;YAK5B,YAAY;IAQ1B;;;;;;;;;OASG;YACW,YAAY;YAoHZ,uBAAuB;YA8CvB,0BAA0B;YAuB1B,kBAAkB;YAmFlB,gBAAgB;IAiBxB,MAAM,CACV,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,EACf,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IA6R3B,OAAO,CACX,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAyC3B,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAOjC,+EAA+E;IACzE,mBAAmB,CACvB,cAAc,EAAE,MAAM,EACtB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAmBlC,IAAI,CACR,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IA6B7B,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,gBAAgB,EACxB,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAsCnC;;;;OAIG;IACG,MAAM,CACV,CAAC,EAAE,MAAM,EACT,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,IAAI,CAAC;QAAC,EAAE,CAAC,EAAE,IAAI,CAAA;KAAE,EAChC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CACR,MAAM,CAAC;QACL,KAAK,EAAE,KAAK,CAAC;YACX,EAAE,EAAE,MAAM,CAAC;YACX,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,IAAI,CAAC;YACf,MAAM,EAAE,MAAM,CAAC;YACf,UAAU,EAAE,MAAM,CAAC;YACnB,QAAQ,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;gBAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;aAAE,GAAG,IAAI,CAAC;SAC5E,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CACH;IA+BK,YAAY,CAChB,KAAK,EAAE,iBAAiB,EACxB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAoS3B,MAAM,CACV,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,MAAM,SAAsB,EAC5B,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAQ3B,MAAM,CACV,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,MAAM,SAAa,EACnB,GAAG,CAAC,EAAE,SAAS,EACf,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACzB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAenB,cAAc;IAoB5B;;;;;;OAMG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,KAAK,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,EAC9F,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,KAAK,EAAE,aAAa,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;IAyIjE;;;;;;OAMG;IACG,UAAU,CACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,KAAK,EAAE,aAAa,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;IAuD3D,WAAW,CACf,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAYjC,iEAAiE;IAC3D,eAAe,CACnB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;YAuBzE,kBAAkB;IAiB1B,OAAO,CACX,OAAO,EAAE,MAAM,EACf,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;KAAE,EACrD,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAmBvB,SAAS,CACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAMzB,UAAU,CACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IAQrC;;;OAGG;IACG,QAAQ,CACZ,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QACtB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;QACnC,EAAE,EAAE,IAAI,CAAC;QACT,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC/B,CAAC,CAAC,CAAC;IA2DJ;;;;OAIG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAC1B,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAiE3B,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAcxC,yEAAyE;IACzE,OAAO,CAAC,iBAAiB;IAyBzB;;;;OAIG;YACW,iBAAiB;IA6BzB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC/B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;KAChD,EACD,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAyE3B,mBAAmB,CACvB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,EAC3B,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IA0C3B,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAmC3B,WAAW,CACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;QACJ,QAAQ,CAAC,EAAE,IAAI,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,EACD,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,EACpB,GAAG,CAAC,EAAE,SAAS,GACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;CAS1B"}
|
|
@@ -241,6 +241,17 @@ export class OrderService {
|
|
|
241
241
|
const afterHooks = this.deps.hooks.resolve("orders.afterCreate");
|
|
242
242
|
const hookCtx = context(actor, this.deps.services, this.deps.database, this.deps.config, ctx?.tx);
|
|
243
243
|
const processed = await runBeforeHooks(beforeHooks, serviceInput, "create", hookCtx);
|
|
244
|
+
// Two different mistakes, two different messages. A caller who typoed a state and a caller who
|
|
245
|
+
// asked for a real state that an order may not START in will look in completely different
|
|
246
|
+
// places, and one message for both sends half of them to the wrong one.
|
|
247
|
+
const status = processed.status ?? this.machine.initial;
|
|
248
|
+
if (!this.machine.states.includes(status)) {
|
|
249
|
+
return Err(new CommerceValidationError(`Unknown order status "${status}".`));
|
|
250
|
+
}
|
|
251
|
+
if (!this.machine.initialStates.includes(status)) {
|
|
252
|
+
return Err(new CommerceValidationError(`An order cannot be created in status "${status}"; it is reached by transition. ` +
|
|
253
|
+
`Orders may be created in: ${this.machine.initialStates.join(", ")}.`));
|
|
254
|
+
}
|
|
244
255
|
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
245
256
|
const idempotencyScope = processed.idempotencyKey
|
|
246
257
|
? await makeIdempotencyScope(actor, opts?.guestCredential, typeof processed.metadata?.cartId === "string"
|
|
@@ -294,7 +305,7 @@ export class OrderService {
|
|
|
294
305
|
...(opts?.trustedPricing === true && processed.id != null ? { id: processed.id } : {}),
|
|
295
306
|
organizationId: orgId,
|
|
296
307
|
orderNumber,
|
|
297
|
-
status
|
|
308
|
+
status,
|
|
298
309
|
currency: processed.currency,
|
|
299
310
|
subtotal: computedSubtotal,
|
|
300
311
|
taxTotal: processed.taxTotal,
|
|
@@ -358,8 +369,8 @@ export class OrderService {
|
|
|
358
369
|
}
|
|
359
370
|
await this.repo.createStatusHistory({
|
|
360
371
|
orderId: order.id,
|
|
361
|
-
fromStatus:
|
|
362
|
-
toStatus:
|
|
372
|
+
fromStatus: status,
|
|
373
|
+
toStatus: status,
|
|
363
374
|
reason: "order_created",
|
|
364
375
|
changedBy: actor?.userId ?? "system",
|
|
365
376
|
}, ctx);
|
|
@@ -373,8 +384,22 @@ export class OrderService {
|
|
|
373
384
|
if (!order)
|
|
374
385
|
return Err(new CommerceNotFoundError("Order not found."));
|
|
375
386
|
const access = await this.authorizeOrderRead(order, actor, ctx, guestCredential);
|
|
387
|
+
// A refusal here has to be INDISTINGUISHABLE from the miss above. Looking the row up before
|
|
388
|
+
// authorizing it turns the pair into an existence oracle: 403 meant "this order is real" and
|
|
389
|
+
// 404 meant it is not, and since `GET /api/orders/{idOrNumber}` also accepts an order NUMBER —
|
|
390
|
+
// which comes out of a sequence and is therefore short, ordered and walkable — an anonymous
|
|
391
|
+
// caller could enumerate a store's orders and read off its volume.
|
|
392
|
+
//
|
|
393
|
+
// The same instinct already governs the guest branch of `authorizeOrderRead` one level down,
|
|
394
|
+
// which refuses a stale cart secret with the identical error as a wrong one "so a stale window
|
|
395
|
+
// is not an oracle telling the caller their secret is valid". It was right and simply did not
|
|
396
|
+
// reach far enough up: the row's existence had already leaked before that branch was consulted.
|
|
397
|
+
//
|
|
398
|
+
// So an unauthorized read answers exactly as a missing one does. The caller who may legitimately
|
|
399
|
+
// see the order is unaffected; the caller who may not now cannot tell the two apart, which is
|
|
400
|
+
// the only shape in which "not found" and "not yours" can share a door.
|
|
376
401
|
if (!access.ok)
|
|
377
|
-
return
|
|
402
|
+
return Err(new CommerceNotFoundError("Order not found."));
|
|
378
403
|
const hydrated = await this.hydrateOrder(order, ctx);
|
|
379
404
|
// Run afterGet hooks — allows plugins to enrich the order (e.g., vendor fulfillment)
|
|
380
405
|
const afterGetHooks = this.deps.hooks.resolve("orders.afterGet");
|
|
@@ -8,7 +8,7 @@ export declare class PaymentsService {
|
|
|
8
8
|
* Resolve a specific adapter by its providerId.
|
|
9
9
|
* Falls back to the default (first) adapter only when paymentMethodId is omitted.
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
resolveAdapter(paymentMethodId?: string): Result<PaymentAdapter>;
|
|
12
12
|
/** Expose registered provider IDs for validation hooks. */
|
|
13
13
|
get registeredProviderIds(): string[];
|
|
14
14
|
authorize(params: Omit<CreatePaymentIntentParams, "orderId"> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/payments/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EACV,yBAAyB,EACzB,cAAc,EACd,cAAc,EACd,aAAa,EACb,aAAa,EACd,MAAM,cAAc,CAAC;AAEtB,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;gBAEhD,QAAQ,EAAE,cAAc,EAAE,GAAG,SAAS;IAQlD;;;OAGG;IACH,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/modules/payments/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EACV,yBAAyB,EACzB,cAAc,EACd,cAAc,EACd,aAAa,EACb,aAAa,EACd,MAAM,cAAc,CAAC;AAEtB,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;gBAEhD,QAAQ,EAAE,cAAc,EAAE,GAAG,SAAS;IAQlD;;;OAGG;IACH,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;IAmBhE,2DAA2D;IAC3D,IAAI,qBAAqB,IAAI,MAAM,EAAE,CAEpC;IAEK,SAAS,CACb,MAAM,EAAE,IAAI,CAAC,yBAAyB,EAAE,SAAS,CAAC,GAAG;QACnD,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,GACA,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAgB3B,OAAO,CACX,eAAe,EAAE,MAAM,EACvB,MAAM,CAAC,EAAE,MAAM,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAM5B,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAM3B,MAAM,CACV,eAAe,EAAE,MAAM,EACvB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAMlB,aAAa,CAAC,OAAO,EAAE,OAAO;CAKrC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
"eslint": "^9.39.1",
|
|
63
63
|
"typescript": "5.9.2",
|
|
64
64
|
"vitest": "^3.2.4",
|
|
65
|
-
"@porulle/
|
|
66
|
-
"@porulle/
|
|
65
|
+
"@porulle/eslint-config": "0.1.0",
|
|
66
|
+
"@porulle/typescript-config": "0.1.0"
|
|
67
67
|
},
|
|
68
68
|
"publishConfig": {
|
|
69
69
|
"access": "public"
|
|
@@ -65,7 +65,7 @@ function normalize(entry: string): string {
|
|
|
65
65
|
* The routes that want this are app-local by nature — a signed payment notify,
|
|
66
66
|
* a tracked click-out — and they have no session, taking their organization
|
|
67
67
|
* from the payload they verified rather than from a resolver, which is what
|
|
68
|
-
* core's own `POST /api/payments/webhook` already does.
|
|
68
|
+
* core's own `POST /api/payments/webhook/:provider` already does.
|
|
69
69
|
*
|
|
70
70
|
* WHAT AN ENTRY COSTS: `authMiddleware` is followed by the wrapper that opens
|
|
71
71
|
* the plugin database scope FROM THE RESOLVED ACTOR. A route listed here gets
|
package/src/index.ts
CHANGED
|
@@ -20,7 +20,7 @@ export const PUBLIC_ROUTES: readonly PublicRoute[] = [
|
|
|
20
20
|
{ method: "POST", path: "/api/checkout", justification: "Anonymous storefront checkout is authorized by the customer actor and cart/payment pipeline." },
|
|
21
21
|
{ method: "GET", path: "/api/media/:id", justification: "Public media assets redirect to their configured public storage URL; signed URLs still require an actor in the handler." },
|
|
22
22
|
{ method: "POST", path: "/api/promotions/validate", justification: "Storefront shoppers validate a promotion code before checkout; the route is rate-limited." },
|
|
23
|
-
{ method: "POST", path: "/api/payments/webhook", justification: "The payment provider authenticates this endpoint with its signed webhook payload." },
|
|
23
|
+
{ method: "POST", path: "/api/payments/webhook/:provider", justification: "The payment provider authenticates this endpoint with its signed webhook payload." },
|
|
24
24
|
];
|
|
25
25
|
|
|
26
26
|
type RouteTableApp = {
|
|
@@ -11,8 +11,15 @@ type Db = PgDatabase<PgQueryResultHKT, Record<string, unknown>>;
|
|
|
11
11
|
export function paymentRoutes(kernel: Kernel) {
|
|
12
12
|
const router = new OpenAPIHono<AppEnv>();
|
|
13
13
|
|
|
14
|
-
router.post("/webhook", async (c) => {
|
|
15
|
-
const
|
|
14
|
+
router.post("/webhook/:provider", async (c) => {
|
|
15
|
+
const provider = c.req.param("provider");
|
|
16
|
+
if (!provider) return c.notFound();
|
|
17
|
+
|
|
18
|
+
const resolvedAdapter = kernel.services.payments.resolveAdapter(provider);
|
|
19
|
+
if (!resolvedAdapter.ok) return c.notFound();
|
|
20
|
+
|
|
21
|
+
const adapter = resolvedAdapter.value;
|
|
22
|
+
const result = await adapter.verifyWebhook(c.req.raw);
|
|
16
23
|
if (!result.ok) {
|
|
17
24
|
return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
18
25
|
}
|
|
@@ -28,7 +35,7 @@ export function paymentRoutes(kernel: Kernel) {
|
|
|
28
35
|
.insert(processedWebhookEvents)
|
|
29
36
|
.values({
|
|
30
37
|
eventId: event.id,
|
|
31
|
-
provider:
|
|
38
|
+
provider: adapter.providerId,
|
|
32
39
|
eventType: event.type,
|
|
33
40
|
})
|
|
34
41
|
.onConflictDoNothing()
|
|
@@ -36,7 +43,7 @@ export function paymentRoutes(kernel: Kernel) {
|
|
|
36
43
|
|
|
37
44
|
if (!inserted) return { duplicate: true };
|
|
38
45
|
|
|
39
|
-
if (event.type === "payment_intent.succeeded") {
|
|
46
|
+
if (adapter.providerId === "stripe" && event.type === "payment_intent.succeeded") {
|
|
40
47
|
const data = event.data as Record<string, unknown> | undefined;
|
|
41
48
|
const metadata = data?.metadata as Record<string, unknown> | undefined;
|
|
42
49
|
if (typeof metadata?.orderId === "string") {
|
|
@@ -3,6 +3,17 @@ import { CommerceInvalidTransitionError } from "../errors.js";
|
|
|
3
3
|
export interface StateDefinition<TState extends string> {
|
|
4
4
|
states: readonly TState[];
|
|
5
5
|
initial: TState;
|
|
6
|
+
/**
|
|
7
|
+
* The states an entity may be CREATED in, as opposed to reach by transition.
|
|
8
|
+
*
|
|
9
|
+
* `states` is not this set and must never be used as it: it contains `fulfilled`, `refunded` and
|
|
10
|
+
* `cancelled`, so validating creation against it would let a caller create an order past its
|
|
11
|
+
* entire lifecycle — no transition recorded, no status-change hook fired, nothing to audit.
|
|
12
|
+
* `initial` alone is too narrow in the other direction: a hosted-redirect gateway produces an
|
|
13
|
+
* order that exists and is not yet paid, and that order must not spend a moment looking like a
|
|
14
|
+
* healthy `pending` one.
|
|
15
|
+
*/
|
|
16
|
+
initialStates: readonly TState[];
|
|
6
17
|
transitions: Record<TState, readonly TState[]>;
|
|
7
18
|
terminal: readonly TState[];
|
|
8
19
|
}
|
|
@@ -11,6 +22,15 @@ export type OrderState = string;
|
|
|
11
22
|
|
|
12
23
|
const DEFAULT_TRANSITIONS: Record<string, readonly string[]> = {
|
|
13
24
|
pending: ["confirmed", "cancelled"],
|
|
25
|
+
// An order that exists but is not yet paid. Every hosted-redirect gateway produces one: the
|
|
26
|
+
// shopper has been sent to the gateway and nothing is owed to a merchant yet. It is a core
|
|
27
|
+
// state rather than something each application re-invents, because the alternative is every
|
|
28
|
+
// consumer inventing a different name for the same thing.
|
|
29
|
+
//
|
|
30
|
+
// There is no `expired`. An expiry is a cancellation carrying a reason, and `changeStatus`
|
|
31
|
+
// already carries one; a second terminal meaning "cancelled, but by a clock" would cost every
|
|
32
|
+
// query, filter and report a second name to remember for one outcome.
|
|
33
|
+
pending_payment: ["confirmed", "cancelled"],
|
|
14
34
|
confirmed: ["processing", "cancelled"],
|
|
15
35
|
processing: ["partially_fulfilled", "fulfilled", "cancelled"],
|
|
16
36
|
partially_fulfilled: ["fulfilled", "cancelled"],
|
|
@@ -20,15 +40,19 @@ const DEFAULT_TRANSITIONS: Record<string, readonly string[]> = {
|
|
|
20
40
|
};
|
|
21
41
|
|
|
22
42
|
const DEFAULT_STATES: readonly string[] = [
|
|
23
|
-
"pending", "confirmed", "processing", "partially_fulfilled",
|
|
43
|
+
"pending", "pending_payment", "confirmed", "processing", "partially_fulfilled",
|
|
24
44
|
"fulfilled", "cancelled", "refunded",
|
|
25
45
|
];
|
|
26
46
|
|
|
47
|
+
/** The two ways an order may begin: paid-on-arrival, or awaiting a gateway. */
|
|
48
|
+
const DEFAULT_INITIAL_STATES: readonly string[] = ["pending", "pending_payment"];
|
|
49
|
+
|
|
27
50
|
const DEFAULT_TERMINAL: readonly string[] = ["cancelled", "refunded"];
|
|
28
51
|
|
|
29
52
|
export const orderStateMachine: StateDefinition<string> = {
|
|
30
53
|
states: DEFAULT_STATES,
|
|
31
54
|
initial: "pending",
|
|
55
|
+
initialStates: DEFAULT_INITIAL_STATES,
|
|
32
56
|
transitions: DEFAULT_TRANSITIONS,
|
|
33
57
|
terminal: DEFAULT_TERMINAL,
|
|
34
58
|
};
|
|
@@ -73,6 +97,10 @@ export function extendOrderStateMachine(
|
|
|
73
97
|
return {
|
|
74
98
|
states: allStates,
|
|
75
99
|
initial: "pending",
|
|
100
|
+
// A custom transition adds states an order may REACH, never one it may start in — that would
|
|
101
|
+
// let `customTransitions` quietly widen what can be created. An application that needs a new
|
|
102
|
+
// starting point declares it deliberately, not as a side effect of describing a transition.
|
|
103
|
+
initialStates: DEFAULT_INITIAL_STATES.filter((state) => allStates.includes(state)),
|
|
76
104
|
transitions: merged,
|
|
77
105
|
terminal,
|
|
78
106
|
};
|
|
@@ -60,6 +60,7 @@ export interface CreateOrderInput {
|
|
|
60
60
|
grandTotal: number;
|
|
61
61
|
paymentIntentId?: string | undefined;
|
|
62
62
|
paymentMethodId?: string | undefined;
|
|
63
|
+
status?: string;
|
|
63
64
|
metadata?: Record<string, unknown>;
|
|
64
65
|
lineItems: Array<{
|
|
65
66
|
entityId: string;
|
|
@@ -522,6 +523,21 @@ export class OrderService {
|
|
|
522
523
|
"create",
|
|
523
524
|
hookCtx,
|
|
524
525
|
);
|
|
526
|
+
// Two different mistakes, two different messages. A caller who typoed a state and a caller who
|
|
527
|
+
// asked for a real state that an order may not START in will look in completely different
|
|
528
|
+
// places, and one message for both sends half of them to the wrong one.
|
|
529
|
+
const status = processed.status ?? this.machine.initial;
|
|
530
|
+
if (!this.machine.states.includes(status)) {
|
|
531
|
+
return Err(new CommerceValidationError(`Unknown order status "${status}".`));
|
|
532
|
+
}
|
|
533
|
+
if (!this.machine.initialStates.includes(status)) {
|
|
534
|
+
return Err(
|
|
535
|
+
new CommerceValidationError(
|
|
536
|
+
`An order cannot be created in status "${status}"; it is reached by transition. ` +
|
|
537
|
+
`Orders may be created in: ${this.machine.initialStates.join(", ")}.`,
|
|
538
|
+
),
|
|
539
|
+
);
|
|
540
|
+
}
|
|
525
541
|
|
|
526
542
|
const orgId = resolveOrgIdForCommerce(actor, this.deps.config);
|
|
527
543
|
const idempotencyScope = processed.idempotencyKey
|
|
@@ -617,7 +633,7 @@ export class OrderService {
|
|
|
617
633
|
...(opts?.trustedPricing === true && processed.id != null ? { id: processed.id } : {}),
|
|
618
634
|
organizationId: orgId,
|
|
619
635
|
orderNumber,
|
|
620
|
-
status
|
|
636
|
+
status,
|
|
621
637
|
currency: processed.currency,
|
|
622
638
|
subtotal: computedSubtotal,
|
|
623
639
|
taxTotal: processed.taxTotal,
|
|
@@ -718,8 +734,8 @@ export class OrderService {
|
|
|
718
734
|
await this.repo.createStatusHistory(
|
|
719
735
|
{
|
|
720
736
|
orderId: order.id,
|
|
721
|
-
fromStatus:
|
|
722
|
-
toStatus:
|
|
737
|
+
fromStatus: status,
|
|
738
|
+
toStatus: status,
|
|
723
739
|
reason: "order_created",
|
|
724
740
|
changedBy: actor?.userId ?? "system",
|
|
725
741
|
},
|
|
@@ -757,7 +773,21 @@ export class OrderService {
|
|
|
757
773
|
ctx,
|
|
758
774
|
guestCredential,
|
|
759
775
|
);
|
|
760
|
-
|
|
776
|
+
// A refusal here has to be INDISTINGUISHABLE from the miss above. Looking the row up before
|
|
777
|
+
// authorizing it turns the pair into an existence oracle: 403 meant "this order is real" and
|
|
778
|
+
// 404 meant it is not, and since `GET /api/orders/{idOrNumber}` also accepts an order NUMBER —
|
|
779
|
+
// which comes out of a sequence and is therefore short, ordered and walkable — an anonymous
|
|
780
|
+
// caller could enumerate a store's orders and read off its volume.
|
|
781
|
+
//
|
|
782
|
+
// The same instinct already governs the guest branch of `authorizeOrderRead` one level down,
|
|
783
|
+
// which refuses a stale cart secret with the identical error as a wrong one "so a stale window
|
|
784
|
+
// is not an oracle telling the caller their secret is valid". It was right and simply did not
|
|
785
|
+
// reach far enough up: the row's existence had already leaked before that branch was consulted.
|
|
786
|
+
//
|
|
787
|
+
// So an unauthorized read answers exactly as a missing one does. The caller who may legitimately
|
|
788
|
+
// see the order is unaffected; the caller who may not now cannot tell the two apart, which is
|
|
789
|
+
// the only shape in which "not found" and "not yours" can share a door.
|
|
790
|
+
if (!access.ok) return Err(new CommerceNotFoundError("Order not found."));
|
|
761
791
|
|
|
762
792
|
const hydrated = await this.hydrateOrder(order, ctx);
|
|
763
793
|
|
|
@@ -24,7 +24,7 @@ export class PaymentsService {
|
|
|
24
24
|
* Resolve a specific adapter by its providerId.
|
|
25
25
|
* Falls back to the default (first) adapter only when paymentMethodId is omitted.
|
|
26
26
|
*/
|
|
27
|
-
|
|
27
|
+
resolveAdapter(paymentMethodId?: string): Result<PaymentAdapter> {
|
|
28
28
|
if (paymentMethodId) {
|
|
29
29
|
const adapter = this.adapterMap.get(paymentMethodId);
|
|
30
30
|
if (!adapter) {
|