@reactionary/core 0.12.3 → 0.12.5
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/analytics/index.js +1 -0
- package/analytics/placed-order.js +15 -0
- package/capabilities/analytics.capability.js +4 -0
- package/capabilities/identity.capability.js +14 -0
- package/package.json +1 -1
- package/schemas/errors/identity-conflict.error.js +8 -0
- package/schemas/errors/index.js +1 -0
- package/schemas/models/identity-provider.model.js +26 -0
- package/schemas/models/index.js +1 -0
- package/schemas/mutations/analytics/events/commerce.mutation.js +3 -1
- package/schemas/mutations/identity.mutation.js +13 -1
- package/schemas/queries/identity.query.js +2 -0
- package/schemas/session.schema.js +6 -1
- package/src/analytics/index.d.ts +1 -0
- package/src/analytics/placed-order.d.ts +24 -0
- package/src/capabilities/identity.capability.d.ts +13 -2
- package/src/schemas/errors/identity-conflict.error.d.ts +7 -0
- package/src/schemas/errors/index.d.ts +1 -0
- package/src/schemas/models/analytics/event.model.d.ts +6948 -2666
- package/src/schemas/models/identity-provider.model.d.ts +23 -0
- package/src/schemas/models/index.d.ts +1 -0
- package/src/schemas/mutations/analytics/events/commerce.mutation.d.ts +2143 -2
- package/src/schemas/mutations/analytics/events/index.d.ts +2143 -2
- package/src/schemas/mutations/identity.mutation.d.ts +17 -0
- package/src/schemas/queries/identity.query.d.ts +2 -0
- package/src/schemas/session.schema.d.ts +15 -0
package/analytics/index.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
function summarizePlacedOrder(payload) {
|
|
2
|
+
const { checkout, order } = payload;
|
|
3
|
+
const source = checkout ?? order;
|
|
4
|
+
if (!source) {
|
|
5
|
+
return void 0;
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
transactionId: order?.identifier.key ?? checkout?.resultingOrder?.key ?? source.identifier.key,
|
|
9
|
+
items: source.items,
|
|
10
|
+
price: source.price
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
summarizePlacedOrder
|
|
15
|
+
};
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
AnalyticsMutationProductSharedSchema,
|
|
51
51
|
AnalyticsMutationCustomSchema
|
|
52
52
|
} from "../schemas/index.js";
|
|
53
|
+
import { error } from "../schemas/result.js";
|
|
53
54
|
import { BaseCapability } from "./base.capability.js";
|
|
54
55
|
class AnalyticsCapability extends BaseCapability {
|
|
55
56
|
dispatcher;
|
|
@@ -126,6 +127,9 @@ class AnalyticsCapability extends BaseCapability {
|
|
|
126
127
|
return this.dispatcher.emit("payment-info-added", payload);
|
|
127
128
|
}
|
|
128
129
|
async orderPlaced(payload) {
|
|
130
|
+
if (!payload.checkout && !payload.order) {
|
|
131
|
+
return error({ type: "Generic", message: "orderPlaced needs a checkout (or the deprecated order)" });
|
|
132
|
+
}
|
|
129
133
|
return this.dispatcher.emit("order-placed", payload);
|
|
130
134
|
}
|
|
131
135
|
async quoteRequested(payload) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseCapability } from "./base.capability.js";
|
|
2
|
+
const PENDING_EXTERNAL_LOGIN_TTL_MS = 10 * 60 * 1e3;
|
|
2
3
|
class IdentityCapability extends BaseCapability {
|
|
3
4
|
getResourceName() {
|
|
4
5
|
return "identity";
|
|
@@ -7,6 +8,19 @@ class IdentityCapability extends BaseCapability {
|
|
|
7
8
|
this.context.session.identityContext.lastUpdated = /* @__PURE__ */ new Date();
|
|
8
9
|
this.context.session.identityContext.identity = identity;
|
|
9
10
|
}
|
|
11
|
+
setPendingExternalLogin(provider, state) {
|
|
12
|
+
this.context.session.identityContext.pendingExternalLogin = { provider, state, createdAt: /* @__PURE__ */ new Date() };
|
|
13
|
+
}
|
|
14
|
+
/** Returns true, and clears the pending login, when provider and state match a login started in this session within the last 10 minutes. */
|
|
15
|
+
consumePendingExternalLogin(provider, state) {
|
|
16
|
+
const pending = this.context.session.identityContext.pendingExternalLogin;
|
|
17
|
+
delete this.context.session.identityContext.pendingExternalLogin;
|
|
18
|
+
if (!pending || !state) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const fresh = Date.now() - new Date(pending.createdAt).getTime() <= PENDING_EXTERNAL_LOGIN_TTL_MS;
|
|
22
|
+
return fresh && pending.provider === provider && pending.state === state;
|
|
23
|
+
}
|
|
10
24
|
}
|
|
11
25
|
export {
|
|
12
26
|
IdentityCapability
|
package/package.json
CHANGED
package/schemas/errors/index.js
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { BaseModelSchema } from "./base.model.js";
|
|
3
|
+
const IdentityProviderIdentifierSchema = z.looseObject({
|
|
4
|
+
key: z.string()
|
|
5
|
+
});
|
|
6
|
+
const IdentityProviderSchema = BaseModelSchema.extend({
|
|
7
|
+
identifier: IdentityProviderIdentifierSchema,
|
|
8
|
+
displayName: z.string(),
|
|
9
|
+
brand: z.string().optional().meta({ description: "A neutral slug for the identity provider's brand, such as google, apple, amazon, facebook, microsoft or email, so a storefront can choose its own icon. Absent when the brand is not known." }),
|
|
10
|
+
flow: z.enum(["credentials", "redirect"]).meta({ description: "credentials: the shopper types a username and password into the storefront. redirect: the shopper is sent to an external identity provider and returns with a code." })
|
|
11
|
+
});
|
|
12
|
+
const ExternalLoginRedirectSchema = z.looseObject({
|
|
13
|
+
location: z.url().meta({ description: "Where to send the shopper to authenticate with the external identity provider." })
|
|
14
|
+
});
|
|
15
|
+
const PASSWORD_IDENTITY_PROVIDER = IdentityProviderSchema.parse({
|
|
16
|
+
identifier: { key: "password" },
|
|
17
|
+
displayName: "Email and password",
|
|
18
|
+
brand: "email",
|
|
19
|
+
flow: "credentials"
|
|
20
|
+
});
|
|
21
|
+
export {
|
|
22
|
+
ExternalLoginRedirectSchema,
|
|
23
|
+
IdentityProviderIdentifierSchema,
|
|
24
|
+
IdentityProviderSchema,
|
|
25
|
+
PASSWORD_IDENTITY_PROVIDER
|
|
26
|
+
};
|
package/schemas/models/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export * from "./category.model.js";
|
|
|
6
6
|
export * from "./currency.model.js";
|
|
7
7
|
export * from "./identifiers.model.js";
|
|
8
8
|
export * from "./identity.model.js";
|
|
9
|
+
export * from "./identity-provider.model.js";
|
|
9
10
|
export * from "./inventory.model.js";
|
|
10
11
|
export * from "./payment.model.js";
|
|
11
12
|
export * from "./price.model.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { AnalyticsCouponRejectionReasonSchema, AnalyticsStoreRefSchema } from "../../../models/analytics/event-parts.model.js";
|
|
3
3
|
import { CartItemSchema, CartSchema } from "../../../models/cart.model.js";
|
|
4
|
+
import { CheckoutSchema } from "../../../models/checkout.model.js";
|
|
4
5
|
import { CompanySchema } from "../../../models/company.model.js";
|
|
5
6
|
import { ProductVariantIdentifierSchema } from "../../../models/identifiers.model.js";
|
|
6
7
|
import { OrderSchema } from "../../../models/order.model.js";
|
|
@@ -50,7 +51,8 @@ const AnalyticsMutationPaymentInfoAddedSchema = AnalyticsEventMutationBaseSchema
|
|
|
50
51
|
paymentMethod: PaymentMethodSchema
|
|
51
52
|
});
|
|
52
53
|
const AnalyticsMutationOrderPlacedSchema = AnalyticsEventMutationBaseSchema.extend({
|
|
53
|
-
|
|
54
|
+
checkout: CheckoutSchema.optional().meta({ description: "The finalized checkout: what the customer placed. Preferred over order, as the order may not exist yet when the OMS is the order source. Either checkout or order is required." }),
|
|
55
|
+
order: OrderSchema.optional().meta({ description: "Deprecated: pass the checkout instead. Either checkout or order is required.", deprecated: true })
|
|
54
56
|
});
|
|
55
57
|
const AnalyticsMutationQuoteRequestedSchema = AnalyticsEventMutationBaseSchema.extend({
|
|
56
58
|
cart: CartSchema
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { BaseMutationSchema } from "./base.mutation.js";
|
|
3
|
+
import { IdentityProviderIdentifierSchema } from "../models/identity-provider.model.js";
|
|
3
4
|
const IdentityMutationLoginSchema = BaseMutationSchema.extend({
|
|
4
5
|
username: z.string(),
|
|
5
6
|
password: z.string()
|
|
@@ -9,8 +10,19 @@ const IdentityMutationRegisterSchema = BaseMutationSchema.extend({
|
|
|
9
10
|
username: z.string(),
|
|
10
11
|
password: z.string()
|
|
11
12
|
});
|
|
13
|
+
const IdentityMutationStartExternalLoginSchema = BaseMutationSchema.extend({
|
|
14
|
+
provider: IdentityProviderIdentifierSchema,
|
|
15
|
+
callbackUrl: z.url().meta({ description: "The storefront URL the identity provider returns the shopper to. Must be registered with the identity provider." })
|
|
16
|
+
});
|
|
17
|
+
const IdentityMutationCompleteExternalLoginSchema = BaseMutationSchema.extend({
|
|
18
|
+
provider: IdentityProviderIdentifierSchema,
|
|
19
|
+
callbackUrl: z.url().meta({ description: "The same callbackUrl that was passed to startExternalLogin." }),
|
|
20
|
+
callbackParameters: z.record(z.string(), z.string()).meta({ description: "The query parameters the identity provider appended to the callback URL, passed through unchanged." })
|
|
21
|
+
});
|
|
12
22
|
export {
|
|
23
|
+
IdentityMutationCompleteExternalLoginSchema,
|
|
13
24
|
IdentityMutationLoginSchema,
|
|
14
25
|
IdentityMutationLogoutSchema,
|
|
15
|
-
IdentityMutationRegisterSchema
|
|
26
|
+
IdentityMutationRegisterSchema,
|
|
27
|
+
IdentityMutationStartExternalLoginSchema
|
|
16
28
|
};
|
|
@@ -11,7 +11,12 @@ const LanguageContextSchema = z.looseObject({
|
|
|
11
11
|
});
|
|
12
12
|
const IdentityContextSchema = z.looseObject({
|
|
13
13
|
identity: IdentitySchema,
|
|
14
|
-
lastUpdated: z.coerce.date()
|
|
14
|
+
lastUpdated: z.coerce.date(),
|
|
15
|
+
pendingExternalLogin: z.looseObject({
|
|
16
|
+
provider: z.string(),
|
|
17
|
+
state: z.string(),
|
|
18
|
+
createdAt: z.coerce.date()
|
|
19
|
+
}).optional().meta({ description: "An external login that has been started but not completed. Binds the callback to the browser that started it." })
|
|
15
20
|
});
|
|
16
21
|
const SessionSchema = z.looseObject({
|
|
17
22
|
id: z.string().optional().meta({ description: "The id of the visitor's current session, set by the storefront. A long-lived visitor id belongs in marketingContext.identifier, not here." }),
|
package/src/analytics/index.d.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Checkout } from '../schemas/models/checkout.model.js';
|
|
2
|
+
import type { CostBreakDown, ItemCostBreakdown } from '../schemas/models/cost.model.js';
|
|
3
|
+
import type { ProductVariantIdentifier } from '../schemas/models/identifiers.model.js';
|
|
4
|
+
import type { Order } from '../schemas/models/order.model.js';
|
|
5
|
+
export interface PlacedOrderLine {
|
|
6
|
+
variant: ProductVariantIdentifier;
|
|
7
|
+
quantity: number;
|
|
8
|
+
price: ItemCostBreakdown;
|
|
9
|
+
}
|
|
10
|
+
/** What an analytics subscriber needs to report a purchase, whether it was given a checkout or an order. */
|
|
11
|
+
export interface PlacedOrderSummary {
|
|
12
|
+
/** The order key when it is known, otherwise the key of the checkout that created it. */
|
|
13
|
+
transactionId: string;
|
|
14
|
+
items: PlacedOrderLine[];
|
|
15
|
+
price: CostBreakDown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Normalizes an order-placed payload. The checkout is preferred, as it is what the customer placed; the order is
|
|
19
|
+
* the deprecated alternative. Returns undefined when the payload carries neither.
|
|
20
|
+
*/
|
|
21
|
+
export declare function summarizePlacedOrder(payload: {
|
|
22
|
+
checkout?: Checkout;
|
|
23
|
+
order?: Order;
|
|
24
|
+
}): PlacedOrderSummary | undefined;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { ExternalLoginRedirect, IdentityProvider } from "../schemas/models/identity-provider.model.js";
|
|
1
2
|
import type { Identity } from "../schemas/models/identity.model.js";
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
3
|
+
import type { IdentityConflictError } from "../schemas/errors/identity-conflict.error.js";
|
|
4
|
+
import type { IdentityMutationCompleteExternalLogin, IdentityMutationLogin, IdentityMutationLogout, IdentityMutationRegister, IdentityMutationStartExternalLogin } from "../schemas/mutations/identity.mutation.js";
|
|
5
|
+
import type { IdentityQueryProviders, IdentityQuerySelf } from "../schemas/queries/identity.query.js";
|
|
4
6
|
import type { Result } from "../schemas/result.js";
|
|
5
7
|
import { BaseCapability } from "./base.capability.js";
|
|
6
8
|
export declare abstract class IdentityCapability<TIdentity extends Identity = Identity> extends BaseCapability {
|
|
@@ -8,6 +10,15 @@ export declare abstract class IdentityCapability<TIdentity extends Identity = Id
|
|
|
8
10
|
abstract login(payload: IdentityMutationLogin): Promise<Result<TIdentity>>;
|
|
9
11
|
abstract logout(payload: IdentityMutationLogout): Promise<Result<TIdentity>>;
|
|
10
12
|
abstract register(payload: IdentityMutationRegister): Promise<Result<TIdentity>>;
|
|
13
|
+
/** The ways a shopper can sign in with this backend. */
|
|
14
|
+
abstract listProviders(payload: IdentityQueryProviders): Promise<Result<IdentityProvider[]>>;
|
|
15
|
+
/** Begins a redirect flow. The caller sends the shopper to the returned location. */
|
|
16
|
+
abstract startExternalLogin(payload: IdentityMutationStartExternalLogin): Promise<Result<ExternalLoginRedirect>>;
|
|
17
|
+
/** Completes a redirect flow from the parameters the identity provider appended to the callback URL. */
|
|
18
|
+
abstract completeExternalLogin(payload: IdentityMutationCompleteExternalLogin): Promise<Result<TIdentity, IdentityConflictError>>;
|
|
11
19
|
protected getResourceName(): string;
|
|
12
20
|
protected updateIdentityContext(identity: TIdentity): void;
|
|
21
|
+
protected setPendingExternalLogin(provider: string, state: string): void;
|
|
22
|
+
/** Returns true, and clears the pending login, when provider and state match a login started in this session within the last 10 minutes. */
|
|
23
|
+
protected consumePendingExternalLogin(provider: string, state: string | undefined): boolean;
|
|
13
24
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import type { InferType } from '../../zod-utils.js';
|
|
3
|
+
export declare const IdentityConflictErrorSchema: z.ZodObject<{
|
|
4
|
+
type: z.ZodLiteral<"IdentityConflict">;
|
|
5
|
+
message: z.ZodString;
|
|
6
|
+
}, z.core.$loose>;
|
|
7
|
+
export type IdentityConflictError = InferType<typeof IdentityConflictErrorSchema>;
|