@fayz-ai/shop 0.9.0 → 0.11.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/README.md +18 -1
- package/dist/admin.d.ts +2 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/catalog.d.ts +1 -3
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +2 -2
- package/dist/{chunk-IYQHKMLB.js → chunk-2WACO2TG.js} +4 -4
- package/dist/chunk-2WACO2TG.js.map +1 -0
- package/dist/chunk-3GERSY5F.js +526 -0
- package/dist/chunk-3GERSY5F.js.map +1 -0
- package/dist/chunk-6BO2TMZ5.js +93 -0
- package/dist/chunk-6BO2TMZ5.js.map +1 -0
- package/dist/chunk-FQPGE3YN.js +3 -0
- package/dist/{chunk-JR25TISO.js.map → chunk-FQPGE3YN.js.map} +1 -1
- package/dist/{chunk-CTKZ6O2J.js → chunk-IKNGCRUM.js} +41 -15
- package/dist/chunk-IKNGCRUM.js.map +1 -0
- package/dist/chunk-KLDS7IPU.js +17 -0
- package/dist/chunk-KLDS7IPU.js.map +1 -0
- package/dist/chunk-NWW3WJ7Y.js +136 -0
- package/dist/chunk-NWW3WJ7Y.js.map +1 -0
- package/dist/chunk-STRNMFC4.js +1438 -0
- package/dist/chunk-STRNMFC4.js.map +1 -0
- package/dist/chunk-U6HV3LVP.js +1170 -0
- package/dist/chunk-U6HV3LVP.js.map +1 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/data/customer-search.d.ts +3 -0
- package/dist/data/customer-search.d.ts.map +1 -0
- package/dist/data/functions.d.ts +9 -0
- package/dist/data/functions.d.ts.map +1 -0
- package/dist/data/media.d.ts +37 -0
- package/dist/data/media.d.ts.map +1 -0
- package/dist/{mock-catalog.d.ts → data/mock-catalog.d.ts} +21 -1
- package/dist/data/mock-catalog.d.ts.map +1 -0
- package/dist/data/mock-provider.d.ts +165 -0
- package/dist/data/mock-provider.d.ts.map +1 -0
- package/dist/data/mock.d.ts +3 -0
- package/dist/data/mock.d.ts.map +1 -0
- package/dist/data/provider.d.ts +335 -0
- package/dist/data/provider.d.ts.map +1 -0
- package/dist/data/supabase-provider.d.ts +208 -0
- package/dist/data/supabase-provider.d.ts.map +1 -0
- package/dist/data/tables.d.ts +38 -0
- package/dist/data/tables.d.ts.map +1 -0
- package/dist/data/tenant.d.ts.map +1 -0
- package/dist/entities/entity-reconcile.d.ts +32 -0
- package/dist/entities/entity-reconcile.d.ts.map +1 -0
- package/dist/entities/entity-sql.d.ts +50 -0
- package/dist/entities/entity-sql.d.ts.map +1 -0
- package/dist/entities/entity-store.d.ts +58 -0
- package/dist/entities/entity-store.d.ts.map +1 -0
- package/dist/entities/index.d.ts +10 -0
- package/dist/entities/index.d.ts.map +1 -0
- package/dist/entities/mock-entity-store.d.ts +17 -0
- package/dist/entities/mock-entity-store.d.ts.map +1 -0
- package/dist/entities/supabase-entity-store.d.ts +8 -0
- package/dist/entities/supabase-entity-store.d.ts.map +1 -0
- package/dist/entities.js +159 -0
- package/dist/entities.js.map +1 -0
- package/dist/index.d.ts +28 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1558 -40
- package/dist/index.js.map +1 -1
- package/dist/inventory/allocation.d.ts +98 -0
- package/dist/inventory/allocation.d.ts.map +1 -0
- package/dist/inventory/index.d.ts +13 -0
- package/dist/inventory/index.d.ts.map +1 -0
- package/dist/inventory/mock-stock-store.d.ts +89 -0
- package/dist/inventory/mock-stock-store.d.ts.map +1 -0
- package/dist/inventory/postgrest-double.d.ts +65 -0
- package/dist/inventory/postgrest-double.d.ts.map +1 -0
- package/dist/inventory/shopify-mapping.d.ts +67 -0
- package/dist/inventory/shopify-mapping.d.ts.map +1 -0
- package/dist/inventory/stock-contract.d.ts +46 -0
- package/dist/inventory/stock-contract.d.ts.map +1 -0
- package/dist/inventory/stock-store.d.ts +96 -0
- package/dist/inventory/stock-store.d.ts.map +1 -0
- package/dist/inventory/stock-types.d.ts +351 -0
- package/dist/inventory/stock-types.d.ts.map +1 -0
- package/dist/inventory/supabase-stock-store.d.ts +60 -0
- package/dist/inventory/supabase-stock-store.d.ts.map +1 -0
- package/dist/inventory/vocabulary.d.ts +86 -0
- package/dist/inventory/vocabulary.d.ts.map +1 -0
- package/dist/inventory.js +4 -0
- package/dist/inventory.js.map +1 -0
- package/dist/lib/catalog.d.ts +4 -0
- package/dist/lib/catalog.d.ts.map +1 -0
- package/dist/{commerce.d.ts → lib/commerce.d.ts} +2 -2
- package/dist/lib/commerce.d.ts.map +1 -0
- package/dist/lib/document.d.ts +13 -0
- package/dist/lib/document.d.ts.map +1 -0
- package/dist/lib/emails.d.ts +50 -0
- package/dist/lib/emails.d.ts.map +1 -0
- package/dist/lib/message-events.d.ts +4 -0
- package/dist/lib/message-events.d.ts.map +1 -0
- package/dist/lib/runtime.d.ts +5 -0
- package/dist/lib/runtime.d.ts.map +1 -0
- package/dist/lib/variant-matrix.d.ts +120 -0
- package/dist/lib/variant-matrix.d.ts.map +1 -0
- package/dist/mock.d.ts +1 -2
- package/dist/mock.d.ts.map +1 -1
- package/dist/mock.js +4 -2
- package/dist/provider.d.ts +1 -88
- package/dist/provider.d.ts.map +1 -1
- package/dist/providers/checkout.d.ts +129 -0
- package/dist/providers/checkout.d.ts.map +1 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/shipping.d.ts +43 -0
- package/dist/providers/shipping.d.ts.map +1 -0
- package/dist/providers.js +70 -0
- package/dist/providers.js.map +1 -0
- package/dist/rules/adapter.d.ts +36 -0
- package/dist/rules/adapter.d.ts.map +1 -0
- package/dist/rules/attributes.d.ts +64 -0
- package/dist/rules/attributes.d.ts.map +1 -0
- package/dist/rules/context.d.ts +43 -0
- package/dist/rules/context.d.ts.map +1 -0
- package/dist/rules/evaluator.d.ts +37 -0
- package/dist/rules/evaluator.d.ts.map +1 -0
- package/dist/rules/index.d.ts +13 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/prices.d.ts +25 -0
- package/dist/rules/prices.d.ts.map +1 -0
- package/dist/rules/rule-types.d.ts +160 -0
- package/dist/rules/rule-types.d.ts.map +1 -0
- package/dist/rules.js +22 -0
- package/dist/rules.js.map +1 -0
- package/dist/runtime.d.ts +1 -4
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +5 -3
- package/dist/shipping/label-provider.d.ts +43 -0
- package/dist/shipping/label-provider.d.ts.map +1 -0
- package/dist/types.d.ts +688 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +30 -20
- package/dist/chunk-CTKZ6O2J.js.map +0 -1
- package/dist/chunk-IYQHKMLB.js.map +0 -1
- package/dist/chunk-JR25TISO.js +0 -3
- package/dist/chunk-SVTCJ6HP.js +0 -440
- package/dist/chunk-SVTCJ6HP.js.map +0 -1
- package/dist/commerce.d.ts.map +0 -1
- package/dist/mock-catalog.d.ts.map +0 -1
- package/dist/mock-provider.d.ts +0 -60
- package/dist/mock-provider.d.ts.map +0 -1
- package/dist/supabase-provider.d.ts +0 -56
- package/dist/supabase-provider.d.ts.map +0 -1
- package/dist/tables.d.ts +0 -12
- package/dist/tables.d.ts.map +0 -1
- package/dist/tenant.d.ts.map +0 -1
- package/src/catalog.ts +0 -3
- package/src/commerce.ts +0 -120
- package/src/index.ts +0 -40
- package/src/mock-catalog.ts +0 -266
- package/src/mock-provider.ts +0 -480
- package/src/mock.ts +0 -2
- package/src/provider.ts +0 -117
- package/src/runtime.ts +0 -20
- package/src/supabase-provider.ts +0 -754
- package/src/tables.ts +0 -17
- package/src/tenant.ts +0 -21
- package/src/types.ts +0 -623
- /package/dist/{tenant.d.ts → data/tenant.d.ts} +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Registry } from '@fayz-ai/core';
|
|
2
|
+
import type { RegistryMeta } from '@fayz-ai/core';
|
|
3
|
+
import type { RuleOperator } from './rule-types';
|
|
4
|
+
export declare const RULE_ATTRIBUTE_FIELD_TYPES: readonly ["text", "number", "boolean"];
|
|
5
|
+
export type RuleAttributeFieldType = (typeof RULE_ATTRIBUTE_FIELD_TYPES)[number];
|
|
6
|
+
/**
|
|
7
|
+
* One vocabulary row.
|
|
8
|
+
*
|
|
9
|
+
* `path` locates the value in the evaluation context built from the cart
|
|
10
|
+
* snapshot. Paths under `items.` are ITEM-scoped: they evaluate per cart line
|
|
11
|
+
* (scoping target/buy rules to lines; for eligibility, "some line matches").
|
|
12
|
+
* Every other path is CART-scoped, walked from the snapshot root. A context
|
|
13
|
+
* provider's attributes resolve by KEY from the provided context instead.
|
|
14
|
+
*
|
|
15
|
+
* `value_source` names the id list an admin form offers as values
|
|
16
|
+
* ('products', 'categories', …) — a UI hint, never an evaluation input.
|
|
17
|
+
*/
|
|
18
|
+
export interface RuleAttribute {
|
|
19
|
+
key: string;
|
|
20
|
+
path: string;
|
|
21
|
+
label: string;
|
|
22
|
+
fieldType: RuleAttributeFieldType;
|
|
23
|
+
/** Where an admin form fetches candidate values. Null = free entry. */
|
|
24
|
+
valueSource?: string | null;
|
|
25
|
+
/** The operators this attribute supports — a subset of the 7. */
|
|
26
|
+
operators: readonly RuleOperator[];
|
|
27
|
+
}
|
|
28
|
+
/** Prefix that marks an attribute path as item-scoped. */
|
|
29
|
+
export declare const ITEM_PATH_PREFIX = "items.";
|
|
30
|
+
/**
|
|
31
|
+
* The core vocabulary — what every Fayz-backed store starts with, mirrored as
|
|
32
|
+
* the plg_shop_rule_attributes seed rows in migration 0032.
|
|
33
|
+
*/
|
|
34
|
+
export declare const CORE_RULE_ATTRIBUTES: readonly RuleAttribute[];
|
|
35
|
+
export declare const ruleAttributeRegistry: Registry<RuleAttribute>;
|
|
36
|
+
/** Idempotent — mirrors registerStorefrontBlocks: consumers call before reads. */
|
|
37
|
+
export declare function registerCoreRuleAttributes(): void;
|
|
38
|
+
export interface RegisterRuleAttributeOptions {
|
|
39
|
+
meta?: RegistryMeta;
|
|
40
|
+
/** Re-registering an existing key is an error unless the caller owns it
|
|
41
|
+
* (module re-evaluation under HMR re-registers the same declaration). */
|
|
42
|
+
replace?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Widen the vocabulary with one attribute. Duplicate keys are an I2 hard
|
|
46
|
+
* error naming the taken set — two providers silently fighting over one key
|
|
47
|
+
* would make rules mean different things on different renders.
|
|
48
|
+
*/
|
|
49
|
+
export declare function registerRuleAttribute(attribute: RuleAttribute, options?: RegisterRuleAttributeOptions): void;
|
|
50
|
+
/** The attribute for a key, or an I2 hard error naming the valid set — the
|
|
51
|
+
* only lookup the evaluator and the validators may use. */
|
|
52
|
+
export declare function resolveRuleAttribute(key: string): RuleAttribute;
|
|
53
|
+
export declare function hasRuleAttribute(key: string): boolean;
|
|
54
|
+
/** Every attribute key, sorted — the valid set I2 errors name. */
|
|
55
|
+
export declare function listRuleAttributeKeys(): string[];
|
|
56
|
+
/** Every vocabulary row, sorted by key — what describeStore publishes and the
|
|
57
|
+
* admin promotion form renders itself from. */
|
|
58
|
+
export declare function listRuleAttributes(): RuleAttribute[];
|
|
59
|
+
/** True when the attribute evaluates per cart line. */
|
|
60
|
+
export declare function isItemScopedAttribute(attribute: RuleAttribute): boolean;
|
|
61
|
+
/** Test seam — suites that widen the vocabulary must not leak into the next.
|
|
62
|
+
* Core attributes re-register on the next read. */
|
|
63
|
+
export declare function clearRuleAttributes(): void;
|
|
64
|
+
//# sourceMappingURL=attributes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../src/rules/attributes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAqBhD,eAAO,MAAM,0BAA0B,wCAAyC,CAAA;AAChF,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAA;AAEhF;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,sBAAsB,CAAA;IACjC,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,iEAAiE;IACjE,SAAS,EAAE,SAAS,YAAY,EAAE,CAAA;CACnC;AAKD,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,WAAW,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,aAAa,EAyExD,CAAA;AAOD,eAAO,MAAM,qBAAqB,yBAA+C,CAAA;AAIjF,kFAAkF;AAClF,wBAAgB,0BAA0B,IAAI,IAAI,CAUjD;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB;8EAC0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,aAAa,EAAE,OAAO,GAAE,4BAAiC,GAAG,IAAI,CA6BhH;AAED;4DAC4D;AAC5D,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAO/D;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAGhD;AAED;gDACgD;AAChD,wBAAgB,kBAAkB,IAAI,aAAa,EAAE,CAMpD;AAED,uDAAuD;AACvD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,CAEvE;AAED;oDACoD;AACpD,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Registry } from '@fayz-ai/core';
|
|
2
|
+
import type { RegistryMeta } from '@fayz-ai/core';
|
|
3
|
+
import type { RuleAttribute } from './attributes';
|
|
4
|
+
import type { RuleCartSnapshot } from './rule-types';
|
|
5
|
+
/** What a provider contributes: one context value per declared attribute key.
|
|
6
|
+
* A value may be a scalar of the declared field type or an array of them
|
|
7
|
+
* (e.g. customer tags); null/undefined mean "no value" and are dropped. */
|
|
8
|
+
export type RuleContext = Record<string, unknown>;
|
|
9
|
+
export interface RuleContextAttributeInput extends Omit<RuleAttribute, 'path'> {
|
|
10
|
+
/** Optional — context attributes resolve by KEY from the provided context,
|
|
11
|
+
* so the path is display metadata only. Defaults to `context.<key>`. */
|
|
12
|
+
path?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface RuleContextProvider {
|
|
15
|
+
/** Attributes this provider contributes — registered into the vocabulary. */
|
|
16
|
+
attributes: readonly RuleContextAttributeInput[];
|
|
17
|
+
/** Compute the context values for one evaluation. Pure of side effects. */
|
|
18
|
+
resolve(cart: RuleCartSnapshot): Promise<RuleContext> | RuleContext;
|
|
19
|
+
}
|
|
20
|
+
export declare const ruleContextRegistry: Registry<RuleContextProvider>;
|
|
21
|
+
/**
|
|
22
|
+
* Register a context provider. Its attributes enter the vocabulary
|
|
23
|
+
* immediately (duplicate keys are the I2 hard error registerRuleAttribute
|
|
24
|
+
* throws), so discovery and evaluation can never disagree about what exists.
|
|
25
|
+
*/
|
|
26
|
+
export declare function defineRuleContextProvider(id: string, provider: RuleContextProvider, meta?: RegistryMeta): void;
|
|
27
|
+
/**
|
|
28
|
+
* Validate one provider's resolved context against its declaration (I2):
|
|
29
|
+
* unknown keys name the declared set; wrong-typed values name the expected
|
|
30
|
+
* type. Returns only the declared, typed, non-null entries.
|
|
31
|
+
*/
|
|
32
|
+
export declare function validateRuleContextResult(id: string, provider: RuleContextProvider, result: RuleContext): RuleContext;
|
|
33
|
+
/**
|
|
34
|
+
* Run every registered provider against the cart and merge the validated
|
|
35
|
+
* results into one context record, keyed by attribute key — the `context`
|
|
36
|
+
* input of computePromotionActions. Key collisions cannot happen here: the
|
|
37
|
+
* vocabulary registry already refused the second registration.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildRuleContext(cart: RuleCartSnapshot): Promise<RuleContext>;
|
|
40
|
+
/** Test seam. Clearing providers does not un-register their vocabulary rows —
|
|
41
|
+
* pair with clearRuleAttributes() in suite teardown. */
|
|
42
|
+
export declare function clearRuleContextProviders(): void;
|
|
43
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/rules/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,OAAO,KAAK,EAAE,aAAa,EAA0B,MAAM,cAAc,CAAA;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AA0BpD;;4EAE4E;AAC5E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEjD,MAAM,WAAW,yBAA0B,SAAQ,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;IAC5E;6EACyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,UAAU,EAAE,SAAS,yBAAyB,EAAE,CAAA;IAChD,2EAA2E;IAC3E,OAAO,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAAA;CACpE;AAED,eAAO,MAAM,mBAAmB,+BAAmD,CAAA;AAEnF;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,mBAAmB,EAC7B,IAAI,GAAE,YAAiB,GACtB,IAAI,CAiBN;AAQD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,EAAE,WAAW,GAAG,WAAW,CAwBrH;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAOnF;AAED;yDACyD;AACzD,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { RuleContext } from './context';
|
|
2
|
+
import type { ComputeAction, Promotion, PromotionRule, RuleCartSnapshot } from './rule-types';
|
|
3
|
+
export interface EvaluateOptions {
|
|
4
|
+
/** Extra attribute values, keyed by attribute KEY — the validated output of
|
|
5
|
+
* buildRuleContext (context providers). Wins over snapshot resolution. */
|
|
6
|
+
context?: RuleContext;
|
|
7
|
+
/** ISO timestamp the date-window gates compare against. Default: now. */
|
|
8
|
+
now?: string;
|
|
9
|
+
}
|
|
10
|
+
/** One rule against a flat value list. Values are OR; `ne` is a negative and
|
|
11
|
+
* therefore holds only when NO value equals any rule value. */
|
|
12
|
+
export declare function matchRuleValues(rule: PromotionRule, values: unknown[]): boolean;
|
|
13
|
+
/** ALL rules match (AND). Empty/absent = match. */
|
|
14
|
+
export declare function rulesMatchCart(rules: PromotionRule[] | undefined, cart: RuleCartSnapshot, context?: RuleContext): boolean;
|
|
15
|
+
export type PromotionGateReason = 'inactive' | 'not_started' | 'expired' | 'usage_limit' | 'code_not_entered' | 'rules_not_matched';
|
|
16
|
+
/**
|
|
17
|
+
* Why a promotion does NOT fire against this cart, or null when it does.
|
|
18
|
+
* Shared by the evaluator and the coupon-surface adapter so a rejected code
|
|
19
|
+
* reports the same machine-readable reason everywhere.
|
|
20
|
+
*/
|
|
21
|
+
export declare function promotionGateReason(promotion: Promotion, cart: RuleCartSnapshot, options?: EvaluateOptions): PromotionGateReason | null;
|
|
22
|
+
/** Split `total` across weights, in cents, largest-remainder — the parts sum
|
|
23
|
+
* to exactly `total` so a spread discount never loses or invents a cent. */
|
|
24
|
+
export declare function splitProportionally(total: number, weights: number[]): number[];
|
|
25
|
+
/** Deterministic evaluation order: buyget first, specific before generic, id
|
|
26
|
+
* as the final tiebreak. Exported so the SQL mirror's ORDER BY has a named
|
|
27
|
+
* TS counterpart to test against. */
|
|
28
|
+
export declare function orderPromotions(promotions: Promotion[]): Promotion[];
|
|
29
|
+
/**
|
|
30
|
+
* Evaluate promotions against a cart snapshot → the ordered compute-actions
|
|
31
|
+
* the cart applies. Pure and deterministic (inject `now` for date gates).
|
|
32
|
+
*/
|
|
33
|
+
export declare function computePromotionActions(cart: RuleCartSnapshot, promotions: Promotion[], options?: EvaluateOptions): ComputeAction[];
|
|
34
|
+
/** Total item+shipping discount an action list carries — the preview number a
|
|
35
|
+
* cart shows. Free items carry no amount (they enter the cart at price 0). */
|
|
36
|
+
export declare function actionsDiscountTotal(actions: ComputeAction[]): number;
|
|
37
|
+
//# sourceMappingURL=evaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluator.d.ts","sourceRoot":"","sources":["../../src/rules/evaluator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAK5C,OAAO,KAAK,EAEV,aAAa,EACb,SAAS,EACT,aAAa,EAEb,gBAAgB,EAEjB,MAAM,cAAc,CAAA;AAkCrB,MAAM,WAAW,eAAe;IAC9B;+EAC2E;IAC3E,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AA4DD;gEACgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAgB/E;AAoBD,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAE7H;AASD,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,aAAa,GACb,SAAS,GACT,aAAa,GACb,kBAAkB,GAClB,mBAAmB,CAAA;AAEvB;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,gBAAgB,EACtB,OAAO,GAAE,eAAoB,GAC5B,mBAAmB,GAAG,IAAI,CAe5B;AAQD;6EAC6E;AAC7E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAgB9E;AAoJD;;sCAEsC;AACtC,wBAAgB,eAAe,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAQpE;AAID;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,gBAAgB,EACtB,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,GAAE,eAAoB,GAC5B,aAAa,EAAE,CAYjB;AAED;+EAC+E;AAC/E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,CAIrE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { RULE_OPERATORS, APPLICATION_METHOD_TYPES, APPLICATION_METHOD_TARGET_TYPES, APPLICATION_METHOD_ALLOCATIONS, PROMOTION_TYPES, PROMOTION_STATUSES, cartSubtotal, roundCents, } from './rule-types';
|
|
2
|
+
export type { RuleOperator, RuleValue, PromotionRule, ApplicationMethod, ApplicationMethodType, ApplicationMethodTargetType, ApplicationMethodAllocation, Promotion, PromotionType, PromotionStatus, Campaign, RuleCartItem, RuleCartSnapshot, ComputeAction, AddItemDiscountAction, AddShippingDiscountAction, AddFreeItemAction, } from './rule-types';
|
|
3
|
+
export { RULE_ATTRIBUTE_FIELD_TYPES, CORE_RULE_ATTRIBUTES, ITEM_PATH_PREFIX, ruleAttributeRegistry, registerCoreRuleAttributes, registerRuleAttribute, resolveRuleAttribute, hasRuleAttribute, listRuleAttributeKeys, listRuleAttributes, isItemScopedAttribute, clearRuleAttributes, } from './attributes';
|
|
4
|
+
export type { RuleAttribute, RuleAttributeFieldType, RegisterRuleAttributeOptions } from './attributes';
|
|
5
|
+
export { ruleContextRegistry, defineRuleContextProvider, validateRuleContextResult, buildRuleContext, clearRuleContextProviders, } from './context';
|
|
6
|
+
export type { RuleContext, RuleContextProvider, RuleContextAttributeInput } from './context';
|
|
7
|
+
export { computePromotionActions, promotionGateReason, rulesMatchCart, matchRuleValues, orderPromotions, splitProportionally, actionsDiscountTotal, } from './evaluator';
|
|
8
|
+
export type { EvaluateOptions, PromotionGateReason } from './evaluator';
|
|
9
|
+
export { rankPrices, selectPrice } from './prices';
|
|
10
|
+
export type { PriceCandidate, RankPricesOptions } from './prices';
|
|
11
|
+
export { discountToPromotion, storefrontDiscountToPromotion, previewCouponPercent, } from './adapter';
|
|
12
|
+
export type { StorefrontPercentCode, CouponPreview } from './adapter';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,+BAA+B,EAC/B,8BAA8B,EAC9B,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,UAAU,GACX,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,YAAY,EACZ,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,2BAA2B,EAC3B,2BAA2B,EAC3B,SAAS,EACT,aAAa,EACb,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,GAClB,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAA;AAEvG,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AAE5F,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEvE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAEjE,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,oBAAoB,GACrB,MAAM,WAAW,CAAA;AAClB,YAAY,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RuleContext } from './context';
|
|
2
|
+
import type { PromotionRule, RuleCartSnapshot } from './rule-types';
|
|
3
|
+
/** One candidate price for a purchasable. `rules` guard applicability;
|
|
4
|
+
* `priceListId` marks an override list (a price list always outranks a
|
|
5
|
+
* bare price, however many rules the bare price carries). */
|
|
6
|
+
export interface PriceCandidate {
|
|
7
|
+
id: string;
|
|
8
|
+
amount: number;
|
|
9
|
+
priceListId?: string | null;
|
|
10
|
+
rules?: PromotionRule[];
|
|
11
|
+
}
|
|
12
|
+
export interface RankPricesOptions {
|
|
13
|
+
/** Context-provider values, keyed by attribute key (see buildRuleContext). */
|
|
14
|
+
context?: RuleContext;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The applicable candidates, most-precedent first:
|
|
18
|
+
* price_list first, rules_count DESC, amount ASC, id as a stable tiebreak.
|
|
19
|
+
* A candidate whose rules do not ALL match is not in the answer at all —
|
|
20
|
+
* matched_count = rules_count, never partial credit.
|
|
21
|
+
*/
|
|
22
|
+
export declare function rankPrices(candidates: PriceCandidate[], cart: RuleCartSnapshot, options?: RankPricesOptions): PriceCandidate[];
|
|
23
|
+
/** The winning price, or null when no candidate's rules all match. */
|
|
24
|
+
export declare function selectPrice(candidates: PriceCandidate[], cart: RuleCartSnapshot, options?: RankPricesOptions): PriceCandidate | null;
|
|
25
|
+
//# sourceMappingURL=prices.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prices.d.ts","sourceRoot":"","sources":["../../src/rules/prices.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAsBnE;;8DAE8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,KAAK,CAAC,EAAE,aAAa,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,WAAW,CAAA;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,cAAc,EAAE,EAC5B,IAAI,EAAE,gBAAgB,EACtB,OAAO,GAAE,iBAAsB,GAC9B,cAAc,EAAE,CAYlB;AAED,sEAAsE;AACtE,wBAAgB,WAAW,CACzB,UAAU,EAAE,cAAc,EAAE,EAC5B,IAAI,EAAE,gBAAgB,EACtB,OAAO,GAAE,iBAAsB,GAC9B,cAAc,GAAG,IAAI,CAEvB"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/** The 7 rule operators. This is the closed set — widening it is a model
|
|
2
|
+
* change (TS union + DB CHECK + SQL evaluator), not an insert. */
|
|
3
|
+
export declare const RULE_OPERATORS: readonly ["gte", "lte", "gt", "lt", "eq", "ne", "in"];
|
|
4
|
+
export type RuleOperator = (typeof RULE_OPERATORS)[number];
|
|
5
|
+
/** A rule value is a JSON scalar. The DB stores each in its own
|
|
6
|
+
* plg_shop_rule_values row (values-in-a-child-table, per the model). */
|
|
7
|
+
export type RuleValue = string | number | boolean;
|
|
8
|
+
/**
|
|
9
|
+
* One rule: `attribute` names a row of the rule_attribute VOCABULARY (I9 —
|
|
10
|
+
* never a free-form dotted path; an unknown attribute is an I2 hard error
|
|
11
|
+
* naming the valid set), `operator` is one of the 7, `values` is the child
|
|
12
|
+
* list (a single-element list for scalar operators).
|
|
13
|
+
*/
|
|
14
|
+
export interface PromotionRule {
|
|
15
|
+
attribute: string;
|
|
16
|
+
operator: RuleOperator;
|
|
17
|
+
values: RuleValue[];
|
|
18
|
+
}
|
|
19
|
+
export declare const APPLICATION_METHOD_TYPES: readonly ["percentage", "fixed"];
|
|
20
|
+
export type ApplicationMethodType = (typeof APPLICATION_METHOD_TYPES)[number];
|
|
21
|
+
export declare const APPLICATION_METHOD_TARGET_TYPES: readonly ["order", "items", "shipping"];
|
|
22
|
+
export type ApplicationMethodTargetType = (typeof APPLICATION_METHOD_TARGET_TYPES)[number];
|
|
23
|
+
export declare const APPLICATION_METHOD_ALLOCATIONS: readonly ["each", "across", "once"];
|
|
24
|
+
export type ApplicationMethodAllocation = (typeof APPLICATION_METHOD_ALLOCATIONS)[number];
|
|
25
|
+
/**
|
|
26
|
+
* HOW an eligible promotion applies. The six numbers + two rule sets that make
|
|
27
|
+
* buy-N-pay-M pure data:
|
|
28
|
+
*
|
|
29
|
+
* - `type` percentage (value = percentage points) or fixed (value = amount).
|
|
30
|
+
* - `targetType` order (spread across all items) | items | shipping.
|
|
31
|
+
* - `allocation` (items only):
|
|
32
|
+
* each — per unit of each eligible line, `maxQuantity` units per line;
|
|
33
|
+
* across — one amount over the eligible subtotal, split proportionally;
|
|
34
|
+
* once — one unit of the cheapest eligible line, once.
|
|
35
|
+
* - `buyRulesMinQuantity` + `buyRules` — what must be in the cart, and how
|
|
36
|
+
* many, for the promotion to fire (buyget). The promotion applies
|
|
37
|
+
* floor(matched buy quantity / buyRulesMinQuantity) times.
|
|
38
|
+
* - `applyToQuantity` — how many target units each firing discounts.
|
|
39
|
+
* - `targetRules` — which items the discount lands on. A buyget whose target
|
|
40
|
+
* is not in the cart but is pinned to one product id emits addFreeItem.
|
|
41
|
+
*/
|
|
42
|
+
export interface ApplicationMethod {
|
|
43
|
+
type: ApplicationMethodType;
|
|
44
|
+
value: number;
|
|
45
|
+
targetType: ApplicationMethodTargetType;
|
|
46
|
+
allocation?: ApplicationMethodAllocation;
|
|
47
|
+
/** Unit cap: per line for `each`; total discounted/free units for buyget. */
|
|
48
|
+
maxQuantity?: number | null;
|
|
49
|
+
/** Buyget: target units discounted per firing. */
|
|
50
|
+
applyToQuantity?: number | null;
|
|
51
|
+
/** Buyget: matched buy quantity required per firing. Null/absent = standard. */
|
|
52
|
+
buyRulesMinQuantity?: number | null;
|
|
53
|
+
/** What gets discounted (the `target` pivot). Absent = every item. */
|
|
54
|
+
targetRules?: PromotionRule[];
|
|
55
|
+
/** What must be bought (the `buy` pivot). Item-scoped attributes only. */
|
|
56
|
+
buyRules?: PromotionRule[];
|
|
57
|
+
}
|
|
58
|
+
export declare const PROMOTION_TYPES: readonly ["standard", "buyget"];
|
|
59
|
+
export type PromotionType = (typeof PROMOTION_TYPES)[number];
|
|
60
|
+
export declare const PROMOTION_STATUSES: readonly ["draft", "active", "inactive"];
|
|
61
|
+
export type PromotionStatus = (typeof PROMOTION_STATUSES)[number];
|
|
62
|
+
/**
|
|
63
|
+
* A promotion: eligibility rules (the `eligibility` pivot) + one application
|
|
64
|
+
* method. `code` promotions fire only when the shopper entered the code
|
|
65
|
+
* (cart.codes); `isAutomatic` promotions fire whenever eligible.
|
|
66
|
+
*/
|
|
67
|
+
export interface Promotion {
|
|
68
|
+
id: string;
|
|
69
|
+
/** Coupon code. Null/absent = automatic-only. Matched case-insensitively. */
|
|
70
|
+
code?: string | null;
|
|
71
|
+
isAutomatic?: boolean;
|
|
72
|
+
/** Derivable (buyRulesMinQuantity ⇒ buyget) but stored for the admin UI. */
|
|
73
|
+
type?: PromotionType;
|
|
74
|
+
status?: PromotionStatus;
|
|
75
|
+
campaignId?: string | null;
|
|
76
|
+
/** Does this promotion apply at all? (the `eligibility` pivot). AND across
|
|
77
|
+
* rules; a rule's values are OR. Absent/empty = always eligible. */
|
|
78
|
+
rules?: PromotionRule[];
|
|
79
|
+
applicationMethod: ApplicationMethod;
|
|
80
|
+
startsAt?: string | null;
|
|
81
|
+
endsAt?: string | null;
|
|
82
|
+
usageLimit?: number | null;
|
|
83
|
+
timesUsed?: number;
|
|
84
|
+
}
|
|
85
|
+
/** A campaign groups promotions for reporting/budgets. Parent row only in M6;
|
|
86
|
+
* budget enforcement is a later milestone. */
|
|
87
|
+
export interface Campaign {
|
|
88
|
+
id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
startsAt?: string | null;
|
|
91
|
+
endsAt?: string | null;
|
|
92
|
+
}
|
|
93
|
+
/** One cart line as the engine sees it. Prices are authoritative-catalog
|
|
94
|
+
* prices; the engine never trusts a client-computed total. */
|
|
95
|
+
export interface RuleCartItem {
|
|
96
|
+
/** Line identity actions refer back to. Defaults to productId. */
|
|
97
|
+
id?: string;
|
|
98
|
+
productId: string;
|
|
99
|
+
quantity: number;
|
|
100
|
+
unitPrice: number;
|
|
101
|
+
categoryId?: string | null;
|
|
102
|
+
collectionId?: string | null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The evaluation input. Serializable on purpose: the SAME snapshot shape is
|
|
106
|
+
* the TS evaluator's input and the SQL function's `p_cart` jsonb, so the
|
|
107
|
+
* preview a shopper sees and the revalidation place_order runs read one
|
|
108
|
+
* contract.
|
|
109
|
+
*/
|
|
110
|
+
export interface RuleCartSnapshot {
|
|
111
|
+
items: RuleCartItem[];
|
|
112
|
+
/** Quoted shipping — what a shipping-target promotion discounts. */
|
|
113
|
+
shippingTotal?: number | null;
|
|
114
|
+
/** Shipping region/zone identifier (the shipping.region attribute). */
|
|
115
|
+
region?: string | null;
|
|
116
|
+
customer?: {
|
|
117
|
+
email?: string | null;
|
|
118
|
+
tags?: string[];
|
|
119
|
+
};
|
|
120
|
+
/** Promotion codes the shopper entered (the code attribute; case-insensitive). */
|
|
121
|
+
codes?: string[];
|
|
122
|
+
currency?: string;
|
|
123
|
+
}
|
|
124
|
+
/** Discount one cart line by an absolute amount (already allocation-resolved). */
|
|
125
|
+
export interface AddItemDiscountAction {
|
|
126
|
+
action: 'addItemDiscount';
|
|
127
|
+
promotionId: string;
|
|
128
|
+
code?: string | null;
|
|
129
|
+
itemId: string;
|
|
130
|
+
amount: number;
|
|
131
|
+
}
|
|
132
|
+
/** Discount the shipping total by an absolute amount. */
|
|
133
|
+
export interface AddShippingDiscountAction {
|
|
134
|
+
action: 'addShippingDiscount';
|
|
135
|
+
promotionId: string;
|
|
136
|
+
code?: string | null;
|
|
137
|
+
amount: number;
|
|
138
|
+
}
|
|
139
|
+
/** Add `quantity` free units of a product the buyget promotion grants but the
|
|
140
|
+
* cart does not contain. The cart applies it by adding the line at price 0. */
|
|
141
|
+
export interface AddFreeItemAction {
|
|
142
|
+
action: 'addFreeItem';
|
|
143
|
+
promotionId: string;
|
|
144
|
+
code?: string | null;
|
|
145
|
+
productId: string;
|
|
146
|
+
quantity: number;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The ordered action list computePromotionActions returns. Deterministic:
|
|
150
|
+
* buyget promotions first (they consume target units), then by specificity
|
|
151
|
+
* (total rules count DESC), then id — so replaying the same cart against the
|
|
152
|
+
* same promotions always yields byte-identical actions.
|
|
153
|
+
*/
|
|
154
|
+
export type ComputeAction = AddItemDiscountAction | AddShippingDiscountAction | AddFreeItemAction;
|
|
155
|
+
/** Sum of a cart's line totals, cents-rounded — the number `cart.subtotal`
|
|
156
|
+
* rules compare against. */
|
|
157
|
+
export declare function cartSubtotal(cart: RuleCartSnapshot): number;
|
|
158
|
+
/** Cents rounding, the house money convention (commerce.ts round2). */
|
|
159
|
+
export declare function roundCents(value: number): number;
|
|
160
|
+
//# sourceMappingURL=rule-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-types.d.ts","sourceRoot":"","sources":["../../src/rules/rule-types.ts"],"names":[],"mappings":"AAsBA;mEACmE;AACnE,eAAO,MAAM,cAAc,uDAAwD,CAAA;AACnF,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAA;AAE1D;yEACyE;AACzE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAEjD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,YAAY,CAAA;IACtB,MAAM,EAAE,SAAS,EAAE,CAAA;CACpB;AAED,eAAO,MAAM,wBAAwB,kCAAmC,CAAA;AACxE,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE7E,eAAO,MAAM,+BAA+B,yCAA0C,CAAA;AACtF,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,+BAA+B,CAAC,CAAC,MAAM,CAAC,CAAA;AAE1F,eAAO,MAAM,8BAA8B,qCAAsC,CAAA;AACjF,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,qBAAqB,CAAA;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,2BAA2B,CAAA;IACvC,UAAU,CAAC,EAAE,2BAA2B,CAAA;IACxC,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,gFAAgF;IAChF,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,sEAAsE;IACtE,WAAW,CAAC,EAAE,aAAa,EAAE,CAAA;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAA;CAC3B;AAED,eAAO,MAAM,eAAe,iCAAkC,CAAA;AAC9D,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAE5D,eAAO,MAAM,kBAAkB,0CAA2C,CAAA;AAC1E,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEjE;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B;yEACqE;IACrE,KAAK,CAAC,EAAE,aAAa,EAAE,CAAA;IACvB,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;+CAC+C;AAC/C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAID;+DAC+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,EAAE,CAAA;IACrB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;IACrD,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAID,kFAAkF;AAClF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,iBAAiB,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,yDAAyD;AACzD,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,qBAAqB,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;gFACgF;AAChF,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,aAAa,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,qBAAqB,GAAG,yBAAyB,GAAG,iBAAiB,CAAA;AAEjG;6BAC6B;AAC7B,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAE3D;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD"}
|
package/dist/rules.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { rulesMatchCart } from './chunk-3GERSY5F.js';
|
|
2
|
+
export { APPLICATION_METHOD_ALLOCATIONS, APPLICATION_METHOD_TARGET_TYPES, APPLICATION_METHOD_TYPES, CORE_RULE_ATTRIBUTES, ITEM_PATH_PREFIX, PROMOTION_STATUSES, PROMOTION_TYPES, RULE_ATTRIBUTE_FIELD_TYPES, RULE_OPERATORS, actionsDiscountTotal, buildRuleContext, cartSubtotal, clearRuleAttributes, clearRuleContextProviders, computePromotionActions, defineRuleContextProvider, discountToPromotion, hasRuleAttribute, isItemScopedAttribute, listRuleAttributeKeys, listRuleAttributes, matchRuleValues, orderPromotions, previewCouponPercent, promotionGateReason, registerCoreRuleAttributes, registerRuleAttribute, resolveRuleAttribute, roundCents, ruleAttributeRegistry, ruleContextRegistry, rulesMatchCart, splitProportionally, storefrontDiscountToPromotion, validateRuleContextResult } from './chunk-3GERSY5F.js';
|
|
3
|
+
|
|
4
|
+
// src/rules/prices.ts
|
|
5
|
+
function rankPrices(candidates, cart, options = {}) {
|
|
6
|
+
const context = options.context ?? {};
|
|
7
|
+
return candidates.filter((candidate) => rulesMatchCart(candidate.rules, cart, context)).sort((a, b) => {
|
|
8
|
+
const list = Number(b.priceListId != null) - Number(a.priceListId != null);
|
|
9
|
+
if (list !== 0) return list;
|
|
10
|
+
const specificity = (b.rules?.length ?? 0) - (a.rules?.length ?? 0);
|
|
11
|
+
if (specificity !== 0) return specificity;
|
|
12
|
+
if (a.amount !== b.amount) return a.amount - b.amount;
|
|
13
|
+
return a.id.localeCompare(b.id);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function selectPrice(candidates, cart, options = {}) {
|
|
17
|
+
return rankPrices(candidates, cart, options)[0] ?? null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { rankPrices, selectPrice };
|
|
21
|
+
//# sourceMappingURL=rules.js.map
|
|
22
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rules/prices.ts"],"names":[],"mappings":";;;;AA6CO,SAAS,UAAA,CACd,UAAA,EACA,IAAA,EACA,OAAA,GAA6B,EAAC,EACZ;AAClB,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,EAAC;AACpC,EAAA,OAAO,UAAA,CACJ,MAAA,CAAO,CAAC,SAAA,KAAc,eAAe,SAAA,CAAU,KAAA,EAAO,IAAA,EAAM,OAAO,CAAC,CAAA,CACpE,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AACd,IAAA,MAAM,IAAA,GAAO,OAAO,CAAA,CAAE,WAAA,IAAe,IAAI,CAAA,GAAI,MAAA,CAAO,CAAA,CAAE,WAAA,IAAe,IAAI,CAAA;AACzE,IAAA,IAAI,IAAA,KAAS,GAAG,OAAO,IAAA;AACvB,IAAA,MAAM,eAAe,CAAA,CAAE,KAAA,EAAO,UAAU,CAAA,KAAM,CAAA,CAAE,OAAO,MAAA,IAAU,CAAA,CAAA;AACjE,IAAA,IAAI,WAAA,KAAgB,GAAG,OAAO,WAAA;AAC9B,IAAA,IAAI,EAAE,MAAA,KAAW,CAAA,CAAE,QAAQ,OAAO,CAAA,CAAE,SAAS,CAAA,CAAE,MAAA;AAC/C,IAAA,OAAO,CAAA,CAAE,EAAA,CAAG,aAAA,CAAc,CAAA,CAAE,EAAE,CAAA;AAAA,EAChC,CAAC,CAAA;AACL;AAGO,SAAS,WAAA,CACd,UAAA,EACA,IAAA,EACA,OAAA,GAA6B,EAAC,EACP;AACvB,EAAA,OAAO,WAAW,UAAA,EAAY,IAAA,EAAM,OAAO,CAAA,CAAE,CAAC,CAAA,IAAK,IAAA;AACrD","file":"rules.js","sourcesContent":["import { rulesMatchCart } from './evaluator'\nimport type { RuleContext } from './context'\nimport type { PromotionRule, RuleCartSnapshot } from './rule-types'\n\n// ---------------------------------------------------------------------------\n// Price precedence by rules_count specificity (spine §3 L2) — Medusa's\n// pricing trick (pricing/src/repositories/pricing.ts:228-295), adopted\n// because it makes precedence DERIVABLE FROM THE DATA ALONE:\n//\n// a price applies iff matched_count = rules_count,\n// ranked price_list first, rules_count DESC, amount ASC.\n//\n// \"Applies iff matched_count = rules_count\" is simply \"ALL of its rules\n// match\" — rulesMatchCart. Because the ranking is a pure function of the\n// candidate rows, an agent adding \"VIP customers in Brazil buying more than\n// 10 units get this price\" never reasons about precedence: more rules = more\n// specific = wins; ties resolve to the cheaper price, which is the promise a\n// shopper was shown somewhere.\n//\n// Same rule model, same vocabulary, same evaluator — this is what \"ONE rule\n// engine\" (I8) buys: prices, promotions and shipping share matching\n// semantics, so a rule means the same thing wherever it appears.\n// ---------------------------------------------------------------------------\n\n/** One candidate price for a purchasable. `rules` guard applicability;\n * `priceListId` marks an override list (a price list always outranks a\n * bare price, however many rules the bare price carries). */\nexport interface PriceCandidate {\n id: string\n amount: number\n priceListId?: string | null\n rules?: PromotionRule[]\n}\n\nexport interface RankPricesOptions {\n /** Context-provider values, keyed by attribute key (see buildRuleContext). */\n context?: RuleContext\n}\n\n/**\n * The applicable candidates, most-precedent first:\n * price_list first, rules_count DESC, amount ASC, id as a stable tiebreak.\n * A candidate whose rules do not ALL match is not in the answer at all —\n * matched_count = rules_count, never partial credit.\n */\nexport function rankPrices(\n candidates: PriceCandidate[],\n cart: RuleCartSnapshot,\n options: RankPricesOptions = {},\n): PriceCandidate[] {\n const context = options.context ?? {}\n return candidates\n .filter((candidate) => rulesMatchCart(candidate.rules, cart, context))\n .sort((a, b) => {\n const list = Number(b.priceListId != null) - Number(a.priceListId != null)\n if (list !== 0) return list\n const specificity = (b.rules?.length ?? 0) - (a.rules?.length ?? 0)\n if (specificity !== 0) return specificity\n if (a.amount !== b.amount) return a.amount - b.amount\n return a.id.localeCompare(b.id)\n })\n}\n\n/** The winning price, or null when no candidate's rules all match. */\nexport function selectPrice(\n candidates: PriceCandidate[],\n cart: RuleCartSnapshot,\n options: RankPricesOptions = {},\n): PriceCandidate | null {\n return rankPrices(candidates, cart, options)[0] ?? null\n}\n"]}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function getShopProvider(): ShopProvider;
|
|
3
|
-
export declare function setShopProvider(nextProvider: ShopProvider): void;
|
|
4
|
-
export declare function resetShopProvider(): void;
|
|
1
|
+
export * from './lib/runtime';
|
|
5
2
|
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAEA,cAAc,eAAe,CAAA"}
|
package/dist/runtime.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { getShopProvider, resetShopProvider, setShopProvider } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
export { getShopProvider, resetShopProvider, setShopProvider } from './chunk-2WACO2TG.js';
|
|
2
|
+
import './chunk-U6HV3LVP.js';
|
|
3
|
+
import './chunk-IKNGCRUM.js';
|
|
4
|
+
import './chunk-NWW3WJ7Y.js';
|
|
5
|
+
import './chunk-3GERSY5F.js';
|
|
4
6
|
//# sourceMappingURL=runtime.js.map
|
|
5
7
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ShippingLabel, ShippingLabelOption } from '../types';
|
|
2
|
+
export interface ShippingLabelProvider {
|
|
3
|
+
/** Connector slug — the id `plg_connections.connector_id` carries. */
|
|
4
|
+
id: string;
|
|
5
|
+
/** How the merchant knows them ("Melhor Envio"). Shown in the panel. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Services and prices for one order. Free, repeatable, spends nothing. */
|
|
8
|
+
quote(orderId: string): Promise<{
|
|
9
|
+
options: ShippingLabelOption[];
|
|
10
|
+
label: ShippingLabel | null;
|
|
11
|
+
}>;
|
|
12
|
+
/** SPENDS the merchant's balance. Idempotent per order by contract. */
|
|
13
|
+
buy(orderId: string, serviceId: number): Promise<ShippingLabel>;
|
|
14
|
+
/** The label PDF, as many times as the merchant needs it. */
|
|
15
|
+
print(orderId: string): Promise<string | null>;
|
|
16
|
+
/** What the carrier says now. */
|
|
17
|
+
track(orderId: string): Promise<ShippingLabel['tracking']>;
|
|
18
|
+
}
|
|
19
|
+
export declare function registerShippingLabelProvider(provider: ShippingLabelProvider): void;
|
|
20
|
+
export declare function listShippingLabelProviders(): ShippingLabelProvider[];
|
|
21
|
+
/** Test seam — the registry is module state, and a test that registers a fake
|
|
22
|
+
* must not leak it into the next one. */
|
|
23
|
+
export declare function resetShippingLabelProviders(): void;
|
|
24
|
+
export interface ResolveShippingLabelOptions {
|
|
25
|
+
/** Connector ids the store has ACTIVE, in the order the panel lists them. */
|
|
26
|
+
connected: readonly string[];
|
|
27
|
+
/**
|
|
28
|
+
* The merchant's explicit choice, when they made one.
|
|
29
|
+
*
|
|
30
|
+
* `''` (empty, not undefined) is a decision too — "I print labels myself" —
|
|
31
|
+
* and it must beat every connected carrier, exactly as the payment provider
|
|
32
|
+
* setting treats "confirmo à mão".
|
|
33
|
+
*/
|
|
34
|
+
preferred?: string | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Which carrier issues this store's labels — or nobody.
|
|
38
|
+
*
|
|
39
|
+
* Null is a first-class answer and the common one: most stores dispatch by hand,
|
|
40
|
+
* and the panel must show them the manual path without a dead button beside it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveShippingLabelProvider(options: ResolveShippingLabelOptions): ShippingLabelProvider | null;
|
|
43
|
+
//# sourceMappingURL=label-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"label-provider.d.ts","sourceRoot":"","sources":["../../src/shipping/label-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAiBlE,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAA;IACV,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;QAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;KAAE,CAAC,CAAA;IAChG,uEAAuE;IACvE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;IAC/D,6DAA6D;IAC7D,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAC9C,iCAAiC;IACjC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAA;CAC3D;AAID,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAEnF;AAED,wBAAgB,0BAA0B,IAAI,qBAAqB,EAAE,CAEpE;AAED;0CAC0C;AAC1C,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED,MAAM,WAAW,2BAA2B;IAC1C,6EAA6E;IAC7E,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,2BAA2B,GACnC,qBAAqB,GAAG,IAAI,CAkB9B"}
|