@tbox.cn/app-contracts-mall 0.2.0 → 0.9.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.
Files changed (81) hide show
  1. package/README.md +16 -2
  2. package/dist/alipay-activity/cards.d.ts +305 -0
  3. package/dist/assembly.d.ts +31 -6
  4. package/dist/chunk-KIZD6FZ2.js +43 -0
  5. package/dist/deployment.d.ts +32 -33
  6. package/dist/domain/activity.d.ts +64 -0
  7. package/dist/domain/coupon.d.ts +2 -0
  8. package/dist/domain/entitlement.d.ts +53 -0
  9. package/dist/domain/offer.d.ts +111 -0
  10. package/dist/domain/operation.d.ts +22 -0
  11. package/dist/domain/parking.d.ts +195 -12
  12. package/dist/domain/points.d.ts +3 -2
  13. package/dist/domain/shopping-guide.d.ts +201 -0
  14. package/dist/index.d.ts +14 -2
  15. package/dist/member/cards.d.ts +636 -213
  16. package/dist/parking/cards.d.ts +1271 -0
  17. package/dist/promotion/cards.d.ts +2529 -0
  18. package/dist/query-context.d.ts +47 -0
  19. package/dist/runtime.d.ts +11 -2
  20. package/dist/runtime.js +910 -86
  21. package/dist/scope.d.ts +42 -15
  22. package/dist/server/index.d.ts +11 -0
  23. package/dist/server/index.js +80 -0
  24. package/dist/server/mall-context.d.ts +24 -0
  25. package/dist/server/mall-control-plane.d.ts +8 -0
  26. package/dist/server/request-credentials.d.ts +22 -0
  27. package/dist/services/customer-service.d.ts +11 -0
  28. package/dist/services/mall-info.d.ts +26 -0
  29. package/dist/services/member.d.ts +173 -31
  30. package/dist/services/parking.d.ts +105 -12
  31. package/dist/services/promotion.d.ts +100 -4
  32. package/dist/services/shopping-guide.d.ts +97 -0
  33. package/dist/shared/cards.d.ts +42 -0
  34. package/dist/shopping-guide/cards.d.ts +3399 -561
  35. package/package.json +18 -7
  36. package/src/alipay-activity/cards.ts +66 -0
  37. package/src/assembly.ts +103 -0
  38. package/src/deployment.ts +44 -0
  39. package/src/domain/activity.ts +66 -0
  40. package/src/domain/coupon.ts +11 -0
  41. package/src/domain/discount.ts +6 -0
  42. package/src/domain/entitlement.ts +56 -0
  43. package/src/domain/offer.ts +120 -0
  44. package/src/domain/operation.ts +40 -0
  45. package/src/domain/parking.ts +207 -0
  46. package/src/domain/points.ts +15 -0
  47. package/src/domain/shopping-guide.ts +242 -0
  48. package/src/events/index.ts +10 -0
  49. package/src/guard.ts +48 -0
  50. package/src/index.ts +33 -0
  51. package/src/member/cards.ts +209 -0
  52. package/src/parking/cards.ts +233 -0
  53. package/src/promotion/cards.ts +290 -0
  54. package/src/query-context.ts +81 -0
  55. package/src/runtime.ts +41 -0
  56. package/src/scope.ts +92 -0
  57. package/src/server/index.ts +11 -0
  58. package/src/server/mall-context.ts +39 -0
  59. package/src/server/mall-control-plane.ts +56 -0
  60. package/src/server/request-credentials.ts +43 -0
  61. package/src/service-slots.json +23 -0
  62. package/src/services/customer-service.ts +12 -0
  63. package/src/services/mall-info.ts +31 -0
  64. package/src/services/member.ts +366 -0
  65. package/src/services/parking.ts +166 -0
  66. package/src/services/promotion.ts +126 -0
  67. package/src/services/shopping-guide.ts +138 -0
  68. package/src/shared/cards.ts +25 -0
  69. package/src/shopping-guide/cards.ts +438 -0
  70. package/tests/assembly-validate-scope.test.ts +132 -0
  71. package/tests/cards.test.ts +586 -0
  72. package/tests/context-unification.test.ts +73 -0
  73. package/tests/mall-control-plane.test.ts +86 -0
  74. package/tests/member-status.test.ts +197 -0
  75. package/tests/query-context.test.ts +111 -0
  76. package/tests/request-credentials.test.ts +38 -0
  77. package/tests/resolve-primitives.test.ts +55 -0
  78. package/tests/service-slots.test.ts +78 -0
  79. package/tsconfig.build.json +15 -0
  80. package/tsconfig.json +5 -0
  81. package/dist/shopping-guide/ports.d.ts +0 -216
