@fire-spark/core 0.12.4 → 0.13.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/index.d.ts +33 -2
- package/dist/index.js +223 -24
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -216,8 +216,32 @@ type OrderCustomerSource = {
|
|
|
216
216
|
email?: string | null;
|
|
217
217
|
phone?: string | null;
|
|
218
218
|
};
|
|
219
|
+
/**
|
|
220
|
+
* Stand-ins the order schema needs while a guest's contact data is unknown.
|
|
221
|
+
* Only valid when the merchant's `anonymous_customer` field is optional or
|
|
222
|
+
* hidden; the API rejects them on required fields (`CUSTOMER_FIELD_REQUIRED`).
|
|
223
|
+
*/
|
|
224
|
+
declare const CUSTOMER_INFO_PLACEHOLDERS: {
|
|
225
|
+
readonly email: "unknown@example.com";
|
|
226
|
+
readonly phone: "+10000000000";
|
|
227
|
+
};
|
|
219
228
|
/** Builds the order `customer` snapshot sent on create/update. */
|
|
220
229
|
declare const buildCustomerSnapshot: (source: OrderCustomerSource) => Order$1["customer"];
|
|
230
|
+
/**
|
|
231
|
+
* True when `value` is a stand-in, not data the guest typed: the
|
|
232
|
+
* placeholders above, or a name equal to the anonymous customer id.
|
|
233
|
+
*/
|
|
234
|
+
declare const isCustomerInfoPlaceholder: (key: string, value: unknown, customerId?: string | null) => boolean;
|
|
235
|
+
/** A `customer_info` field holds real (non-placeholder) guest data. */
|
|
236
|
+
declare const isCustomerInfoFieldFilled: (info: Record<string, unknown> | null | undefined, key: string, customerId?: string | null) => boolean;
|
|
237
|
+
/** Strips spaces, dashes, dots and parentheses: "+593 99-123" → "+59399123". */
|
|
238
|
+
declare const normalizeCustomerPhone: (value: string) => string;
|
|
239
|
+
/**
|
|
240
|
+
* Format check the order schema enforces on `customer_info`: email shape and
|
|
241
|
+
* E.164 phone (`+593991234567`). Empty values are valid (presence is checked
|
|
242
|
+
* against the merchant's `anonymous_customer` modes instead).
|
|
243
|
+
*/
|
|
244
|
+
declare const isCustomerInfoValueValid: (key: string, value: string) => boolean;
|
|
221
245
|
//#endregion
|
|
222
246
|
//#region src/services/http.d.ts
|
|
223
247
|
type ServiceHttpOptions = {
|
|
@@ -620,6 +644,8 @@ declare class Order {
|
|
|
620
644
|
setCustomerDetails(details: {
|
|
621
645
|
address_info?: Order$1["customer"]["address_info"];
|
|
622
646
|
billing_info?: Order$1["customer"]["billing_info"];
|
|
647
|
+
/** Guest contact data (anonymous checkout); blanks keep the snapshot. */
|
|
648
|
+
customer_info?: Partial<Order$1["customer"]["customer_info"]>;
|
|
623
649
|
}): void;
|
|
624
650
|
cancelOrder(): Promise<void>;
|
|
625
651
|
/**
|
|
@@ -824,7 +850,7 @@ declare const isOrderPaymentRequiredError: (error: unknown) => error is OrderPay
|
|
|
824
850
|
//#endregion
|
|
825
851
|
//#region src/order/validate.d.ts
|
|
826
852
|
type OrderLineIssueCode = "PRODUCT_NOT_FOUND" | "HIDDEN" | "OUT_OF_STOCK" | "OUTSIDE_HOURS" | "MODIFIER_NOT_FOUND" | "MODIFIER_RULES_INVALID" | "VARIANT_BASE_NOT_ORDERABLE" | "VARIANT_NOT_OFFERED" | "PRICE_MISMATCH" | "TAX_MISMATCH" | "DISCOUNT_MISMATCH" | "QUANTITY_MISMATCH" | "QUANTITY_BELOW_MINIMUM" | "QUANTITY_ABOVE_MAXIMUM" | "STRUCTURE_MISMATCH" | "FEE_MISMATCH" | "REDEEM_EXPIRED" | RedeemIssueCode;
|
|
827
|
-
type OrderIssueCode = "NO_MENU" | "MENU_CLOSED" | "SCOPE_INACTIVE" | "TOTALS_MISMATCH" | "REDEEM_EXPIRED" | RedeemIssueCode | "REDEMPTION_STEPS_MISMATCH" | "REDEMPTION_MISMATCH" | "EMPTY_ORDER" | "ITEMS_BELOW_MINIMUM" | "ITEMS_ABOVE_MAXIMUM" | "TOTAL_BELOW_MINIMUM" | "TOTAL_ABOVE_MAXIMUM" | "REDEEMS_ABOVE_MAXIMUM" | "REDEEMS_TOTAL_ABOVE_MAXIMUM" | "SHIPPING_REQUIRED" | "BILLING_REQUIRED" | "SHIPPING_FIELD_REQUIRED" | "BILLING_FIELD_REQUIRED" | "DAILY_ORDER_LIMIT_REACHED";
|
|
853
|
+
type OrderIssueCode = "NO_MENU" | "MENU_CLOSED" | "SCOPE_INACTIVE" | "TOTALS_MISMATCH" | "REDEEM_EXPIRED" | RedeemIssueCode | "REDEMPTION_STEPS_MISMATCH" | "REDEMPTION_MISMATCH" | "EMPTY_ORDER" | "ITEMS_BELOW_MINIMUM" | "ITEMS_ABOVE_MAXIMUM" | "TOTAL_BELOW_MINIMUM" | "TOTAL_ABOVE_MAXIMUM" | "REDEEMS_ABOVE_MAXIMUM" | "REDEEMS_TOTAL_ABOVE_MAXIMUM" | "SHIPPING_REQUIRED" | "BILLING_REQUIRED" | "SHIPPING_FIELD_REQUIRED" | "BILLING_FIELD_REQUIRED" | "CUSTOMER_FIELD_REQUIRED" | "DAILY_ORDER_LIMIT_REACHED";
|
|
828
854
|
type OrderLineIssue = {
|
|
829
855
|
code: OrderLineIssueCode;
|
|
830
856
|
field?: string;
|
|
@@ -941,6 +967,7 @@ declare const capRedeems: <T extends CapOrder>(order: T) => T & {
|
|
|
941
967
|
id: string;
|
|
942
968
|
parent_uid: string | null;
|
|
943
969
|
parent_id: string | null;
|
|
970
|
+
group_id?: string | undefined;
|
|
944
971
|
name: string;
|
|
945
972
|
image_url?: string | undefined;
|
|
946
973
|
menu_id?: string | undefined;
|
|
@@ -1570,6 +1597,10 @@ interface CheckoutSection {
|
|
|
1570
1597
|
interface CheckoutPreferences {
|
|
1571
1598
|
shipping: CheckoutSection;
|
|
1572
1599
|
billing: CheckoutSection;
|
|
1600
|
+
/** Missing on orders stamped before the setting existed → defaults. */
|
|
1601
|
+
anonymous_customer?: {
|
|
1602
|
+
fields: Record<string, CheckoutMode>;
|
|
1603
|
+
};
|
|
1573
1604
|
}
|
|
1574
1605
|
declare const isCheckoutFieldFilled: (info: Record<string, unknown> | null | undefined, key: string) => boolean;
|
|
1575
1606
|
interface CheckoutOrderInput {
|
|
@@ -1674,4 +1705,4 @@ declare const validateCardholderName: (value: string) => CardholderNameError | n
|
|
|
1674
1705
|
*/
|
|
1675
1706
|
declare const cardPreviewGroups: (value: string) => CardPreviewSlot[][];
|
|
1676
1707
|
//#endregion
|
|
1677
|
-
export { type ApplyRedeemInput, type AuthConfigureOptions, CARD_BRANDS, type CardBrand, type CardBrandSpec, type CardCvcError, type CardExpiry, type CardExpiryError, type CardNumberError, type CardPreviewSlot, type CardholderNameError, type CreateOrderOptions, type CreateSessionOptions, type CustomizationPath, type CustomizationSession, DEFAULT_RECOMMENDATION_TYPES, type DeunaCallbackUrls, type DeunaOrderStatus, type ExchangeOptions, type FailedCharge, type FlatMenuCategory, type GenOrderIdOptions, type GroupDisplayType, ID_HASH_FORMATS, type IdBuilder, type IdHashFormat, type ListMenusStreamOptions, type ListPaymentsOptions, type Menu, type MenuCategoryNode, type MenuLookup, type MilestoneSteps, type MilestoneTrackItem, type ModifierControlType, type ModifierCtx, type ModifierGroupCtx, type NestedMenuCategory, Order, type OrderCancelInput, type OrderCancelOptions, type OrderCancelResult, type OrderCancelType, type OrderCustomerSource, type OrderDeviceCredential, type OrderDraft, type OrderIssue, type OrderIssueCode, type OrderLineDiff, type OrderLineIssue, type OrderLineIssueCode, OrderPaymentRequiredError, type OrderScope, OrderSyncPendingError, OrderSyncRejectedError, OrderValidationError, type OrderValidationResult, type PayIntentOptions, type PayIntentResult, type PayOptions, type PaymentCardBrand, type PaymentProgressEvent, type PaymentProgressListener, type PaymentRunOptions, type PaymentSessionOptions, type PricingModifier, type Product, type ProductCtx, type QuantitiesByPath, type RecommendationType, RecurringDateCron, type RedeemPaymentRow, type RemoveRedeemInput, type ReorderOrderOptions, type ResetOptions, type ReversalOutcome, type ReverseAllOptions, RulesEngine, type ScheduleWindow, type SelectionStatus, type SelectionsByPath, type SerializedError, type ServiceHttpOptions, type SimpleTenderPayment, type Snapshot, type StorefrontAccessToken, type StorefrontErrorDetails, StorefrontHttpError, type TrackWorkflow, type ValidateOptions, type ValidateOrderAgainstMenuInput, type Variant, type VariantGroup, type VariantGroupCtx, type VariantOptionCtx, type VariantSelection, type VerifyWebhookSignatureInput, type VisitedState, addLines, auth, buildCustomerSnapshot, cancelTypeOf, capRedeems, cappedRedeems, cardBrandSpec, cardDigits, cardNumberGaps, cardNumberMaxLength, cardPreviewGroups, caretAfterDigits, collectOrderLineDiffs, computeStartingPrice, countCartProducts, coveredAmount, createDeunaWidgetApi, createSession, currentNodes, cvcMaxLength, defaultConditionError, detectCardBrand, fitRedeems, flattenMenuCategories, flushLogs, formatCardNumber, formatCvc, formatExpiry, fromOrderLines, genId, genOrderId, getLogContext, getScheduleWindow, indexMenu, isCardNumberComplete, isCardNumberDefinitelyInvalid, isCheckoutFieldFilled, isCvcComplete, isDeviceCharged, isDeviceNotLinked, isExpiryComplete, isGenId, isKioskUnauthorized, isMilestoneStepDone, isOnSchedule, isOrderPaymentRequiredError, isOrderValidationError, isPosDeviceNotLinked, isPosUnauthorized, isRealPaymentMethod, isStorefrontNotFound, isVariantBase, linePayableTotal, listMenusStream, localizePosError, log, logError, luhnCheck, matchAbsoluteDateOperator, matchBooleanOperator, matchCurrencyOperator, matchEnumOperator, matchNumberOperator, matchRecurringDateOperator, matchRelativeDateOperator, matchStringOperator, milestoneSteps, milestoneTrack, nestMenuCategories, normalizeCardholderName, orderPayableTotal, orderRedeemedTotal, orderRedeems, parseExpiry, paymentMatchesClientConditions, rebuildRootGroups, recomputeTotals, redeemedTotal, redemptionCap, redemptionSteps, remainingAmount, removeLine, replaceLine, resolveCheckout, resolveModifierImageUrl, reversePayment, runPaymentAttempt, selectablePayments, serializeError, services, setLineQuantity, storefrontJson, toOrderLines, toPaymentCardBrand, validateCardNumber, validateCardholderName, validateCvc, validateExpiry, validateOrderAgainstMenu, verifyWebhookSignature, visitedStates };
|
|
1708
|
+
export { type ApplyRedeemInput, type AuthConfigureOptions, CARD_BRANDS, CUSTOMER_INFO_PLACEHOLDERS, type CardBrand, type CardBrandSpec, type CardCvcError, type CardExpiry, type CardExpiryError, type CardNumberError, type CardPreviewSlot, type CardholderNameError, type CreateOrderOptions, type CreateSessionOptions, type CustomizationPath, type CustomizationSession, DEFAULT_RECOMMENDATION_TYPES, type DeunaCallbackUrls, type DeunaOrderStatus, type ExchangeOptions, type FailedCharge, type FlatMenuCategory, type GenOrderIdOptions, type GroupDisplayType, ID_HASH_FORMATS, type IdBuilder, type IdHashFormat, type ListMenusStreamOptions, type ListPaymentsOptions, type Menu, type MenuCategoryNode, type MenuLookup, type MilestoneSteps, type MilestoneTrackItem, type ModifierControlType, type ModifierCtx, type ModifierGroupCtx, type NestedMenuCategory, Order, type OrderCancelInput, type OrderCancelOptions, type OrderCancelResult, type OrderCancelType, type OrderCustomerSource, type OrderDeviceCredential, type OrderDraft, type OrderIssue, type OrderIssueCode, type OrderLineDiff, type OrderLineIssue, type OrderLineIssueCode, OrderPaymentRequiredError, type OrderScope, OrderSyncPendingError, OrderSyncRejectedError, OrderValidationError, type OrderValidationResult, type PayIntentOptions, type PayIntentResult, type PayOptions, type PaymentCardBrand, type PaymentProgressEvent, type PaymentProgressListener, type PaymentRunOptions, type PaymentSessionOptions, type PricingModifier, type Product, type ProductCtx, type QuantitiesByPath, type RecommendationType, RecurringDateCron, type RedeemPaymentRow, type RemoveRedeemInput, type ReorderOrderOptions, type ResetOptions, type ReversalOutcome, type ReverseAllOptions, RulesEngine, type ScheduleWindow, type SelectionStatus, type SelectionsByPath, type SerializedError, type ServiceHttpOptions, type SimpleTenderPayment, type Snapshot, type StorefrontAccessToken, type StorefrontErrorDetails, StorefrontHttpError, type TrackWorkflow, type ValidateOptions, type ValidateOrderAgainstMenuInput, type Variant, type VariantGroup, type VariantGroupCtx, type VariantOptionCtx, type VariantSelection, type VerifyWebhookSignatureInput, type VisitedState, addLines, auth, buildCustomerSnapshot, cancelTypeOf, capRedeems, cappedRedeems, cardBrandSpec, cardDigits, cardNumberGaps, cardNumberMaxLength, cardPreviewGroups, caretAfterDigits, collectOrderLineDiffs, computeStartingPrice, countCartProducts, coveredAmount, createDeunaWidgetApi, createSession, currentNodes, cvcMaxLength, defaultConditionError, detectCardBrand, fitRedeems, flattenMenuCategories, flushLogs, formatCardNumber, formatCvc, formatExpiry, fromOrderLines, genId, genOrderId, getLogContext, getScheduleWindow, indexMenu, isCardNumberComplete, isCardNumberDefinitelyInvalid, isCheckoutFieldFilled, isCustomerInfoFieldFilled, isCustomerInfoPlaceholder, isCustomerInfoValueValid, isCvcComplete, isDeviceCharged, isDeviceNotLinked, isExpiryComplete, isGenId, isKioskUnauthorized, isMilestoneStepDone, isOnSchedule, isOrderPaymentRequiredError, isOrderValidationError, isPosDeviceNotLinked, isPosUnauthorized, isRealPaymentMethod, isStorefrontNotFound, isVariantBase, linePayableTotal, listMenusStream, localizePosError, log, logError, luhnCheck, matchAbsoluteDateOperator, matchBooleanOperator, matchCurrencyOperator, matchEnumOperator, matchNumberOperator, matchRecurringDateOperator, matchRelativeDateOperator, matchStringOperator, milestoneSteps, milestoneTrack, nestMenuCategories, normalizeCardholderName, normalizeCustomerPhone, orderPayableTotal, orderRedeemedTotal, orderRedeems, parseExpiry, paymentMatchesClientConditions, rebuildRootGroups, recomputeTotals, redeemedTotal, redemptionCap, redemptionSteps, remainingAmount, removeLine, replaceLine, resolveCheckout, resolveModifierImageUrl, reversePayment, runPaymentAttempt, selectablePayments, serializeError, services, setLineQuantity, storefrontJson, toOrderLines, toPaymentCardBrand, validateCardNumber, validateCardholderName, validateCvc, validateExpiry, validateOrderAgainstMenu, verifyWebhookSignature, visitedStates };
|
package/dist/index.js
CHANGED
|
@@ -1415,9 +1415,11 @@ const flattenMenuCategories = (categories, categoriesById, options) => {
|
|
|
1415
1415
|
//#endregion
|
|
1416
1416
|
//#region src/productCustomization/fromOrderLines.ts
|
|
1417
1417
|
/** Group slot of a child line: listed directly, or as the variant of a base
|
|
1418
|
-
* listed in one of the parent's modifier groups.
|
|
1419
|
-
|
|
1418
|
+
* listed in one of the parent's modifier groups. With `onlyGroupId` (the
|
|
1419
|
+
* line's declared `group_id`) only that group of this parent is searched. */
|
|
1420
|
+
const matchModifierLine = (lookup, parent, childId, onlyGroupId) => {
|
|
1420
1421
|
const groups = parent.pricing.modifier_group_ids.flatMap((groupId) => {
|
|
1422
|
+
if (onlyGroupId !== void 0 && groupId !== onlyGroupId) return [];
|
|
1421
1423
|
const group = lookup.modifierGroupsById[groupId];
|
|
1422
1424
|
return group ? [group] : [];
|
|
1423
1425
|
});
|
|
@@ -1463,7 +1465,13 @@ const fromOrderLines = (root, lines, lookup) => {
|
|
|
1463
1465
|
const parentProduct = lookup.productsById[parentLine.id];
|
|
1464
1466
|
if (!parentProduct) return;
|
|
1465
1467
|
for (const child of childrenByParent.get(parentLine.uid) ?? []) {
|
|
1466
|
-
const
|
|
1468
|
+
const p = [
|
|
1469
|
+
lookup,
|
|
1470
|
+
parentProduct,
|
|
1471
|
+
child.id,
|
|
1472
|
+
child.group_id
|
|
1473
|
+
];
|
|
1474
|
+
const match = matchModifierLine(...p);
|
|
1467
1475
|
if (!match) continue;
|
|
1468
1476
|
const { groupId, modifierId, selection } = match;
|
|
1469
1477
|
const path = `${pathPrefix}/group/${groupId}/modifier/${modifierId}`;
|
|
@@ -1750,6 +1758,7 @@ const buildLine = (args) => {
|
|
|
1750
1758
|
name: args.name
|
|
1751
1759
|
};
|
|
1752
1760
|
const r4 = {
|
|
1761
|
+
...args.group_id ? { group_id: args.group_id } : {},
|
|
1753
1762
|
...imagePatch,
|
|
1754
1763
|
...catalog
|
|
1755
1764
|
};
|
|
@@ -1835,7 +1844,8 @@ const appendModifierLine = (modifier, groupId, parent, locale) => {
|
|
|
1835
1844
|
const line = buildLine({
|
|
1836
1845
|
...l1,
|
|
1837
1846
|
...l2,
|
|
1838
|
-
...l3
|
|
1847
|
+
...l3,
|
|
1848
|
+
group_id: groupId
|
|
1839
1849
|
});
|
|
1840
1850
|
parent.children.push(line);
|
|
1841
1851
|
if (modifier.product) appendGroupLines(modifier.product.groups, line, locale);
|
|
@@ -1955,6 +1965,15 @@ const auth = {
|
|
|
1955
1965
|
};
|
|
1956
1966
|
//#endregion
|
|
1957
1967
|
//#region src/order/customer.ts
|
|
1968
|
+
/**
|
|
1969
|
+
* Stand-ins the order schema needs while a guest's contact data is unknown.
|
|
1970
|
+
* Only valid when the merchant's `anonymous_customer` field is optional or
|
|
1971
|
+
* hidden; the API rejects them on required fields (`CUSTOMER_FIELD_REQUIRED`).
|
|
1972
|
+
*/
|
|
1973
|
+
const CUSTOMER_INFO_PLACEHOLDERS = {
|
|
1974
|
+
email: "unknown@example.com",
|
|
1975
|
+
phone: "+10000000000"
|
|
1976
|
+
};
|
|
1958
1977
|
const splitName = (name) => {
|
|
1959
1978
|
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
1960
1979
|
const first_name = parts[0] ?? name;
|
|
@@ -1967,14 +1986,108 @@ const splitName = (name) => {
|
|
|
1967
1986
|
/** Builds the order `customer` snapshot sent on create/update. */
|
|
1968
1987
|
const buildCustomerSnapshot = (source) => {
|
|
1969
1988
|
const names = splitName(source.name);
|
|
1989
|
+
const email = source.email || CUSTOMER_INFO_PLACEHOLDERS.email;
|
|
1990
|
+
const phone = source.phone || CUSTOMER_INFO_PLACEHOLDERS.phone;
|
|
1970
1991
|
return { customer_info: {
|
|
1971
1992
|
display_name: names.display_name,
|
|
1972
1993
|
first_name: names.first_name,
|
|
1973
1994
|
last_name: names.last_name,
|
|
1974
|
-
email
|
|
1975
|
-
phone
|
|
1995
|
+
email,
|
|
1996
|
+
phone
|
|
1976
1997
|
} };
|
|
1977
1998
|
};
|
|
1999
|
+
/**
|
|
2000
|
+
* True when `value` is a stand-in, not data the guest typed: the
|
|
2001
|
+
* placeholders above, or a name equal to the anonymous customer id.
|
|
2002
|
+
*/
|
|
2003
|
+
const isCustomerInfoPlaceholder = (key, value, customerId) => {
|
|
2004
|
+
if (typeof value !== "string") return false;
|
|
2005
|
+
const text = value.trim();
|
|
2006
|
+
if (key === "email") return text === CUSTOMER_INFO_PLACEHOLDERS.email;
|
|
2007
|
+
if (key === "phone") return text === CUSTOMER_INFO_PLACEHOLDERS.phone;
|
|
2008
|
+
if ((key === "first_name" || key === "last_name") && customerId) return text === customerId;
|
|
2009
|
+
return false;
|
|
2010
|
+
};
|
|
2011
|
+
/** A `customer_info` field holds real (non-placeholder) guest data. */
|
|
2012
|
+
const isCustomerInfoFieldFilled = (info, key, customerId) => {
|
|
2013
|
+
let value = info?.[key];
|
|
2014
|
+
const metadata = info?.metadata;
|
|
2015
|
+
if (value == null && metadata && typeof metadata === "object" && !Array.isArray(metadata)) value = metadata[key];
|
|
2016
|
+
if (value == null) return false;
|
|
2017
|
+
if (typeof value === "string" && !value.trim()) return false;
|
|
2018
|
+
return !isCustomerInfoPlaceholder(key, value, customerId);
|
|
2019
|
+
};
|
|
2020
|
+
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2021
|
+
const PHONE_RE = /^\+[1-9]\d{1,14}$/;
|
|
2022
|
+
/** Strips spaces, dashes, dots and parentheses: "+593 99-123" → "+59399123". */
|
|
2023
|
+
const normalizeCustomerPhone = (value) => {
|
|
2024
|
+
return value.trim().replace(/[\s\-().]/g, "");
|
|
2025
|
+
};
|
|
2026
|
+
/**
|
|
2027
|
+
* Format check the order schema enforces on `customer_info`: email shape and
|
|
2028
|
+
* E.164 phone (`+593991234567`). Empty values are valid (presence is checked
|
|
2029
|
+
* against the merchant's `anonymous_customer` modes instead).
|
|
2030
|
+
*/
|
|
2031
|
+
const isCustomerInfoValueValid = (key, value) => {
|
|
2032
|
+
const text = value.trim();
|
|
2033
|
+
if (!text) return true;
|
|
2034
|
+
if (key === "email") return EMAIL_RE.test(text);
|
|
2035
|
+
if (key === "phone") return PHONE_RE.test(normalizeCustomerPhone(text));
|
|
2036
|
+
return text.length <= 100;
|
|
2037
|
+
};
|
|
2038
|
+
/**
|
|
2039
|
+
* Merges guest contact data into `customer_info`; empty or malformed values
|
|
2040
|
+
* fall back to the current snapshot (placeholders for optional/hidden fields)
|
|
2041
|
+
* so a half-typed field never breaks the order sync.
|
|
2042
|
+
*/
|
|
2043
|
+
const mergeCustomerInfo = (current, patch) => {
|
|
2044
|
+
const clean = (value, key = "") => {
|
|
2045
|
+
let text = value?.trim();
|
|
2046
|
+
if (text && key === "phone") text = normalizeCustomerPhone(text);
|
|
2047
|
+
if (!text || !isCustomerInfoValueValid(key, text)) return void 0;
|
|
2048
|
+
return text;
|
|
2049
|
+
};
|
|
2050
|
+
const first_name = clean(patch.first_name) ?? current.first_name;
|
|
2051
|
+
const last_name = clean(patch.last_name) ?? current.last_name;
|
|
2052
|
+
const email = clean(patch.email, "email") ?? current.email;
|
|
2053
|
+
const phone = clean(patch.phone, "phone") ?? current.phone;
|
|
2054
|
+
const typedName = clean(patch.first_name) || clean(patch.last_name);
|
|
2055
|
+
let display_name = current.display_name;
|
|
2056
|
+
if (typedName) display_name = `${first_name} ${last_name}`.trim();
|
|
2057
|
+
const b1 = {
|
|
2058
|
+
display_name,
|
|
2059
|
+
first_name,
|
|
2060
|
+
last_name,
|
|
2061
|
+
email,
|
|
2062
|
+
phone
|
|
2063
|
+
};
|
|
2064
|
+
if (!patch.metadata) return {
|
|
2065
|
+
...current,
|
|
2066
|
+
...b1
|
|
2067
|
+
};
|
|
2068
|
+
const metadata = mergeCustomMetadata(current.metadata, patch.metadata);
|
|
2069
|
+
const { metadata: _drop, ...rest } = current;
|
|
2070
|
+
if (metadata === void 0) return {
|
|
2071
|
+
...rest,
|
|
2072
|
+
...b1
|
|
2073
|
+
};
|
|
2074
|
+
return {
|
|
2075
|
+
...rest,
|
|
2076
|
+
...b1,
|
|
2077
|
+
metadata
|
|
2078
|
+
};
|
|
2079
|
+
};
|
|
2080
|
+
/** Custom guest fields: non-empty text is set, blanks remove the key. */
|
|
2081
|
+
const mergeCustomMetadata = (current, patch) => {
|
|
2082
|
+
const next = { ...current };
|
|
2083
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
2084
|
+
const text = typeof value === "string" ? value.trim() : value;
|
|
2085
|
+
const valid = typeof text !== "string" || isCustomerInfoValueValid(key, text);
|
|
2086
|
+
if (text == null || text === "" || !valid) delete next[key];
|
|
2087
|
+
else next[key] = text;
|
|
2088
|
+
}
|
|
2089
|
+
return Object.keys(next).length > 0 ? next : void 0;
|
|
2090
|
+
};
|
|
1978
2091
|
//#endregion
|
|
1979
2092
|
//#region src/logs/limits.ts
|
|
1980
2093
|
/** Mirrors the API limits so oversized logs are trimmed, not rejected. */
|
|
@@ -3687,7 +3800,8 @@ const computeLineFingerprint = (root, lines) => {
|
|
|
3687
3800
|
const keys = lines.filter((line) => {
|
|
3688
3801
|
return line.parent_uid === parentUid;
|
|
3689
3802
|
}).map((line) => {
|
|
3690
|
-
|
|
3803
|
+
const slot = line.group_id ? `@${line.group_id}` : "";
|
|
3804
|
+
return `${line.id}${slot}x${line.quantity}(${childKeys(line.uid)})`;
|
|
3691
3805
|
});
|
|
3692
3806
|
keys.sort((left, right) => left.localeCompare(right));
|
|
3693
3807
|
return keys.join(",");
|
|
@@ -6000,15 +6114,21 @@ var Order = class Order {
|
|
|
6000
6114
|
}
|
|
6001
6115
|
setCustomerDetails(details) {
|
|
6002
6116
|
if (this.deleted) return;
|
|
6117
|
+
let customer_info = this.draft.customer.customer_info;
|
|
6118
|
+
if (details.customer_info) customer_info = mergeCustomerInfo(customer_info, details.customer_info);
|
|
6003
6119
|
const hasAddressInfo = details.address_info !== void 0;
|
|
6004
6120
|
const hasBillingInfo = details.billing_info !== void 0;
|
|
6005
6121
|
const address_info = !hasAddressInfo ? this.draft.customer.address_info : details.address_info;
|
|
6006
6122
|
const billing_info = !hasBillingInfo ? this.draft.customer.billing_info : details.billing_info;
|
|
6007
|
-
const
|
|
6008
|
-
|
|
6123
|
+
const c1 = {
|
|
6124
|
+
customer_info,
|
|
6009
6125
|
address_info,
|
|
6010
6126
|
billing_info
|
|
6011
6127
|
};
|
|
6128
|
+
const customer = {
|
|
6129
|
+
...this.draft.customer,
|
|
6130
|
+
...c1
|
|
6131
|
+
};
|
|
6012
6132
|
this.draft = {
|
|
6013
6133
|
...this.draft,
|
|
6014
6134
|
customer
|
|
@@ -6643,7 +6763,8 @@ const selectionKey = (line, kidsOf, cache) => {
|
|
|
6643
6763
|
return selectionKey(child, kidsOf, cache);
|
|
6644
6764
|
});
|
|
6645
6765
|
nested.sort((left, right) => left.localeCompare(right));
|
|
6646
|
-
const
|
|
6766
|
+
const slot = line.group_id ? `@${line.group_id}` : "";
|
|
6767
|
+
const key = `${line.id}${slot}x${line.quantity}(${nested.join(",")})`;
|
|
6647
6768
|
cache.set(line.uid, key);
|
|
6648
6769
|
return key;
|
|
6649
6770
|
};
|
|
@@ -6730,6 +6851,36 @@ const hasRepeatedProductSibling = (lines, rootUid) => {
|
|
|
6730
6851
|
};
|
|
6731
6852
|
return walk(rootUid);
|
|
6732
6853
|
};
|
|
6854
|
+
/** A line whose product the parent's menu lists in more than one slot, at
|
|
6855
|
+
* any depth. Cart lines carry no group id, so the slot is chosen by
|
|
6856
|
+
* `placeCartLines`; with a single listing the session path is unambiguous. */
|
|
6857
|
+
const hasMultiSlotChild = (lines, rootUid, lookup) => {
|
|
6858
|
+
const kidsOf = /* @__PURE__ */ new Map();
|
|
6859
|
+
for (const line of lines) {
|
|
6860
|
+
if (line.parent_uid == null) continue;
|
|
6861
|
+
const list = kidsOf.get(line.parent_uid) ?? [];
|
|
6862
|
+
list.push(line);
|
|
6863
|
+
kidsOf.set(line.parent_uid, list);
|
|
6864
|
+
}
|
|
6865
|
+
const walk = (line) => {
|
|
6866
|
+
const parent = lookup.productsById[line.id];
|
|
6867
|
+
const groups = parent ? parentGroups(lookup, parent) : [];
|
|
6868
|
+
for (const kid of kidsOf.get(line.uid) ?? []) {
|
|
6869
|
+
const ids = listingsFor(lookup, groups, kid.id).map((row) => slotKey(row.group.id, row.modifierId));
|
|
6870
|
+
if (new Set(ids).size > 1) return true;
|
|
6871
|
+
if (walk(kid)) return true;
|
|
6872
|
+
}
|
|
6873
|
+
return false;
|
|
6874
|
+
};
|
|
6875
|
+
const root = lines.find((line) => line.uid === rootUid);
|
|
6876
|
+
return root ? walk(root) : false;
|
|
6877
|
+
};
|
|
6878
|
+
/** Cart shapes the slot search must place: a repeated sibling product, or
|
|
6879
|
+
* a product listed in several slots. Everything else keeps the session. */
|
|
6880
|
+
const needsSlotPlacement = (lines, rootUid, lookup) => {
|
|
6881
|
+
if (hasRepeatedProductSibling(lines, rootUid)) return true;
|
|
6882
|
+
return hasMultiSlotChild(lines, rootUid, lookup);
|
|
6883
|
+
};
|
|
6733
6884
|
const noteRules = (state, broken) => {
|
|
6734
6885
|
if (broken) state.rulesBroken = true;
|
|
6735
6886
|
};
|
|
@@ -6897,13 +7048,21 @@ const greedyAssignment = (plans) => {
|
|
|
6897
7048
|
overCapacity
|
|
6898
7049
|
};
|
|
6899
7050
|
};
|
|
7051
|
+
/** The groups a line may sit in under this parent: only its declared
|
|
7052
|
+
* `group_id` when it names one, else every group of the parent. A declared id
|
|
7053
|
+
* the parent does not own leaves none, so the line is never placed. */
|
|
7054
|
+
const groupsDeclared = (groups, line) => {
|
|
7055
|
+
if (line.group_id === void 0) return groups;
|
|
7056
|
+
return groups.filter((group) => group.id === line.group_id);
|
|
7057
|
+
};
|
|
6900
7058
|
const planKids = (lookup, groups, byKey, kids, prefix, state) => {
|
|
6901
7059
|
const plans = [];
|
|
6902
7060
|
let previous = "";
|
|
6903
7061
|
for (const child of kids) {
|
|
6904
7062
|
if (pathVisits(prefix, child.id)) continue;
|
|
6905
7063
|
const ordered = lookup.productsById[child.id];
|
|
6906
|
-
const
|
|
7064
|
+
const scope = groupsDeclared(groups, child);
|
|
7065
|
+
const listings = listingsFor(lookup, scope, child.id);
|
|
6907
7066
|
if (!ordered || listings.length === 0) continue;
|
|
6908
7067
|
const listed = [];
|
|
6909
7068
|
for (const item of listings) {
|
|
@@ -7123,14 +7282,17 @@ const emit = (node, parentUid, parentId, locale, out) => {
|
|
|
7123
7282
|
type: "PRODUCT",
|
|
7124
7283
|
uid: randomUUID()
|
|
7125
7284
|
};
|
|
7285
|
+
const id = node.product.id;
|
|
7286
|
+
const groupPatch = node.group ? { group_id: node.group.id } : {};
|
|
7126
7287
|
const r2 = {
|
|
7127
|
-
id
|
|
7288
|
+
id,
|
|
7128
7289
|
parent_uid: parentUid,
|
|
7129
7290
|
parent_id: parentId
|
|
7130
7291
|
};
|
|
7131
7292
|
const r3 = {
|
|
7132
7293
|
name: displayName(node.product.name, locale),
|
|
7133
|
-
quantity: node.quantity
|
|
7294
|
+
quantity: node.quantity,
|
|
7295
|
+
...groupPatch
|
|
7134
7296
|
};
|
|
7135
7297
|
const r4 = {
|
|
7136
7298
|
redeem: [],
|
|
@@ -7321,10 +7483,25 @@ const childrenOf = (lines, parentUid) => {
|
|
|
7321
7483
|
if (byShape !== 0) return byShape;
|
|
7322
7484
|
const bySubtotal = new Big(a.unit_subtotal).cmp(b.unit_subtotal);
|
|
7323
7485
|
if (bySubtotal !== 0) return bySubtotal;
|
|
7324
|
-
|
|
7486
|
+
const byTax = new Big(a.unit_tax_total).cmp(b.unit_tax_total);
|
|
7487
|
+
if (byTax !== 0) return byTax;
|
|
7488
|
+
return (a.group_id ?? "").localeCompare(b.group_id ?? "");
|
|
7325
7489
|
});
|
|
7326
7490
|
return children;
|
|
7327
7491
|
};
|
|
7492
|
+
/** A declared `group_id` that the parent's menu does not back (unknown under
|
|
7493
|
+
* this parent, or it does not hold the product) names the field; a line that
|
|
7494
|
+
* is no modifier of its parent at all keeps the plain code. */
|
|
7495
|
+
const notFoundIssue = (lookup, parent, child) => {
|
|
7496
|
+
const code = "MODIFIER_NOT_FOUND";
|
|
7497
|
+
if (child.group_id === void 0) return { code };
|
|
7498
|
+
if (!matchModifierLine(lookup, parent, child.id)) return { code };
|
|
7499
|
+
return {
|
|
7500
|
+
code,
|
|
7501
|
+
field: "group_id",
|
|
7502
|
+
actual: child.group_id
|
|
7503
|
+
};
|
|
7504
|
+
};
|
|
7328
7505
|
const collectUnmatchedModifiers = (lines, lookup, parentProductId, parentUid, out) => {
|
|
7329
7506
|
const parent = lookup.productsById[parentProductId];
|
|
7330
7507
|
if (!parent) return;
|
|
@@ -7336,9 +7513,14 @@ const collectUnmatchedModifiers = (lines, lookup, parentProductId, parentUid, ou
|
|
|
7336
7513
|
pushLineIssue(out, child.uid, { code: "VARIANT_BASE_NOT_ORDERABLE" });
|
|
7337
7514
|
continue;
|
|
7338
7515
|
}
|
|
7339
|
-
const match = matchModifierLine(
|
|
7516
|
+
const match = matchModifierLine(...[
|
|
7517
|
+
lookup,
|
|
7518
|
+
parent,
|
|
7519
|
+
child.id,
|
|
7520
|
+
child.group_id
|
|
7521
|
+
]);
|
|
7340
7522
|
if (!match) {
|
|
7341
|
-
pushLineIssue(out, child.uid,
|
|
7523
|
+
pushLineIssue(out, child.uid, notFoundIssue(lookup, parent, child));
|
|
7342
7524
|
continue;
|
|
7343
7525
|
}
|
|
7344
7526
|
const base = lookup.productsById[match.modifierId];
|
|
@@ -7481,6 +7663,13 @@ const compareTrees = (actualLines, expectedLines, actualUid, expectedUid, out) =
|
|
|
7481
7663
|
});
|
|
7482
7664
|
return;
|
|
7483
7665
|
}
|
|
7666
|
+
const declared = actual.group_id;
|
|
7667
|
+
if (declared !== void 0 && declared !== expected.group_id) pushLineIssue(out, actual.uid, {
|
|
7668
|
+
code: "STRUCTURE_MISMATCH",
|
|
7669
|
+
field: "group_id",
|
|
7670
|
+
expected: expected.group_id,
|
|
7671
|
+
actual: declared
|
|
7672
|
+
});
|
|
7484
7673
|
if (actual.quantity !== expected.quantity) pushLineIssue(out, actual.uid, {
|
|
7485
7674
|
code: "QUANTITY_MISMATCH",
|
|
7486
7675
|
field: "quantity",
|
|
@@ -7566,7 +7755,7 @@ const validateProductRoot = (root, lines, lookup, locale, out) => {
|
|
|
7566
7755
|
if (!isOnSchedule(product.availability.schedules)) pushLineIssue(out, root.uid, { code: "OUTSIDE_HOURS" });
|
|
7567
7756
|
collectUnmatchedModifiers(lines, lookup, root.id, root.uid, out);
|
|
7568
7757
|
let expected;
|
|
7569
|
-
if (
|
|
7758
|
+
if (needsSlotPlacement(lines, root.uid, lookup)) {
|
|
7570
7759
|
const placed = placeCartLines(root, lines, lookup, locale);
|
|
7571
7760
|
if (placed.rulesBroken) pushLineIssue(out, root.uid, { code: "MODIFIER_RULES_INVALID" });
|
|
7572
7761
|
expected = placed.lines;
|
|
@@ -7898,7 +8087,7 @@ const collectOrderLineDiffs = (input) => {
|
|
|
7898
8087
|
continue;
|
|
7899
8088
|
}
|
|
7900
8089
|
try {
|
|
7901
|
-
if (
|
|
8090
|
+
if (needsSlotPlacement(input.lines, root.uid, lookup)) {
|
|
7902
8091
|
const placed = placeCartLines(root, input.lines, lookup, locale);
|
|
7903
8092
|
const next = placed.rulesBroken ? null : placed.lines;
|
|
7904
8093
|
diffs.push({
|
|
@@ -9452,6 +9641,13 @@ const DEFAULT_BILLING_FIELDS = {
|
|
|
9452
9641
|
tax_id: "required",
|
|
9453
9642
|
tax_id_type: "required"
|
|
9454
9643
|
};
|
|
9644
|
+
/** Guest contact fields → `customer.customer_info` (anonymous orders). */
|
|
9645
|
+
const DEFAULT_CUSTOMER_FIELDS = {
|
|
9646
|
+
email: "required",
|
|
9647
|
+
first_name: "required",
|
|
9648
|
+
last_name: "required",
|
|
9649
|
+
phone: "required"
|
|
9650
|
+
};
|
|
9455
9651
|
const getCheckoutFieldValue = (info, key) => {
|
|
9456
9652
|
if (!info) return void 0;
|
|
9457
9653
|
const top = info[key];
|
|
@@ -9481,7 +9677,8 @@ const defaultCheckoutPreferences = {
|
|
|
9481
9677
|
billing: {
|
|
9482
9678
|
fields: DEFAULT_BILLING_FIELDS,
|
|
9483
9679
|
rules: [fallbackRequired]
|
|
9484
|
-
}
|
|
9680
|
+
},
|
|
9681
|
+
anonymous_customer: { fields: DEFAULT_CUSTOMER_FIELDS }
|
|
9485
9682
|
};
|
|
9486
9683
|
const factsFromOrder = (order) => {
|
|
9487
9684
|
const brand_id = order.brand_id ?? void 0;
|
|
@@ -9536,13 +9733,15 @@ const resolveCheckout = (order, options) => {
|
|
|
9536
9733
|
let shipping = "hidden";
|
|
9537
9734
|
if (ships) shipping = resolveSection(checkout.shipping, engine);
|
|
9538
9735
|
const billing = resolveSection(checkout.billing, engine);
|
|
9539
|
-
const
|
|
9540
|
-
|
|
9736
|
+
const f1 = {
|
|
9737
|
+
shippingFields: checkout.shipping.fields ?? DEFAULT_SHIPPING_FIELDS,
|
|
9738
|
+
billingFields: checkout.billing.fields ?? DEFAULT_BILLING_FIELDS,
|
|
9739
|
+
customerFields: checkout.anonymous_customer?.fields ?? DEFAULT_CUSTOMER_FIELDS
|
|
9740
|
+
};
|
|
9541
9741
|
return {
|
|
9542
9742
|
shipping,
|
|
9543
9743
|
billing,
|
|
9544
|
-
|
|
9545
|
-
billingFields
|
|
9744
|
+
...f1
|
|
9546
9745
|
};
|
|
9547
9746
|
};
|
|
9548
9747
|
//#endregion
|
|
@@ -9881,4 +10080,4 @@ const cardPreviewGroups = (value) => {
|
|
|
9881
10080
|
return groups;
|
|
9882
10081
|
};
|
|
9883
10082
|
//#endregion
|
|
9884
|
-
export { CARD_BRANDS, DEFAULT_RECOMMENDATION_TYPES, ID_HASH_FORMATS, Order, OrderPaymentRequiredError, OrderSyncPendingError, OrderSyncRejectedError, OrderValidationError, RecurringDateCron, RulesEngine, StorefrontHttpError, addLines, auth, buildCustomerSnapshot, cancelTypeOf, capRedeems, cappedRedeems, cardBrandSpec, cardDigits, cardNumberGaps, cardNumberMaxLength, cardPreviewGroups, caretAfterDigits, collectOrderLineDiffs, computeStartingPrice, countCartProducts, coveredAmount, createDeunaWidgetApi, createSession, currentNodes, cvcMaxLength, defaultConditionError, detectCardBrand, fitRedeems, flattenMenuCategories, flushLogs, formatCardNumber, formatCvc, formatExpiry, fromOrderLines, genId, genOrderId, getLogContext, getScheduleWindow, indexMenu, isCardNumberComplete, isCardNumberDefinitelyInvalid, isCheckoutFieldFilled, isCvcComplete, isDeviceCharged, isDeviceNotLinked, isExpiryComplete, isGenId, isKioskUnauthorized, isMilestoneStepDone, isOnSchedule, isOrderPaymentRequiredError, isOrderValidationError, isPosDeviceNotLinked, isPosUnauthorized, isRealPaymentMethod, isStorefrontNotFound, isVariantBase, linePayableTotal, listMenusStream, localizePosError, log, logError, luhnCheck, matchAbsoluteDateOperator, matchBooleanOperator, matchCurrencyOperator, matchEnumOperator, matchNumberOperator, matchRecurringDateOperator, matchRelativeDateOperator, matchStringOperator, milestoneSteps, milestoneTrack, nestMenuCategories, normalizeCardholderName, orderPayableTotal, orderRedeemedTotal, orderRedeems, parseExpiry, paymentMatchesClientConditions, rebuildRootGroups, recomputeTotals, redeemedTotal, redemptionCap, redemptionSteps, remainingAmount, removeLine, replaceLine, resolveCheckout, resolveModifierImageUrl, reversePayment, runPaymentAttempt, selectablePayments, serializeError, services, setLineQuantity, storefrontJson, toOrderLines, toPaymentCardBrand, validateCardNumber, validateCardholderName, validateCvc, validateExpiry, validateOrderAgainstMenu, verifyWebhookSignature, visitedStates };
|
|
10083
|
+
export { CARD_BRANDS, CUSTOMER_INFO_PLACEHOLDERS, DEFAULT_RECOMMENDATION_TYPES, ID_HASH_FORMATS, Order, OrderPaymentRequiredError, OrderSyncPendingError, OrderSyncRejectedError, OrderValidationError, RecurringDateCron, RulesEngine, StorefrontHttpError, addLines, auth, buildCustomerSnapshot, cancelTypeOf, capRedeems, cappedRedeems, cardBrandSpec, cardDigits, cardNumberGaps, cardNumberMaxLength, cardPreviewGroups, caretAfterDigits, collectOrderLineDiffs, computeStartingPrice, countCartProducts, coveredAmount, createDeunaWidgetApi, createSession, currentNodes, cvcMaxLength, defaultConditionError, detectCardBrand, fitRedeems, flattenMenuCategories, flushLogs, formatCardNumber, formatCvc, formatExpiry, fromOrderLines, genId, genOrderId, getLogContext, getScheduleWindow, indexMenu, isCardNumberComplete, isCardNumberDefinitelyInvalid, isCheckoutFieldFilled, isCustomerInfoFieldFilled, isCustomerInfoPlaceholder, isCustomerInfoValueValid, isCvcComplete, isDeviceCharged, isDeviceNotLinked, isExpiryComplete, isGenId, isKioskUnauthorized, isMilestoneStepDone, isOnSchedule, isOrderPaymentRequiredError, isOrderValidationError, isPosDeviceNotLinked, isPosUnauthorized, isRealPaymentMethod, isStorefrontNotFound, isVariantBase, linePayableTotal, listMenusStream, localizePosError, log, logError, luhnCheck, matchAbsoluteDateOperator, matchBooleanOperator, matchCurrencyOperator, matchEnumOperator, matchNumberOperator, matchRecurringDateOperator, matchRelativeDateOperator, matchStringOperator, milestoneSteps, milestoneTrack, nestMenuCategories, normalizeCardholderName, normalizeCustomerPhone, orderPayableTotal, orderRedeemedTotal, orderRedeems, parseExpiry, paymentMatchesClientConditions, rebuildRootGroups, recomputeTotals, redeemedTotal, redemptionCap, redemptionSteps, remainingAmount, removeLine, replaceLine, resolveCheckout, resolveModifierImageUrl, reversePayment, runPaymentAttempt, selectablePayments, serializeError, services, setLineQuantity, storefrontJson, toOrderLines, toPaymentCardBrand, validateCardNumber, validateCardholderName, validateCvc, validateExpiry, validateOrderAgainstMenu, verifyWebhookSignature, visitedStates };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fire-spark/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Fire Spark headless SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"big.js": "6.2.1",
|
|
21
21
|
"dayjs": "1.11.9",
|
|
22
22
|
"@types/big.js": "6.2.2",
|
|
23
|
-
"@fire-spark/payments": "^0.
|
|
24
|
-
"@fire-spark/types": "^0.
|
|
23
|
+
"@fire-spark/payments": "^0.13.0",
|
|
24
|
+
"@fire-spark/types": "^0.13.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"tsdown": "^0.22.14",
|