sahab-utils 1.7.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -655,6 +655,17 @@ export type Discount = {
655
655
  gift?: {
656
656
  giftId: string;
657
657
  };
658
+ /**
659
+ * Which environment this offer belongs to. Absent means prod, matching every offer created
660
+ * before this field existed — mirrors `Client.isTest`/`Order.isTest`/`Provider.isTest`.
661
+ *
662
+ * Only meaningful for an offer that doesn't otherwise resolve to one environment (see
663
+ * `loyaltyOfferMatchesTestMode` in `ts/loyalty.ts`): a provider-scoped offer's environment is
664
+ * really the provider's own `isTest`, and a gift voucher's is really the gift's — this field
665
+ * is what lets a genuinely Sahab-wide, no-single-provider offer (or a promo code with no
666
+ * gift/provider scope at all) still declare one explicitly.
667
+ */
668
+ isTest?: boolean;
658
669
  };
659
670
  /**
660
671
  * "Buy N washes, get one free" configuration, carried on the `Discount` that represents the
@@ -762,6 +773,12 @@ export type Gift = {
762
773
  expiresAt?: TimestampType;
763
774
  notifiedAt?: TimestampType;
764
775
  notifyChannel?: GiftNotifyChannel;
776
+ /**
777
+ * Whether the giver was a test client at purchase — mirrors `Client.isTest`. Stamped once at
778
+ * creation and never recomputed, same reasoning as `expiresAt`: a client's test/prod status
779
+ * changing later must not retroactively move a gift someone already paid for.
780
+ */
781
+ isTest?: boolean;
765
782
  };
766
783
  /** One line of a gifted basket, priced when the gift was bought. */
767
784
  export type GiftItem = {
package/dist/ts/gifts.js CHANGED
@@ -121,6 +121,7 @@ function giftDiscount(gift, dates) {
121
121
  validFrom: dates.validFrom,
122
122
  validTo: dates.validTo,
123
123
  gift: { giftId: gift.giftId },
124
+ isTest: gift.isTest,
124
125
  };
125
126
  }
126
127
  /** Every service and addon line on an order, flattened. */
@@ -20,6 +20,19 @@ export declare function isProviderLoyaltyOffer(offer?: Discount): boolean;
20
20
  export declare function isSahabLoyaltyOffer(offer?: Discount): boolean;
21
21
  /** Whether an offer's provider scope admits a given provider. */
22
22
  export declare function loyaltyCoversProvider(offer: Discount | undefined, providerUid?: string): boolean;