@@ -0,0 +1,207 @@
1
+ /**
2
+ * 停车域模型(015:POC parking 域精华沉淀,TIER1)。
3
+ * 金额一律 cents(number);展示层字符串化(D11)。
4
+ */
5
+
6
+ /** 停车车辆(绑定车) */
7
+ export interface ParkingVehicle {
8
+ readonly vehicleRef: string;
9
+ readonly plateNo: string;
10
+ readonly boundAt?: string;
11
+ /**
12
+ * 是否在场内(可选能力):provider 无入场查询能力时缺省,UI 据此不显示任何入场状态——
13
+ * 缺省与 false 不同义,false 是「查过,不在场」。
14
+ */
15
+ readonly parked?: boolean;
16
+ }
17
+
18
+ /**
19
+ * 入场探测结果元素(可选能力口 ParkingQueryPort.probeParkedVehicles 出参)。
20
+ * 仅含在场车辆;缺席 = 未入场或未知。
21
+ */
22
+ export interface ParkingPresence {
23
+ readonly plateNo: string;
24
+ /** 已停时长(分钟,≥1);provider 给不出时缺省,UI 退回通用计费文案 */
25
+ readonly parkedMinutes?: number;
26
+ }
27
+
28
+ /** 费用明细项 */
29
+ export interface ParkingFeeItem {
30
+ readonly name: string;
31
+ /** 应收(cents) */
32
+ readonly amountCents: number;
33
+ /** 优惠减免(cents,正数) */
34
+ readonly discountCents?: number;
35
+ readonly note?: string;
36
+ }
37
+
38
+ /** 报价快照(revision 乐观锁:权益重选 → 新 revision,旧卡提交被拒) */
39
+ export interface QuoteSnapshot {
40
+ readonly quoteRef: string;
41
+ readonly plateNo: string;
42
+ readonly mallId: string;
43
+ readonly entryAt?: string;
44
+ readonly exitAt?: string;
45
+ readonly feeItems: readonly ParkingFeeItem[];
46
+ /** 应收合计(cents) */
47
+ readonly totalCents: number;
48
+ /** 已减免合计(cents) */
49
+ readonly discountCents: number;
50
+ /** 应付(total - discount,cents) */
51
+ readonly payableCents: number;
52
+ /** 已生效权益(benefitRef → 标题) */
53
+ readonly appliedBenefits: ReadonlyArray<{
54
+ readonly benefitRef: string;
55
+ readonly title: string;
56
+ readonly discountCents: number;
57
+ }>;
58
+ /** 乐观锁版本(reprice 递增) */
59
+ readonly revision: number;
60
+ readonly paymentState: 'UNPAID' | 'PAYING' | 'PAID';
61
+ readonly expiresAt?: string;
62
+ /**
63
+ * 支付交接包(provider 有跳转支付页能力时给出):客户端卡据 kind 调壳 tbox 能力收款——
64
+ * `kind:'pay'` → `openParkingPay`(传 orderInfo,壳负责跳确认页/收银台);
65
+ * `kind:'unpaid'` → `openParkingUnpaidOrder`(传 orderNo,壳打开已有待支付订单详情页)。
66
+ * provider 无此语义时缺省(调用方退回内部建单/收银台流程)。
67
+ */
68
+ readonly payHandoff?: {
69
+ readonly kind: 'pay' | 'unpaid';
70
+ readonly parkingStoreId?: string;
71
+ /** kind='pay' 时给——传给壳 `openParkingPay` 的订单信息 */
72
+ readonly orderInfo?: ParkingPayOrderInfo;
73
+ /** kind='unpaid' 时给——已有订单号(= 厂商 tradeOrderNo,与壳协议 orderNo 同号)传给壳 `openParkingUnpaidOrder` */
74
+ readonly orderNo?: string;
75
+ };
76
+ }
77
+
78
+ /**
79
+ * 厂商协议 `openParkingPay` 的 orderInfo(从 advancePaymentOrder 聚合)。
80
+ * 壳用这些字段自己拼确认页,不再回查费。
81
+ */
82
+ export interface ParkingPayOrderInfo {
83
+ /** 停车秒数 */
84
+ readonly staySecond?: number;
85
+ /** 停车费,单位分 */
86
+ readonly parkingFee?: number;
87
+ /** 车牌绑定状态 */
88
+ readonly bindingStatus?: number;
89
+ /** 车牌 */
90
+ readonly plateNumber?: string;
91
+ /** 1=在场缴费,2=逃费/欠费 */
92
+ readonly orderType: number;
93
+ /** 车场侧订单号 */
94
+ readonly spParkingOrderId?: string;
95
+ /** 车场 ID(协议已定 string) */
96
+ readonly parkingId: string;
97
+ /** 入场时间 */
98
+ readonly entranceTime?: string;
99
+ /** 逗号分隔的能力枚举,如 "LEVEL_DISCOUNT,POINT_DISCOUNT,COUPON" */
100
+ readonly supportDiscount?: string;
101
+ }
102
+
103
+ /** 可选权益(用户可勾选参与 reprice) */
104
+ export interface ParkingBenefit {
105
+ readonly benefitRef: string;
106
+ readonly title: string;
107
+ readonly description?: string;
108
+ /** 是否已默认勾选生效 */
109
+ readonly autoSelected: boolean;
110
+ readonly estimatedDiscountCents?: number;
111
+ /** Provider 归一化后的权益类型;不得由客户端从标题猜测。 */
112
+ readonly kind?: 'points' | 'discount' | 'coupon' | 'other';
113
+ /**
114
+ * 与本权益互斥的权益类型(Provider 归一化下发;客户端不得从标题或类型推断)。
115
+ * 三类优惠(券 / 积分抵扣 / 等级权益)默认可叠加,互斥是厂商侧的按券配置——
116
+ * 部分停车券标记「不可与积分叠加」即 ['points']。互斥判定必须双向:勾选任一方
117
+ * 都要撤下另一方(见客户端 resolveBenefitSelection)。
118
+ */
119
+ readonly exclusiveWithKinds?: readonly ('points' | 'discount' | 'coupon')[];
120
+ /** 仅在 Provider 返回权威兑换计划时提供。 */
121
+ readonly requiredPoints?: number;
122
+ /** 与 requiredPoints 对应的权威预估应付金额。 */
123
+ readonly previewPayableCents?: number;
124
+ /** 不可与哪些 benefitRef 同时生效;为空数组表示与所有同类别权益(如所有 coupon)互斥。 */
125
+ readonly exclusiveWith?: readonly string[];
126
+ /** 是否可与优惠券叠加(仅积分类权益有意义);undefined 表示未知/默认允许。 */
127
+ readonly stacksWithCoupon?: boolean;
128
+ }
129
+
130
+ /** 寻车定位 */
131
+ export interface ParkingLocation {
132
+ readonly floorName?: string;
133
+ readonly zoneName?: string;
134
+ readonly spaceNo?: string;
135
+ readonly walkingRoute?: string;
136
+ readonly mapUrl?: string;
137
+ }
138
+
139
+ /** 缴费记录条目 */
140
+ export interface ParkingPaymentRecord {
141
+ readonly recordRef: string;
142
+ readonly plateNo: string;
143
+ /** 实付(cents) */
144
+ readonly amountCents: number;
145
+ readonly paidAt: string;
146
+ readonly status: 'PAID' | 'REFUNDED' | 'CLOSED' | 'UNKNOWN';
147
+ /** 厂商原始交易状态文案(如「交易关闭」「交易完成」,供卡片直接展示) */
148
+ readonly statusText?: string;
149
+ readonly parkName?: string;
150
+ readonly plazaName?: string;
151
+ readonly entryAt?: string;
152
+ readonly exitAt?: string;
153
+ readonly payOrderNoMasked?: string;
154
+ /** 厂商订单是否已完成(开票资格的前置条件) */
155
+ readonly orderCompleted?: boolean;
156
+ /** 当前是否允许申请开票(同时受停车场配置与订单状态约束) */
157
+ readonly invoiceEligible?: boolean;
158
+ /** 是否已开票/已提交开票申请 */
159
+ readonly invoiceIssued?: boolean;
160
+ }
161
+
162
+ export interface ParkingRecordPage {
163
+ readonly items: readonly ParkingPaymentRecord[];
164
+ readonly total: number;
165
+ readonly page: number;
166
+ readonly pageSize: number;
167
+ readonly hasMore: boolean;
168
+ }
169
+
170
+ /** 停车场综合信息(四合一 kind) */
171
+ export interface ParkingInfo {
172
+ readonly kind: 'chargeRules' | 'benefitPolicy' | 'pendingOrder' | 'vehicleLocation';
173
+ readonly title: string;
174
+ /** 通用键值展示(余位数/首小时费率/会员权益政策等) */
175
+ readonly entries: ReadonlyArray<{
176
+ readonly label: string;
177
+ readonly value: string;
178
+ }>;
179
+ /** pendingOrder 时的待支付单引用 */
180
+ readonly pendingQuote?: QuoteSnapshot;
181
+ }
182
+
183
+ /**
184
+ * 支付操作(StateStore 持久化单据):
185
+ * PAYING →(reconcile 权威)→ PAID / CANCELLED;UNKNOWN = 厂商态不明(悬挂,下次交互收口,V2)。
186
+ */
187
+ export interface PaymentOperation {
188
+ /** 对外不透明引用;卡片/客户端只能持有该值 */
189
+ readonly paymentRef: string;
190
+ /** 厂商支付引用,仅服务端持久化并用于回查 */
191
+ readonly providerPaymentRef: string;
192
+ readonly quoteRef: string;
193
+ readonly plateNo: string;
194
+ /** 支付操作归属主体;与 mallId 共同用于服务端授权 */
195
+ readonly subjectId: string;
196
+ readonly mallId: string;
197
+ readonly payableCents: number;
198
+ /** 厂商支付单号(masked 展示) */
199
+ readonly payOrderNoMasked?: string;
200
+ /** 厂商支付组件流水 ID(GetPaySign 产出;结果上报 UploadPayParamsResult 回传) */
201
+ readonly payOrderFlowId?: string;
202
+ readonly status: 'PAYING' | 'PAID' | 'CANCELLED' | 'UNKNOWN';
203
+ readonly createdAt: string;
204
+ readonly paidAt?: string;
205
+ /** 入场时间(建单时自报价带入):回执要算停车时长,而报价此时已不可达 */
206
+ readonly entryAt?: string;
207
+ }
@@ -0,0 +1,15 @@
1
+ /** 会员积分(商圈领域 DTO) */
2
+ export interface Points {
3
+ userId: string;
4
+ /** 当前积分余额 */
5
+ balance: number;
6
+ /** 厂商返回的真实会员标签;不得由积分余额推导。 */
7
+ membershipLabel?: string;
8
+ }
9
+
10
+ /** 积分余额变动结果 */
11
+ export interface PointsChangeResult {
12
+ success: boolean;
13
+ balance: number;
14
+ reason?: string;
15
+ }
@@ -0,0 +1,242 @@
1
+ /**
2
+ * 商品导购域模型(shopping-guide domain model,TIER1)。
3
+ * 商品、门店(shop)、位置、类目、知识库、人工导购等核心业务实体。
4
+ * Port 接口见 services/shopping-guide.ts;卡片数据结构见 shopping-guide/cards.ts。
5
+ */
6
+ import type { FreeCouponClaimMode } from './coupon';
7
+
8
+ // ===== 共享值对象 =====
9
+
10
+ /** 货币金额值对象 */
11
+ export interface MoneyRecord {
12
+ readonly currency: 'CNY';
13
+ readonly amountMinor: number;
14
+ readonly display: string;
15
+ }
16
+
17
+ /** 门店位置值对象(零坐标依赖,POC R5;poiId 有值时可升级为坐标导航) */
18
+ export interface ShopLocationRecord {
19
+ readonly buildingName?: string;
20
+ readonly floorName?: string;
21
+ readonly unitName?: string;
22
+ readonly displayText: string;
23
+ readonly poiId?: string;
24
+ }
25
+ /** @deprecated 使用 ShopLocationRecord */
26
+ export type MerchantLocationRecord = ShopLocationRecord;
27
+
28
+ // ===== 商品目录域 =====
29
+
30
+ /** 商品实体 */
31
+ export interface ProductRecord {
32
+ readonly productId: string;
33
+ readonly name: string;
34
+ readonly description?: string;
35
+ readonly imageUrls: readonly string[];
36
+ readonly brand?: string;
37
+ readonly categoryPath: readonly string[];
38
+ readonly price: ProductPrice;
39
+ readonly availability: ProductAvailability;
40
+ readonly merchant: ProductShopRef;
41
+ readonly labels: readonly string[];
42
+ readonly attributes: ReadonlyArray<ProductAttribute>;
43
+ readonly promotionFacts: readonly string[];
44
+ readonly observedAt: string;
45
+ }
46
+
47
+ export interface ProductPrice {
48
+ readonly sale?: MoneyRecord;
49
+ readonly original?: MoneyRecord;
50
+ readonly promotion?: MoneyRecord;
51
+ }
52
+
53
+ export interface ProductAvailability {
54
+ readonly status: 'in_stock' | 'out_of_stock' | 'limited' | 'unknown';
55
+ readonly label: string;
56
+ readonly marketable: boolean;
57
+ readonly observedAt: string;
58
+ }
59
+
60
+ /** 商品上的门店引用(轻量,不含完整门店信息) */
61
+ export interface ProductShopRef {
62
+ readonly merchantId: string;
63
+ readonly name: string;
64
+ readonly location?: ShopLocationRecord;
65
+ }
66
+ /** @deprecated 使用 ProductShopRef */
67
+ export type ProductMerchantRef = ProductShopRef;
68
+
69
+ export interface ProductAttribute {
70
+ readonly name: string;
71
+ readonly value: string;
72
+ }
73
+
74
+ export interface ProductFacetsRecord {
75
+ readonly brands: ReadonlyArray<FacetOption>;
76
+ readonly categories: ReadonlyArray<FacetOption>;
77
+ readonly priceRanges: ReadonlyArray<PriceRangeFacet>;
78
+ readonly floors: ReadonlyArray<FloorFacetOption>;
79
+ }
80
+
81
+ export interface FacetOption {
82
+ readonly code: string;
83
+ readonly name: string;
84
+ readonly count: number;
85
+ }
86
+
87
+ export interface PriceRangeFacet {
88
+ readonly minMinor: number;
89
+ readonly maxMinor: number;
90
+ readonly displayLabel: string;
91
+ readonly count: number;
92
+ }
93
+
94
+ export interface FloorFacetOption {
95
+ readonly code: string;
96
+ readonly displayName: string;
97
+ readonly count: number;
98
+ }
99
+
100
+ // ===== 门店目录域 =====
101
+
102
+ /** 门店关联优惠(来自 couponList) */
103
+ export interface ShopCoupon {
104
+ readonly name: string;
105
+ readonly imageUrl?: string;
106
+ /** 去 HTML 标签后的纯文本描述(可选) */
107
+ readonly description?: string;
108
+ /** 券面值(元,parValue/100) */
109
+ readonly faceValue?: number;
110
+ /** 售价(元,price/100;0 = 免费领取) */
111
+ readonly salePrice?: number;
112
+ /** 适用业态列表(useBusinessType) */
113
+ readonly applicableCategories?: string[];
114
+ /** 领取后有效小时数(expiredAfterHours) */
115
+ readonly validHours?: number;
116
+ /** 可用时间文案(useWeekTime 解析:星期段 + st-et 截前 5 位,provider 直出) */
117
+ readonly usageTimeText?: string;
118
+ /** 券的小程序详情入口;付费券固定跳转,免费券由 freeCouponClaimMode 决定。 */
119
+ readonly purchaseUrl?: string;
120
+ /** 仅免费券消费;缺省保持既有直领语义。 */
121
+ readonly freeCouponClaimMode?: FreeCouponClaimMode;
122
+ /**
123
+ * 营销域券引用(厂商 offerRef 形如 `offer:${couponNo}`)——厂商 couponList 返回券编号时提供;
124
+ * DIRECT 模式下经 promotion.acquire 同链路领取。
125
+ */
126
+ readonly offerRef?: string;
127
+ }
128
+
129
+ /** 门店实体(聚合根) */
130
+ export interface ShopRecord {
131
+ readonly merchantId: string;
132
+ readonly name: string;
133
+ readonly logoUrl?: string;
134
+ readonly coverUrls: readonly string[];
135
+ readonly brand?: string;
136
+ readonly businessCategories: readonly string[];
137
+ readonly location: ShopLocationRecord;
138
+ readonly status: ShopStatus;
139
+ readonly description?: string;
140
+ readonly contactInfo?: ReadonlyArray<ContactChannel>;
141
+ readonly services: readonly string[];
142
+ readonly promotionFacts: readonly string[];
143
+ /** 门店关联优惠券列表(来自 provider couponList;有值时展示) */
144
+ readonly coupons?: ReadonlyArray<ShopCoupon>;
145
+ readonly observedAt: string;
146
+ }
147
+ /** @deprecated 使用 ShopRecord */
148
+ export type MerchantRecord = ShopRecord;
149
+
150
+ export interface ShopStatus {
151
+ readonly code: 'enabled' | 'disabled' | 'unknown';
152
+ readonly label: string;
153
+ readonly observedAt: string;
154
+ }
155
+ /** @deprecated 使用 ShopStatus */
156
+ export type MerchantStatus = ShopStatus;
157
+
158
+ export interface ContactChannel {
159
+ readonly channel: string;
160
+ readonly value: string;
161
+ }
162
+
163
+ // ===== 业态分类域 =====
164
+
165
+ export interface CategoryRecord {
166
+ readonly code: string;
167
+ readonly name: string;
168
+ readonly description?: string;
169
+ /** 类目图标 URL(C 端 GetListMallCategory 返回;空字符串时由前端展示默认图标) */
170
+ readonly iconUrl?: string;
171
+ readonly merchantCount: number;
172
+ readonly subCategories?: ReadonlyArray<SubCategoryRecord>;
173
+ }
174
+
175
+ export interface SubCategoryRecord {
176
+ readonly code: string;
177
+ readonly name: string;
178
+ readonly merchantCount: number;
179
+ }
180
+
181
+ // ===== 楼栋目录域 =====
182
+
183
+ export interface MallDirectoryRecord {
184
+ readonly mallId: string;
185
+ readonly mallName: string;
186
+ readonly buildings: ReadonlyArray<BuildingRecord>;
187
+ readonly observedAt: string;
188
+ }
189
+
190
+ export interface BuildingRecord {
191
+ readonly buildingCode: string;
192
+ readonly buildingName: string;
193
+ readonly floors: ReadonlyArray<FloorRecord>;
194
+ }
195
+
196
+ export interface FloorRecord {
197
+ readonly floorCode: string;
198
+ readonly floorName: string;
199
+ readonly businessCategories: readonly string[];
200
+ readonly merchantCount: number;
201
+ }
202
+
203
+ // ===== 知识库 & 客服域 =====
204
+
205
+ export interface FaqEntry {
206
+ readonly question: string;
207
+ readonly answer: string;
208
+ readonly category?: string;
209
+ readonly relevanceScore: number;
210
+ }
211
+
212
+ export interface KnowledgeEntry {
213
+ readonly content: string;
214
+ readonly title?: string;
215
+ readonly score: number;
216
+ }
217
+
218
+ // ===== 人工导购域 =====
219
+
220
+ export interface HumanGuideRecord {
221
+ readonly guideId: string;
222
+ readonly name: string;
223
+ readonly title?: string;
224
+ readonly avatarUrl?: string;
225
+ readonly contactInfo?: ReadonlyArray<ContactChannel>;
226
+ readonly available: boolean;
227
+ }
228
+
229
+ // ===== 附近商场域 =====
230
+
231
+ export interface NearbyMallRecord {
232
+ readonly mallId: string;
233
+ readonly name: string;
234
+ readonly address: string;
235
+ readonly distanceKm?: number;
236
+ readonly status: NearbyMallStatus;
237
+ }
238
+
239
+ export interface NearbyMallStatus {
240
+ readonly code: 'open' | 'closed' | 'unknown';
241
+ readonly label: string;
242
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * MallEventMap:商圈跨模块事件(类型化事件总线 keyof 约束,001 §5.4)。
3
+ * 用 type(非 interface)以获得隐式索引签名,满足 SDK EventMap(Record<string, unknown>)约束。
4
+ */
5
+ export type MallEventMap = {
6
+ /** 会员等级变更 */
7
+ 'member.level.changed': { userId: string; newLevel: 'silver' | 'gold' | 'platinum' };
8
+ /** 停车券核销 */
9
+ 'parking.coupon.used': { userId: string; couponId: string; amount: number };
10
+ };
package/src/guard.ts ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 商圈守卫(011:location/user 领域守卫,TIER1 运行时):
3
+ * 卡片/工具入参中的位置与用户字段防御解析。
4
+ * 平台存储数据不可全信——一切外部形状先过 zod。
5
+ */
6
+ import { z } from 'zod';
7
+
8
+ /** 商圈位置(经纬度字符串化,D11:数值一律字符串化) */
9
+ export interface MallLocation {
10
+ latitude: string;
11
+ longitude: string;
12
+ /** 可选商圈 id(位置所属 mall) */
13
+ mallId?: string;
14
+ /** 可选名称(POI) */
15
+ name?: string;
16
+ }
17
+
18
+ export const mallLocationSchema = z.object({
19
+ latitude: z.string().min(1),
20
+ longitude: z.string().min(1),
21
+ mallId: z.string().optional(),
22
+ name: z.string().optional(),
23
+ });
24
+
25
+ /** 解析失败返回 undefined(调用方降级「位置未知」文案) */
26
+ export function parseMallLocation(raw: unknown): MallLocation | undefined {
27
+ if (!raw || typeof raw !== 'object') return undefined;
28
+ const result = mallLocationSchema.safeParse(raw);
29
+ return result.success ? result.data : undefined;
30
+ }
31
+
32
+ /** 商圈用户标识(D11 字符串化 user 字段守卫) */
33
+ export interface MallUserRef {
34
+ userId: string;
35
+ /** 可选 mall 会员主体 id */
36
+ subjectId?: string;
37
+ }
38
+
39
+ export const mallUserRefSchema = z.object({
40
+ userId: z.string().min(1),
41
+ subjectId: z.string().optional(),
42
+ });
43
+
44
+ export function parseMallUserRef(raw: unknown): MallUserRef | undefined {
45
+ if (!raw || typeof raw !== 'object') return undefined;
46
+ const result = mallUserRefSchema.safeParse(raw);
47
+ return result.success ? result.data : undefined;
48
+ }
package/src/index.ts ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @tbox.cn/app-contracts-mall:商圈领域契约(TIER1,types + runtime)。
3
+ * 消费方(module-* / 模板装配点)只依赖本契约,
4
+ * 不依赖任何模块实现包——结构类型子集接口 + 事件总线破环双向依赖。
5
+ * runtime 值(scope 解析/装配器/守卫)经 ./runtime 导出(dist/runtime.js)。
6
+ */
7
+ export * from './domain/points';
8
+ export * from './domain/coupon';
9
+ export * from './domain/discount';
10
+ export * from './domain/parking';
11
+ export * from './domain/offer';
12
+ export * from './domain/entitlement';
13
+ export * from './domain/activity';
14
+ export * from './domain/operation';
15
+ export * from './services/member';
16
+ export * from './services/parking';
17
+ export * from './services/promotion';
18
+ export * from './services/mall-info';
19
+ export * from './events';
20
+ export * from './scope';
21
+ export * from './query-context';
22
+ export * from './deployment';
23
+ export * from './assembly';
24
+ export * from './guard';
25
+ export * from './shopping-guide/cards';
26
+ export * from './shared/cards';
27
+ export * from './domain/shopping-guide';
28
+ export * from './services/shopping-guide';
29
+ export * from './services/customer-service';
30
+ export * from './member/cards';
31
+ export * from './promotion/cards';
32
+ export * from './parking/cards';
33
+ export * from './alipay-activity/cards';