23
+ /**
24
+ * Whether a loyalty offer belongs to the given test/prod environment.
25
+ *
26
+ * An offer's environment is decided in priority order:
27
+ * 1. `offer.isTest`, when the offer declares one explicitly.
28
+ * 2. `providerIsTest`, for an offer scoped to exactly one provider — resolving that (a
29
+ * Firestore read on the provider) is the caller's job, since this stays framework-agnostic.
30
+ * Pass it only when `loyaltyProviderScope(offer)` resolves to a single provider.
31
+ * 3. Prod, otherwise — a genuinely network-wide offer with no explicit flag is exactly the
32
+ * shape every offer had before this field existed, so it stays visible to prod and hidden
33
+ * from test rather than leaking into both.
34
+ */
35
+ export declare function loyaltyOfferMatchesTestMode(offer: Discount | undefined, isTest: boolean, providerIsTest?: boolean): boolean;
23
36
  /**
24
37
  * Whether a finished order earns a stamp.
25
38
  *
@@ -4,6 +4,7 @@ exports.loyaltyProviderScope = loyaltyProviderScope;
4
4
  exports.isProviderLoyaltyOffer = isProviderLoyaltyOffer;
5
5
  exports.isSahabLoyaltyOffer = isSahabLoyaltyOffer;
6
6
  exports.loyaltyCoversProvider = loyaltyCoversProvider;
7
+ exports.loyaltyOfferMatchesTestMode = loyaltyOfferMatchesTestMode;
7
8
  exports.orderEarnsLoyaltyStamp = orderEarnsLoyaltyStamp;
8
9
  exports.giftEarnsLoyaltyStamp = giftEarnsLoyaltyStamp;
9
10
  exports.emptyLoyaltyProgress = emptyLoyaltyProgress;
@@ -67,6 +68,25 @@ function loyaltyCoversProvider(offer, providerUid) {
67
68
  return true;
68
69
  return !!providerUid && scope.includes(providerUid);
69
70
  }
71
+ /**
72
+ * Whether a loyalty offer belongs to the given test/prod environment.
73
+ *
74
+ * An offer's environment is decided in priority order:
75
+ * 1. `offer.isTest`, when the offer declares one explicitly.
76
+ * 2. `providerIsTest`, for an offer scoped to exactly one provider — resolving that (a
77
+ * Firestore read on the provider) is the caller's job, since this stays framework-agnostic.
78
+ * Pass it only when `loyaltyProviderScope(offer)` resolves to a single provider.
79
+ * 3. Prod, otherwise — a genuinely network-wide offer with no explicit flag is exactly the
80
+ * shape every offer had before this field existed, so it stays visible to prod and hidden
81
+ * from test rather than leaking into both.
82
+ */
83
+ function loyaltyOfferMatchesTestMode(offer, isTest, providerIsTest) {
84
+ if (typeof (offer === null || offer === void 0 ? void 0 : offer.isTest) === 'boolean')
85
+ return offer.isTest === isTest;
86
+ if (typeof providerIsTest === 'boolean')
87
+ return providerIsTest === isTest;
88
+ return !isTest;
89
+ }
70
90
  /**
71
91
  * Whether a finished order earns a stamp.
72
92
  *
package/package.json CHANGED
@@ -1,37 +1,37 @@
1
1
  {
2
- "name": "sahab-utils",
3
- "version": "1.7.0",
4
- "description": "This package contains types and utils functions",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "scripts": {
8
- "build": "tsc",
9
- "deploy": "npm run build && npm publish",
10
- "test": "npm run build && node tests/loyalty.test.js && node tests/gifts.test.js"
11
- },
12
- "repository": {
13
- "type": "git",
14
- "url": "git+https://github.com/SahabApp/sahab-utils.git"
15
- },
16
- "keywords": [
17
- "sahab"
18
- ],
19
- "author": "Sahab",
20
- "license": "ISC",
21
- "bugs": {
22
- "url": "https://github.com/SahabApp/sahab-utils/issues"
23
- },
24
- "homepage": "https://github.com/SahabApp/sahab-utils#readme",
25
- "files": [
26
- "dist"
27
- ],
28
- "devDependencies": {
29
- "@types/lodash": "^4.17.24",
30
- "typescript": "^6.0.2"
31
- },
32
- "dependencies": {
33
- "firebase": "^10.7.1",
34
- "lodash": "^4.17.21"
35
- },
36
- "packageManager": "yarn@4.9.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538"
2
+ "name": "sahab-utils",
3
+ "version": "1.7.1",
4
+ "description": "This package contains types and utils functions",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "deploy": "npm run build && npm publish",
10
+ "test": "npm run build && node tests/loyalty.test.js && node tests/gifts.test.js"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/SahabApp/sahab-utils.git"
15
+ },
16
+ "keywords": [
17
+ "sahab"
18
+ ],
19
+ "author": "Sahab",
20
+ "license": "ISC",
21
+ "bugs": {
22
+ "url": "https://github.com/SahabApp/sahab-utils/issues"
23
+ },
24
+ "homepage": "https://github.com/SahabApp/sahab-utils#readme",
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "devDependencies": {
29
+ "@types/lodash": "^4.17.24",
30
+ "typescript": "^6.0.2"
31
+ },
32
+ "dependencies": {
33
+ "firebase": "^10.7.1",
34
+ "lodash": "^4.17.21"
35
+ },
36
+ "packageManager": "yarn@4.9.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538"
37
37
  }