@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
package/dist/runtime.js CHANGED
@@ -1,64 +1,183 @@
1
- // src/scope.ts
2
- import { z } from "zod";
3
- var MALL_SCOPE_KEY = "mall";
4
- var mallScopeSchema = z.object({
5
- miniAppId: z.string().min(1),
6
- mallId: z.string().min(1),
7
- subjectId: z.string().optional()
8
- });
9
- function parseMallScope(attributes) {
10
- const raw = attributes?.[MALL_SCOPE_KEY];
11
- if (!raw || typeof raw !== "object") return void 0;
12
- const result = mallScopeSchema.safeParse(raw);
13
- return result.success ? result.data : void 0;
1
+ import {
2
+ MALL_SCOPE_KEY,
3
+ extractMallScope,
4
+ mallScopeOf,
5
+ mallScopeSchema,
6
+ mallSlot,
7
+ parseMallScope,
8
+ readLoginMallId
9
+ } from "./chunk-KIZD6FZ2.js";
10
+
11
+ // src/query-context.ts
12
+ function mallScopeOrEmpty(reqCtx) {
13
+ return extractMallScope(reqCtx) ?? { miniAppId: "", mallId: "" };
14
14
  }
15
- function extractMallScope(ctx) {
16
- return parseMallScope(ctx.attributes);
15
+ function mallSubjectIdOf(reqCtx) {
16
+ return reqCtx.identity && reqCtx.identity.source !== "anonymous" ? reqCtx.identity.userId : void 0;
17
17
  }
18
- function requireMallScope(ctx) {
19
- return ctx.attributes[MALL_SCOPE_KEY];
18
+ function withMallScopeFromQuery(reqCtx, query, opts) {
19
+ const text = (value) => typeof value === "string" && value.trim() ? value.trim() : void 0;
20
+ const mallId = text(query["mallId"]);
21
+ if (!mallId) return reqCtx;
22
+ const miniAppId = text(query["miniAppId"]) ?? text(opts?.miniAppId);
23
+ return {
24
+ ...reqCtx,
25
+ attributes: {
26
+ ...reqCtx.attributes,
27
+ [MALL_SCOPE_KEY]: miniAppId ? { mallId, miniAppId } : { mallId }
28
+ }
29
+ };
30
+ }
31
+ function toMallQueryContext(reqCtx) {
32
+ const subjectId = mallSubjectIdOf(reqCtx);
33
+ return {
34
+ scope: mallScopeOrEmpty(reqCtx),
35
+ ...subjectId ? { subjectId } : {},
36
+ requestContext: reqCtx
37
+ };
20
38
  }
21
39
 
22
40
  // src/assembly.ts
41
+ var AUTH_LOGIN_SERVICE = "auth.alipay-login";
42
+ function isValidMallShape(attributes) {
43
+ const mall = attributes[MALL_SCOPE_KEY];
44
+ if (!mall || typeof mall !== "object") return true;
45
+ const mallId = mall.mallId;
46
+ return typeof mallId === "string" && mallId.length > 0;
47
+ }
23
48
  function createMallRuntimeAssembly(controlPlane) {
24
- const mallIds = new Set(controlPlane.malls.map((m) => m.mallId));
25
49
  return {
26
50
  extractScopeKey(ctx) {
27
51
  const scope = extractMallScope(ctx);
28
- if (!scope) throw new Error("Mall scope is required");
29
- return scope.mallId;
52
+ return scope?.mallId ?? "";
30
53
  },
31
54
  validateScope(attributes) {
32
- const scope = parseMallScope(attributes);
33
- return scope !== void 0 && mallIds.has(scope.mallId);
55
+ const ok = isValidMallShape(attributes);
56
+ if (!ok) {
57
+ console.error(
58
+ "[MALL] HELLO context \u5F62\u72B6\u975E\u6CD5\uFF08\u9700 mall.mallId \u975E\u7A7A\u2014\u2014URL \u53C2\u6570 ?mallId=\uFF1BminiAppId \u53EF\u9009\uFF09"
59
+ );
60
+ }
61
+ return ok;
34
62
  },
35
63
  buildScope(attributes) {
36
64
  const scope = parseMallScope(attributes);
37
65
  if (!scope) return {};
38
- return { miniAppId: scope.miniAppId, mallId: scope.mallId };
66
+ return {
67
+ mallId: scope.mallId,
68
+ ...scope.miniAppId !== void 0 ? { miniAppId: scope.miniAppId } : {}
69
+ };
39
70
  },
40
71
  extractMallScope,
41
- requireMallScope,
42
72
  controlPlane
43
73
  };
44
74
  }
75
+ function createMallContextValidator() {
76
+ return isValidMallShape;
77
+ }
78
+
79
+ // src/services/member.ts
80
+ var MEMBER_ACCOUNT_SERVICE = "member.account";
81
+ var MEMBER_PROFILE_SERVICE = "member.profile";
82
+ var MEMBER_CARD_SERVICE = "member.card";
83
+ var MEMBER_BENEFITS_SERVICE = "member.benefits";
84
+ var MEMBER_ENROLLMENT_SERVICE = "member.enrollment";
85
+ function classifyMemberOutcome(identity, account) {
86
+ if (identity?.source === "anonymous") return "unauthenticated";
87
+ if (!account) return "unknown";
88
+ if (account.authState === "unauthenticated") return "unauthenticated";
89
+ return account.state;
90
+ }
91
+ function externalMemberRefOf(account) {
92
+ return account.primaryMallCardNo ?? account.memberRef;
93
+ }
94
+ var MEMBER_GATE_NOTICES = {
95
+ unauthenticated: "\u8BF7\u5148\u767B\u5F55\u540E\u518D\u4F7F\u7528\u8BE5\u670D\u52A1",
96
+ not_enrolled: "\u5B8C\u6210\u5165\u4F1A\u540E\u5373\u53EF\u4F7F\u7528\u8BE5\u670D\u52A1",
97
+ closed: "\u91CD\u65B0\u5165\u4F1A\u540E\u53EF\u6062\u590D\u4F7F\u7528\u8BE5\u670D\u52A1"
98
+ };
99
+ function memberGateCardOf(userId, status) {
100
+ const { outcome } = status;
101
+ if (outcome === "unauthenticated") {
102
+ const loginUrl = status.loginUrl?.trim() || void 0;
103
+ return {
104
+ cardType: "member-login-cta",
105
+ data: { title: "\u767B\u5F55\u540E\u7EE7\u7EED", ...loginUrl ? { loginUrl } : {} },
106
+ // note 契约(W7,2026-09-01):主体+动作(模型据此答话转述——「点击卡片登录」)
107
+ note: "\u672A\u767B\u5F55 \xB7 \u70B9\u51FB\u5361\u7247\u767B\u5F55"
108
+ };
109
+ }
110
+ if (outcome !== "not_enrolled" && outcome !== "closed") return void 0;
111
+ if (!userId) return void 0;
112
+ const enrollUrl = status.enrollUrl?.trim() || void 0;
113
+ return {
114
+ cardType: "member-enrollment-cta",
115
+ data: {
116
+ userId,
117
+ authState: "authenticated",
118
+ state: outcome,
119
+ title: "\u5165\u4F1A\u540E\u7EE7\u7EED",
120
+ ...enrollUrl ? { enrollUrl } : {}
121
+ },
122
+ note: outcome === "not_enrolled" ? "\u672A\u5165\u4F1A \xB7 \u70B9\u51FB\u5361\u7247\u5B8C\u6210\u5165\u4F1A" : "\u5DF2\u9000\u4F1A \xB7 \u70B9\u51FB\u5361\u7247\u91CD\u65B0\u5165\u4F1A"
123
+ };
124
+ }
125
+ async function resolveMemberGate(factory, reqCtx) {
126
+ if (!factory) return void 0;
127
+ let status;
128
+ try {
129
+ status = await factory(reqCtx);
130
+ } catch {
131
+ return void 0;
132
+ }
133
+ const { outcome } = status;
134
+ if (outcome !== "unauthenticated" && outcome !== "not_enrolled" && outcome !== "closed") {
135
+ return void 0;
136
+ }
137
+ const card = memberGateCardOf(reqCtx.identity?.userId ?? "", status);
138
+ return {
139
+ notice: MEMBER_GATE_NOTICES[outcome],
140
+ ...card ? { card } : {}
141
+ };
142
+ }
143
+
144
+ // src/services/parking.ts
145
+ var PARKING_QUERY_SERVICE = "parking.query";
146
+ var PARKING_PAYMENT_SERVICE = "parking.payment";
147
+ var PARKING_VEHICLE_SERVICE = "parking.vehicle";
148
+
149
+ // src/services/promotion.ts
150
+ var PROMOTION_OFFERS_SERVICE = "promotion.offers";
151
+ var PROMOTION_ENTITLEMENTS_SERVICE = "promotion.entitlements";
152
+ var PROMOTION_ACTIVITIES_SERVICE = "promotion.activities";
153
+ var PROMOTION_ACQUISITION_SERVICE = "promotion.acquisition";
154
+ var PROMOTION_ACTIVITY_ROUTING_POLICY = "promotion.activity-routing";
155
+
156
+ // src/services/shopping-guide.ts
157
+ var SHOPPING_CATALOG_SERVICE = "shopping-guide.catalog";
158
+ var SHOPPING_SHOPS_SERVICE = "shopping-guide.shops";
159
+ var SHOPPING_CATEGORIES_SERVICE = "shopping-guide.categories";
160
+ var SHOPPING_DIRECTORY_SERVICE = "shopping-guide.directory";
161
+
162
+ // src/services/mall-info.ts
163
+ var MALL_INFO_SERVICE = "mall.info";
45
164
 
46
165
  // src/guard.ts
47
- import { z as z2 } from "zod";
48
- var mallLocationSchema = z2.object({
49
- latitude: z2.string().min(1),
50
- longitude: z2.string().min(1),
51
- mallId: z2.string().optional(),
52
- name: z2.string().optional()
166
+ import { z } from "zod";
167
+ var mallLocationSchema = z.object({
168
+ latitude: z.string().min(1),
169
+ longitude: z.string().min(1),
170
+ mallId: z.string().optional(),
171
+ name: z.string().optional()
53
172
  });
54
173
  function parseMallLocation(raw) {
55
174
  if (!raw || typeof raw !== "object") return void 0;
56
175
  const result = mallLocationSchema.safeParse(raw);
57
176
  return result.success ? result.data : void 0;
58
177
  }
59
- var mallUserRefSchema = z2.object({
60
- userId: z2.string().min(1),
61
- subjectId: z2.string().optional()
178
+ var mallUserRefSchema = z.object({
179
+ userId: z.string().min(1),
180
+ subjectId: z.string().optional()
62
181
  });
63
182
  function parseMallUserRef(raw) {
64
183
  if (!raw || typeof raw !== "object") return void 0;
@@ -68,6 +187,23 @@ function parseMallUserRef(raw) {
68
187
 
69
188
  // src/shopping-guide/cards.ts
70
189
  import { z as z3 } from "zod";
190
+
191
+ // src/shared/cards.ts
192
+ import { z as z2 } from "zod";
193
+ var actionDraftSchema = z2.discriminatedUnion("kind", [
194
+ z2.object({
195
+ kind: z2.literal("send"),
196
+ label: z2.string().min(1),
197
+ /** 发给服务端 AI 的完整指令(可含隐藏上下文如 merchantId);缺省用 label */
198
+ value: z2.string().optional(),
199
+ /** 用户气泡展示文本(有值时 sendMessage 走 visible=false 隐藏,只展示此文本为气泡副本);
200
+ * 缺省则 visible=true,直接展示 value/label */
201
+ visibleValue: z2.string().optional()
202
+ }),
203
+ z2.object({ kind: z2.literal("link"), label: z2.string().min(1), url: z2.string().min(1) })
204
+ ]);
205
+
206
+ // src/shopping-guide/cards.ts
71
207
  var httpsUrlSchema = z3.string().regex(/^https:\/\//).max(2048);
72
208
  var isoDateTimeSchema = z3.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/);
73
209
  var moneySchema = z3.object({
@@ -96,22 +232,34 @@ var merchantLocationSchema = z3.object({
96
232
  displayText: z3.string().min(1),
97
233
  poiId: z3.string().optional()
98
234
  });
235
+ var shopLocationSchema = merchantLocationSchema;
99
236
  var merchantStatusSchema = z3.object({
100
237
  code: z3.enum(["enabled", "disabled", "unknown"]),
101
238
  label: z3.string().min(1),
102
239
  observedAt: isoDateTimeSchema
103
240
  });
241
+ var shopStatusSchema = merchantStatusSchema;
104
242
  var pageInfoSchema = z3.object({
105
243
  page: z3.number().int().min(1),
106
- pageSize: z3.number().int().min(1).max(100),
244
+ // max 200(0.7.5 放宽,原 100):品牌导览常驻入口经 port 直调 pageSize=200 一次拉全量,
245
+ // provider 回显值入 pageInfo 需过卡 schema(card-emitter safeParse);向后兼容(旧值域 ⊂ 新值域)
246
+ pageSize: z3.number().int().min(1).max(200),
107
247
  total: z3.number().int().min(0),
108
248
  hasMore: z3.boolean()
109
249
  });
110
250
  var refinementSchema = z3.object({ label: z3.string().min(1), queryText: z3.string().min(1) });
111
- var actionDraftSchema = z3.object({
112
- actionId: z3.string().min(1),
113
- label: z3.string().min(1),
114
- input: z3.record(z3.string(), z3.unknown()).optional()
251
+ var shopCouponSchema = z3.object({
252
+ name: z3.string().min(1),
253
+ imageUrl: httpsUrlSchema.optional(),
254
+ description: z3.string().optional(),
255
+ faceValue: z3.number().optional(),
256
+ salePrice: z3.number().optional(),
257
+ applicableCategories: z3.array(z3.string()).optional(),
258
+ validHours: z3.number().optional(),
259
+ usageTimeText: z3.string().optional(),
260
+ purchaseUrl: z3.string().max(2048).optional(),
261
+ freeCouponClaimMode: z3.enum(["DIRECT", "REDIRECT"]).optional(),
262
+ offerRef: z3.string().min(1).optional()
115
263
  });
116
264
  var productListCardDataSchema = z3.object({
117
265
  context: z3.enum(["recommendation", "search", "similar", "history"]),
@@ -146,9 +294,14 @@ var productListCardDataSchema = z3.object({
146
294
  pageInfo: pageInfoSchema.optional(),
147
295
  refinements: z3.array(refinementSchema)
148
296
  });
149
- var merchantListCardDataSchema = z3.object({
297
+ var shopListCardDataSchema = z3.object({
150
298
  context: z3.enum(["recommendation", "search"]),
299
+ /** mall scope 透传:供客户端侧边栏详情 HTTP 请求携带 mallId 与 miniAppId(工具执行时注入) */
300
+ mallId: z3.string().optional(),
301
+ /** 小程序 appId(miniAppId 唯一真值透传;HTTP /shop-detail 鉴权用) */
302
+ miniAppId: z3.string().optional(),
151
303
  summary: z3.string().optional(),
304
+ categoryTabs: z3.array(z3.object({ code: z3.string(), name: z3.string() })).optional(),
152
305
  items: z3.array(
153
306
  z3.object({
154
307
  merchantId: z3.string(),
@@ -159,17 +312,21 @@ var merchantListCardDataSchema = z3.object({
159
312
  businessCategories: z3.array(z3.string()),
160
313
  location: merchantLocationSchema,
161
314
  status: merchantStatusSchema,
315
+ contactInfo: z3.array(z3.object({ channel: z3.string(), value: z3.string() })).optional(),
162
316
  services: z3.array(z3.string()),
163
317
  promotionFacts: z3.array(z3.string()),
164
318
  reasons: z3.array(reasonItemSchema).optional(),
165
319
  evidence: z3.array(evidenceSchema).optional(),
166
- itemActions: z3.array(actionDraftSchema)
320
+ itemActions: z3.array(actionDraftSchema),
321
+ /** 门店关联优惠券(列表卡透传,供点击下钻时直接展示,避免二次请求) */
322
+ coupons: z3.array(shopCouponSchema).optional()
167
323
  })
168
324
  ),
169
325
  noResultsReason: z3.string().optional(),
170
326
  pageInfo: pageInfoSchema.optional(),
171
327
  refinements: z3.array(refinementSchema)
172
328
  });
329
+ var merchantListCardDataSchema = shopListCardDataSchema;
173
330
  var productDetailCardDataSchema = z3.object({
174
331
  productId: z3.string().min(1),
175
332
  name: z3.string().min(1),
@@ -195,9 +352,13 @@ var productDetailCardDataSchema = z3.object({
195
352
  humanGuideAvailable: z3.boolean(),
196
353
  itemActions: z3.array(actionDraftSchema)
197
354
  });
198
- var merchantDetailCardDataSchema = z3.object({
355
+ var shopDetailCardDataSchema = z3.object({
199
356
  merchantId: z3.string(),
200
357
  name: z3.string(),
358
+ /** mall scope 透传:供客户端 Sheet 后台 detail HTTP 请求携带(工具执行时注入,与 shop-list 同源) */
359
+ mallId: z3.string().optional(),
360
+ /** 小程序 appId(miniAppId 唯一真值透传;HTTP /shop-detail 鉴权用) */
361
+ miniAppId: z3.string().optional(),
201
362
  logoUrl: httpsUrlSchema.optional(),
202
363
  coverUrls: z3.array(httpsUrlSchema),
203
364
  brand: z3.string().optional(),
@@ -208,19 +369,43 @@ var merchantDetailCardDataSchema = z3.object({
208
369
  contactInfo: z3.array(z3.object({ channel: z3.string(), value: z3.string() })).optional(),
209
370
  services: z3.array(z3.string()),
210
371
  promotionFacts: z3.array(z3.string()),
372
+ /** 门店关联优惠券列表(来自 couponList;name/imageUrl/faceValue/salePrice/applicableCategories/validHours) */
373
+ coupons: z3.array(shopCouponSchema).optional(),
211
374
  evidence: z3.array(evidenceSchema),
212
375
  itemActions: z3.array(actionDraftSchema)
213
376
  });
377
+ var merchantDetailCardDataSchema = shopDetailCardDataSchema;
214
378
  var categoryListCardDataSchema = z3.object({
215
379
  categories: z3.array(
216
380
  z3.object({
217
381
  code: z3.string().min(1),
218
382
  name: z3.string().min(1),
219
383
  description: z3.string().optional(),
384
+ /** 类目图标 URL;undefined 时前端展示默认图标 */
385
+ iconUrl: httpsUrlSchema.optional(),
220
386
  merchantCount: z3.number().int().min(0),
221
- subCategories: z3.array(z3.object({ code: z3.string(), name: z3.string(), merchantCount: z3.number().int().min(0) })).optional()
387
+ subCategories: z3.array(z3.object({ code: z3.string(), name: z3.string(), merchantCount: z3.number().int().min(0) })).optional(),
388
+ /** 0.3.2 D4:类别条目动作(send 合成话术/外链) */
389
+ itemActions: z3.array(actionDraftSchema).optional()
222
390
  })
223
391
  ),
392
+ /** 商场楼栋-楼层结构(与 mall-directory 同语义子集,供 category-list 卡片展示楼层导航) */
393
+ buildings: z3.array(
394
+ z3.object({
395
+ buildingCode: z3.string(),
396
+ buildingName: z3.string(),
397
+ floors: z3.array(
398
+ z3.object({
399
+ floorCode: z3.string(),
400
+ floorName: z3.string(),
401
+ businessCategories: z3.array(z3.string()),
402
+ merchantCount: z3.number().int().min(0),
403
+ /** 楼层条目动作(send:查看该楼层门店列表) */
404
+ itemActions: z3.array(actionDraftSchema).optional()
405
+ })
406
+ )
407
+ })
408
+ ).optional(),
224
409
  observedAt: isoDateTimeSchema
225
410
  });
226
411
  var productComparisonCardDataSchema = z3.object({
@@ -242,6 +427,8 @@ var productComparisonCardDataSchema = z3.object({
242
427
  caveats: z3.array(z3.string())
243
428
  })
244
429
  ),
430
+ /** 0.3.2 D4:刷新截止时间(ISO);到期后渲染端禁用全部条目交互 */
431
+ refreshRequiredAt: isoDateTimeSchema.optional(),
245
432
  observedAt: isoDateTimeSchema
246
433
  });
247
434
  var mallDirectoryCardDataSchema = z3.object({
@@ -256,7 +443,9 @@ var mallDirectoryCardDataSchema = z3.object({
256
443
  floorCode: z3.string(),
257
444
  floorName: z3.string(),
258
445
  businessCategories: z3.array(z3.string()),
259
- merchantCount: z3.number().int().min(0)
446
+ merchantCount: z3.number().int().min(0),
447
+ /** 0.3.2 D4:楼层条目动作(send:查看楼层门店) */
448
+ itemActions: z3.array(actionDraftSchema).optional()
260
449
  })
261
450
  )
262
451
  })
@@ -283,9 +472,13 @@ var customerServiceFaqCardDataSchema = z3.object({
283
472
  question: z3.string().min(1),
284
473
  answer: z3.string().min(1),
285
474
  category: z3.string().optional(),
286
- relevanceScore: z3.number().min(0).max(1)
475
+ relevanceScore: z3.number().min(0).max(1),
476
+ /** 0.3.2 D4:答案参考外链(openLink) */
477
+ referenceUrl: httpsUrlSchema.optional()
287
478
  })
288
479
  ),
480
+ /** 客服电话(015:deployment.malls 经 mall-directory 服务注入;缺省不渲染拨打条目) */
481
+ contactPhone: z3.string().min(1).optional(),
289
482
  noResultsReason: z3.string().optional()
290
483
  });
291
484
  var humanGuideListCardDataSchema = z3.object({
@@ -314,25 +507,75 @@ var locationHandoffCardDataSchema = z3.object({
314
507
  }).optional(),
315
508
  itemActions: z3.array(actionDraftSchema)
316
509
  });
510
+ var recommendMerchantsCardDataSchema = z3.object({
511
+ summary: z3.string().optional(),
512
+ /** 类目筛选 Tab(来自 list-categories;有值时渲染 Tab 栏) */
513
+ categoryTabs: z3.array(
514
+ z3.object({
515
+ code: z3.string(),
516
+ name: z3.string()
517
+ })
518
+ ).optional(),
519
+ items: z3.array(
520
+ z3.object({
521
+ merchantId: z3.string(),
522
+ name: z3.string(),
523
+ logoUrl: httpsUrlSchema.optional(),
524
+ coverUrl: httpsUrlSchema.optional(),
525
+ brand: z3.string().optional(),
526
+ businessCategories: z3.array(z3.string()),
527
+ location: merchantLocationSchema,
528
+ status: merchantStatusSchema,
529
+ description: z3.string().optional(),
530
+ contactInfo: z3.array(z3.object({ channel: z3.string(), value: z3.string() })).optional(),
531
+ services: z3.array(z3.string()).optional(),
532
+ /** 营业时间/经营状态文本(如 "10:00营业"),来自知识库 经营状态 字段 */
533
+ operatingStatus: z3.string().optional(),
534
+ /** 评分(如 "4.8"),来自知识库 评分 字段 */
535
+ rating: z3.string().optional(),
536
+ /** 人均消费文本(如 "¥202"),来自知识库 人均消费 字段(分为单位时自动格式化) */
537
+ avgSpend: z3.string().optional(),
538
+ promotionFacts: z3.array(z3.string()),
539
+ itemActions: z3.array(actionDraftSchema)
540
+ })
541
+ ),
542
+ noResultsReason: z3.string().optional(),
543
+ observedAt: isoDateTimeSchema
544
+ });
317
545
  var shoppingGuideCardDataSchemas = {
318
546
  "product-list": productListCardDataSchema,
319
547
  "product-detail": productDetailCardDataSchema,
320
- "merchant-list": merchantListCardDataSchema,
321
- "merchant-detail": merchantDetailCardDataSchema,
548
+ "shop-list": shopListCardDataSchema,
549
+ "shop-detail": shopDetailCardDataSchema,
322
550
  "category-list": categoryListCardDataSchema,
323
551
  "product-comparison": productComparisonCardDataSchema,
324
552
  "mall-directory": mallDirectoryCardDataSchema,
325
553
  "nearby-mall-list": nearbyMallListCardDataSchema,
326
554
  "customer-service-faq": customerServiceFaqCardDataSchema,
327
555
  "human-guide-list": humanGuideListCardDataSchema,
328
- "location-handoff": locationHandoffCardDataSchema
556
+ "location-handoff": locationHandoffCardDataSchema,
557
+ "recommend-merchants": recommendMerchantsCardDataSchema
329
558
  };
330
559
 
331
560
  // src/member/cards.ts
332
561
  import { z as z4 } from "zod";
333
- var memberStateSchema = z4.enum(["active", "not_enrolled", "closed"]);
562
+ var memberAuthStateSchema = z4.enum(["authenticated", "unauthenticated"]);
563
+ var memberStateSchema = z4.enum(["unknown", "active", "not_enrolled", "closed"]);
564
+ var MEMBER_PREFERENCE_VALUES = [
565
+ "\u6211\u5E38\u6765\u4E70\u8863\u670D",
566
+ "\u6211\u5E38\u5E26\u5A03\u6765\u73A9",
567
+ "\u6211\u5E38\u6765\u5403\u7F8E\u98DF"
568
+ ];
569
+ var memberPreferenceValueSchema = z4.enum(MEMBER_PREFERENCE_VALUES);
570
+ var MEMBER_PREFERENCE_PROMPTS = MEMBER_PREFERENCE_VALUES.map((value) => ({ value, query: value }));
571
+ var MEMBER_PREFERENCE_RECOMMENDATION_QUERIES = {
572
+ "\u6211\u5E38\u6765\u4E70\u8863\u670D": "\u63A8\u8350\u9002\u5408\u8D2D\u4E70\u7684\u670D\u88C5\u95E8\u5E97\u548C\u5546\u54C1",
573
+ "\u6211\u5E38\u5E26\u5A03\u6765\u73A9": "\u63A8\u8350\u9002\u5408\u5E26\u5A03\u7684\u4EB2\u5B50\u5A31\u4E50\u95E8\u5E97",
574
+ "\u6211\u5E38\u6765\u5403\u7F8E\u98DF": "\u63A8\u8350\u503C\u5F97\u53BB\u7684\u9910\u996E\u7F8E\u98DF\u95E8\u5E97"
575
+ };
334
576
  var memberInfoCardDataSchema = z4.object({
335
577
  userId: z4.string().min(1),
578
+ authState: memberAuthStateSchema,
336
579
  state: memberStateSchema,
337
580
  displayName: z4.string().optional(),
338
581
  avatarUrl: z4.string().optional(),
@@ -348,35 +591,42 @@ var memberCardSummaryCardDataSchema = z4.object({
348
591
  status: z4.enum(["active", "inactive", "frozen", "expired", "unknown"]),
349
592
  levelName: z4.string().optional(),
350
593
  availablePoints: z4.number().int().min(0),
351
- cardImageUrl: z4.string().optional()
352
- });
353
- var memberCouponListCardDataSchema = z4.object({
354
- userId: z4.string().min(1),
355
- items: z4.array(
356
- z4.object({
357
- couponRef: z4.string(),
358
- title: z4.string(),
359
- type: z4.enum(["amount", "discount", "gift", "parking", "unknown"]),
360
- status: z4.enum(["effective", "used", "expired", "invalid", "unknown"]),
361
- benefitText: z4.string().optional(),
362
- thresholdText: z4.string().optional()
363
- })
364
- ),
365
- total: z4.number().int().min(0)
366
- });
367
- var memberCouponDetailCardDataSchema = z4.object({
368
- couponRef: z4.string(),
369
- title: z4.string(),
370
- type: z4.enum(["amount", "discount", "gift", "parking", "unknown"]),
371
- status: z4.enum(["effective", "used", "expired", "invalid", "unknown"]),
372
- description: z4.string().optional(),
373
- benefitText: z4.string().optional(),
374
- thresholdText: z4.string().optional()
594
+ cardImageUrl: z4.string().optional(),
595
+ pointsRuleImageUrl: z4.string().url().optional(),
596
+ pointsRuleContent: z4.string().min(1).max(2e4).optional(),
597
+ pointsUrl: z4.string().url().optional(),
598
+ presentation: z4.object({
599
+ variant: z4.enum(["blue", "silver", "gold", "black"]),
600
+ labelsEmbedded: z4.boolean().optional()
601
+ }).optional(),
602
+ progress: z4.object({
603
+ daySpentCents: z4.number().int().min(0),
604
+ yearSpentCents: z4.number().int().min(0),
605
+ percent: z4.number().min(0).max(100),
606
+ message: z4.string().min(1).max(256)
607
+ }).optional(),
608
+ benefits: z4.array(z4.object({
609
+ benefitRef: z4.string().min(1),
610
+ name: z4.string().min(1).max(128),
611
+ iconUrl: z4.string().url().optional(),
612
+ description: z4.string().min(1).max(128).optional(),
613
+ action: z4.object({
614
+ kind: z4.enum(["miniapp", "dialog", "toast"]),
615
+ url: z4.string().url().optional(),
616
+ title: z4.string().min(1).max(128).optional(),
617
+ text: z4.string().min(1).max(2048).optional()
618
+ }).optional()
619
+ })).max(20).optional(),
620
+ /** 入会后偏好引导;首批固定三项,保留数组形态便于后续扩展。 */
621
+ preferencePrompts: z4.array(z4.object({
622
+ value: memberPreferenceValueSchema,
623
+ query: z4.string().min(1).max(128)
624
+ })).max(8).optional()
375
625
  });
376
626
  var memberPointUsageListCardDataSchema = z4.object({
377
627
  userId: z4.string().min(1),
378
628
  balance: z4.number().int(),
379
- level: z4.enum(["silver", "gold", "platinum"]),
629
+ membershipLabel: z4.string().optional(),
380
630
  items: z4.array(
381
631
  z4.object({
382
632
  usageRecordRef: z4.string(),
@@ -391,33 +641,576 @@ var memberPointUsageListCardDataSchema = z4.object({
391
641
  var memberEnrollmentFormCardDataSchema = z4.object({
392
642
  userId: z4.string().min(1),
393
643
  state: memberStateSchema,
394
- /** 表单必填项(渲染端收集后经 componentAction member.enroll 提交) */
395
- fields: z4.array(z4.object({ fieldId: z4.string(), label: z4.string(), required: z4.boolean() })),
396
- actionId: z4.string()
644
+ /** 表单版本(幂等键组成部分) */
645
+ formVersion: z4.string().min(1),
646
+ /** 表单字段(readOnly = 授权预填锁定;prefill = 预填值) */
647
+ fields: z4.array(
648
+ z4.object({
649
+ fieldId: z4.string(),
650
+ label: z4.string(),
651
+ type: z4.enum(["text", "tel", "select", "date"]),
652
+ required: z4.boolean(),
653
+ readOnly: z4.boolean().optional(),
654
+ prefill: z4.string().optional(),
655
+ placeholder: z4.string().optional(),
656
+ options: z4.array(z4.string()).optional()
657
+ })
658
+ ),
659
+ /** 隐私/条款同意项(required 必勾) */
660
+ consents: z4.array(
661
+ z4.object({
662
+ consentId: z4.string(),
663
+ version: z4.string(),
664
+ title: z4.string(),
665
+ required: z4.boolean(),
666
+ url: z4.string().optional()
667
+ })
668
+ ),
669
+ /** 支付宝授权状态(required → 渲染授权按钮;authorized → mobile 预填 readOnly) */
670
+ authorization: z4.object({
671
+ status: z4.enum(["required", "authorized", "unavailable"]),
672
+ mobileMasked: z4.string().optional()
673
+ }),
674
+ /** 手动填写模式提示(授权不可用降级) */
675
+ manualNotice: z4.string().optional()
397
676
  });
398
677
  var memberEnrollmentStatusCardDataSchema = z4.object({
399
678
  userId: z4.string().min(1),
400
- success: z4.boolean(),
679
+ attemptRef: z4.string().optional(),
680
+ state: z4.enum(["pending_confirmation", "confirmation_timeout", "active", "failed"]),
401
681
  memberRef: z4.string().optional(),
402
- message: z4.string().optional(),
403
- state: memberStateSchema
682
+ message: z4.string().optional()
683
+ });
684
+ var memberEnrollmentCtaCardDataSchema = z4.object({
685
+ userId: z4.string().min(1),
686
+ authState: z4.literal("authenticated"),
687
+ state: z4.enum(["not_enrolled", "closed"]),
688
+ /**
689
+ * alipays:// 深链,由部署配置注入;**可选透传素材**——出卡不依赖它,
690
+ * 壳能力(getLoginState/openGate)缺席时兜底 openLink 用,未配置恒出卡(无此字段)
691
+ */
692
+ enrollUrl: z4.string().min(1).refine((value) => value.startsWith("alipays://") || value.startsWith("https://"), {
693
+ message: "enrollUrl must use alipays:// or https://"
694
+ }).optional(),
695
+ title: z4.string().optional(),
696
+ subtitle: z4.string().optional(),
697
+ /**
698
+ * 入会权益提示列表(工具层注入通用文案;不得包含折扣/免费停车等未经系统确认的承诺)。
699
+ * 缺省不展示,由渲染层按有无决定是否渲染区块。
700
+ */
701
+ perks: z4.array(z4.string()).optional()
702
+ });
703
+ var memberLoginCtaCardDataSchema = z4.object({
704
+ /**
705
+ * 商场小程序登录页深链,由部署配置注入;**可选透传素材**——出卡不依赖它,
706
+ * 壳能力(getLoginState)缺席时兜底 openLink 用,未配置恒出卡(无此字段)
707
+ */
708
+ loginUrl: z4.string().min(1).refine((value) => value.startsWith("alipays://") || value.startsWith("https://"), {
709
+ message: "loginUrl must use alipays:// or https://"
710
+ }).optional(),
711
+ title: z4.string().optional()
404
712
  });
405
713
  var memberCardDataSchemas = {
406
714
  "member-info": memberInfoCardDataSchema,
407
715
  "member-card-summary": memberCardSummaryCardDataSchema,
408
- "member-coupon-list": memberCouponListCardDataSchema,
409
- "member-coupon-detail": memberCouponDetailCardDataSchema,
410
716
  "member-point-usage-list": memberPointUsageListCardDataSchema,
411
717
  "member-enrollment-form": memberEnrollmentFormCardDataSchema,
412
- "member-enrollment-status": memberEnrollmentStatusCardDataSchema
718
+ "member-enrollment-status": memberEnrollmentStatusCardDataSchema,
719
+ "member-enrollment-cta": memberEnrollmentCtaCardDataSchema,
720
+ "member-login-cta": memberLoginCtaCardDataSchema
721
+ };
722
+
723
+ // src/promotion/cards.ts
724
+ import { z as z6 } from "zod";
725
+
726
+ // src/alipay-activity/cards.ts
727
+ import { z as z5 } from "zod";
728
+ var bumpInVoucherSchema = z5.object({
729
+ prizeId: z5.string(),
730
+ voucherName: z5.string(),
731
+ voucherType: z5.string(),
732
+ reductionAmount: z5.string(),
733
+ thresholdAmountText: z5.string(),
734
+ unit: z5.string(),
735
+ merchantName: z5.string(),
736
+ merchantLogo: z5.string().optional(),
737
+ itemLogo: z5.string().optional()
738
+ });
739
+ var bumpInActStatusSchema = z5.enum([
740
+ "NOT_START",
741
+ "INIT",
742
+ "PROCESSING",
743
+ "FINISH",
744
+ "RECEIVED"
745
+ ]);
746
+ var promotionBumpInActivityCardDataSchema = z5.object({
747
+ activityRef: z5.string(),
748
+ title: z5.string(),
749
+ mainTitle: z5.string().optional(),
750
+ coverUrl: z5.string().optional(),
751
+ /** 联单活动全幅背景图 URL(与 coverUrl 互斥;backgroundUrl 存在时头部采用全幅覆盖布局) */
752
+ backgroundUrl: z5.string().optional(),
753
+ /** 左上角活动类型胶囊标签,如"碰一下联单" */
754
+ tagLabel: z5.string().optional(),
755
+ cardLogoUrl: z5.string().optional(),
756
+ actStatus: bumpInActStatusSchema,
757
+ totalProgress: z5.string().optional(),
758
+ currentProgress: z5.string().optional(),
759
+ progressUnit: z5.string().optional(),
760
+ startAtText: z5.string().optional(),
761
+ endAtText: z5.string().optional(),
762
+ description: z5.string().optional(),
763
+ vouchers: z5.array(bumpInVoucherSchema),
764
+ mode: z5.enum(["detail", "banner"]).default("detail"),
765
+ /** bar(线性进度条,默认)| steps(圆形步骤节点,适合联单任务) */
766
+ progressStyle: z5.enum(["bar", "steps"]).default("bar"),
767
+ /** 参与步骤(联单活动 guide.steps;banner 模式用于渲染步骤进度节点) */
768
+ steps: z5.array(z5.object({ title: z5.string(), description: z5.string().optional() })).optional()
769
+ });
770
+
771
+ // src/promotion/cards.ts
772
+ var imageUrlSchema = z6.string().max(2048).optional();
773
+ var freeCouponClaimModeSchema = z6.enum(["DIRECT", "REDIRECT"]);
774
+ var offerSummarySchema = z6.object({
775
+ offerRef: z6.string().min(1),
776
+ title: z6.string().min(1),
777
+ subtitle: z6.string().optional(),
778
+ offerType: z6.enum(["COUPON", "BUNDLE", "PROMOTION", "ACTIVITY", "GROUPON"]),
779
+ /** 主 facet 一句话(如「满 100 减 20」) */
780
+ benefitText: z6.string().optional(),
781
+ /** 使用门槛(如「满 300 元可用」) */
782
+ thresholdText: z6.string().optional(),
783
+ /**
784
+ * 券的**售价**展示,与 benefitText 是两回事——后者说优惠内容,这里说买这张券要花多少。
785
+ * 免费券给「免费」,付费券给「¥28.8」。文案由 provider 直接给:各厂商币种、小数位与
786
+ * 「免费/0 元」措辞不一,客户端不做数值运算也不反解金额。
787
+ */
788
+ priceText: z6.string().optional(),
789
+ /** 划线原价(如「¥38.8」)。与 priceText 成对出现才有意义,单独给不渲染。 */
790
+ originalPriceText: z6.string().optional(),
791
+ /** 折扣角标(如「7.5折」)。同样是 provider 直出文案,不由前端拿两个价格算。 */
792
+ discountLabel: z6.string().optional(),
793
+ /**
794
+ * 领取按钮文案:免费券「领取」、付费券「抢购」。由 provider 给而非前端按 priceText
795
+ * 猜——「免费」的写法各家不同,猜错就把付费券写成领取。缺省回落「领取」。
796
+ */
797
+ claimActionLabel: z6.string().optional(),
798
+ purchaseUrl: z6.string().max(2048).optional(),
799
+ freeCouponClaimMode: freeCouponClaimModeSchema.optional(),
800
+ /**
801
+ * 下面三条供**列表内的详情浮层**渲染——浮层就地展开,没有二次请求可拉,
802
+ * 需要的信息必须随列表一起下发。厂商不给就不渲染对应区块。
803
+ */
804
+ stockText: z6.string().optional(),
805
+ usageNoticeText: z6.string().optional(),
806
+ guaranteeText: z6.string().optional(),
807
+ usageSceneText: z6.string().optional(),
808
+ usageTimeText: z6.string().optional(),
809
+ claimTimeText: z6.string().optional(),
810
+ usageRuleText: z6.string().optional(),
811
+ /** 可领取(availability.status === 'AVAILABLE') */
812
+ claimable: z6.boolean(),
813
+ availabilityStatus: z6.enum(["AVAILABLE", "UNAVAILABLE", "REQUIRES_ACTION", "UNKNOWN"]).optional(),
814
+ validityText: z6.string().optional(),
815
+ imageUrl: imageUrlSchema,
816
+ /** 0.3.2 D4:条目动作(send:查看详情) */
817
+ itemActions: z6.array(actionDraftSchema).optional(),
818
+ tags: z6.array(z6.string())
819
+ });
820
+ var promotionOfferListCardDataSchema = z6.object({
821
+ presentation: z6.enum(["offer", "promotion", "coupon", "recommendation"]).optional(),
822
+ mode: z6.enum(["search", "claimable", "recommend"]),
823
+ /** 客户端默认展示 4 条;传入正整数可覆盖该上限。 */
824
+ maxItems: z6.number().int().positive().optional(),
825
+ summary: z6.string().optional(),
826
+ items: z6.array(offerSummarySchema),
827
+ noResultsReason: z6.string().optional(),
828
+ nextCursor: z6.string().optional()
829
+ });
830
+ var promotionOfferDetailCardDataSchema = z6.object({
831
+ presentation: z6.enum(["offer", "promotion", "promotion-guide", "coupon", "package"]).optional(),
832
+ offerRef: z6.string().min(1),
833
+ title: z6.string().min(1),
834
+ offerType: z6.enum(["COUPON", "BUNDLE", "PROMOTION", "ACTIVITY", "GROUPON"]),
835
+ subtitle: z6.string().optional(),
836
+ description: z6.string().optional(),
837
+ imageUrl: imageUrlSchema,
838
+ benefitText: z6.string().optional(),
839
+ thresholdText: z6.string().optional(),
840
+ validityText: z6.string().optional(),
841
+ /** 售价三件套,语义同 offerSummary(provider 直出文案,前端不做运算) */
842
+ priceText: z6.string().optional(),
843
+ originalPriceText: z6.string().optional(),
844
+ discountLabel: z6.string().optional(),
845
+ claimActionLabel: z6.string().optional(),
846
+ purchaseUrl: z6.string().max(2048).optional(),
847
+ /** 剩余库存文案(如「剩余:29」);厂商不给就不展示,别拿 0 当「售罄」用 */
848
+ stockText: z6.string().optional(),
849
+ usageNoticeText: z6.string().optional(),
850
+ /** 核销场景(如「万铺小二核销」)——告诉用户这张券在哪、怎么用掉 */
851
+ usageSceneText: z6.string().optional(),
852
+ usageTimeText: z6.string().optional(),
853
+ claimTimeText: z6.string().optional(),
854
+ usageRuleText: z6.string().optional(),
855
+ guaranteeText: z6.string().optional(),
856
+ /** 使用规则/参与步骤 */
857
+ rules: z6.array(z6.string()),
858
+ participationMode: z6.enum([
859
+ "AUTOMATIC_DISCOUNT",
860
+ "CLAIM_THEN_PURCHASE",
861
+ "REGISTER_THEN_ATTEND",
862
+ "GROUP_PURCHASE",
863
+ "UNKNOWN"
864
+ ]).optional(),
865
+ steps: z6.array(z6.object({ title: z6.string(), description: z6.string().optional() })).optional(),
866
+ requirements: z6.array(z6.string()).optional(),
867
+ notice: z6.string().optional(),
868
+ /** 厂商可提供时展示适用门店;可选以兼容历史卡数据。 */
869
+ stores: z6.array(z6.object({
870
+ storeId: z6.string().min(1),
871
+ storeName: z6.string().min(1),
872
+ businessName: z6.string().optional(),
873
+ address: z6.string().optional(),
874
+ floor: z6.string().optional()
875
+ })).optional(),
876
+ bundleItems: z6.array(z6.object({ name: z6.string(), quantity: z6.number().int().positive() })).optional(),
877
+ /** 领取动作是否可用(未登录会员/不可用 → false + unavailableReason) */
878
+ claimable: z6.boolean(),
879
+ unavailableReason: z6.string().optional(),
880
+ caveats: z6.array(z6.string())
881
+ });
882
+ var promotionEntitlementListCardDataSchema = z6.object({
883
+ mallId: z6.string().optional(),
884
+ miniAppId: z6.string().optional(),
885
+ /** 客户端默认展示 4 条;传入正整数可覆盖该上限。 */
886
+ maxItems: z6.number().int().positive().optional(),
887
+ items: z6.array(
888
+ z6.object({
889
+ entitlementRef: z6.string().min(1),
890
+ title: z6.string().min(1),
891
+ imageUrl: imageUrlSchema,
892
+ entitlementType: z6.enum(["COUPON", "BUNDLE", "PROMOTION", "ACTIVITY", "GROUPON"]),
893
+ status: z6.enum(["EFFECTIVE", "USED", "EXPIRED", "INVALID", "UNKNOWN"]),
894
+ codeMasked: z6.string().optional(),
895
+ code: z6.string().optional(),
896
+ qrCodeEnabled: z6.boolean().optional(),
897
+ benefitText: z6.string().optional(),
898
+ thresholdText: z6.string().optional(),
899
+ usageNotice: z6.string().optional(),
900
+ guaranteeText: z6.string().optional(),
901
+ usageSceneText: z6.string().optional(),
902
+ usageTimeText: z6.string().optional(),
903
+ claimTimeText: z6.string().optional(),
904
+ usageRuleText: z6.string().optional(),
905
+ validityText: z6.string().optional(),
906
+ validUntilText: z6.string().optional(),
907
+ /** 0.3.2 D4:条目动作(send:查看详情) */
908
+ itemActions: z6.array(actionDraftSchema).optional(),
909
+ stores: z6.array(z6.object({
910
+ storeId: z6.string(),
911
+ storeName: z6.string(),
912
+ businessName: z6.string().optional(),
913
+ imageUrl: imageUrlSchema,
914
+ address: z6.string().optional(),
915
+ floor: z6.string().optional(),
916
+ latitude: z6.number().optional(),
917
+ longitude: z6.number().optional()
918
+ })).optional()
919
+ })
920
+ ),
921
+ noResultsReason: z6.string().optional(),
922
+ nextCursor: z6.string().optional()
923
+ });
924
+ var promotionActivityCategoryListCardDataSchema = z6.object({
925
+ items: z6.array(
926
+ z6.object({
927
+ categoryId: z6.string().min(1),
928
+ name: z6.string().min(1),
929
+ parentId: z6.string().optional(),
930
+ itemActions: z6.array(actionDraftSchema).optional()
931
+ })
932
+ ),
933
+ noResultsReason: z6.string().optional()
934
+ });
935
+ var promotionBestDealCardDataSchema = z6.object({
936
+ authoritative: z6.boolean(),
937
+ originalAmountCents: z6.number().int().min(0),
938
+ savingsCents: z6.number().int().min(0).optional(),
939
+ expectedPayCents: z6.number().int().min(0).optional(),
940
+ appliedOfferRefs: z6.array(z6.string()),
941
+ candidates: z6.array(offerSummarySchema).optional(),
942
+ message: z6.string().optional()
943
+ });
944
+ var promotionActivityListCardDataSchema = z6.object({
945
+ items: z6.array(
946
+ z6.object({
947
+ activityRef: z6.string().min(1),
948
+ title: z6.string().min(1),
949
+ subtitle: z6.string().optional(),
950
+ coverUrl: imageUrlSchema,
951
+ registrationRequired: z6.boolean(),
952
+ jumpOnly: z6.boolean().optional(),
953
+ jumpLabel: z6.string().min(1).optional(),
954
+ remainingQuota: z6.number().int().min(0).optional(),
955
+ periodText: z6.string().optional(),
956
+ categoryName: z6.string().optional(),
957
+ availabilityStatus: z6.enum(["AVAILABLE", "FULL", "ENDED", "UPCOMING", "UNKNOWN"]).optional(),
958
+ itemActions: z6.array(actionDraftSchema).optional()
959
+ })
960
+ ),
961
+ noResultsReason: z6.string().optional(),
962
+ nextCursor: z6.string().optional()
963
+ });
964
+ var promotionActivityDetailCardDataSchema = z6.object({
965
+ presentation: z6.enum(["detail", "schedule", "guide"]).optional(),
966
+ activityRef: z6.string().min(1),
967
+ title: z6.string().min(1),
968
+ subtitle: z6.string().optional(),
969
+ categoryName: z6.string().optional(),
970
+ description: z6.string().optional(),
971
+ coverUrl: imageUrlSchema,
972
+ periodText: z6.string().optional(),
973
+ location: z6.string().optional(),
974
+ registrationRequired: z6.boolean(),
975
+ jumpOnly: z6.boolean().optional(),
976
+ jumpLabel: z6.string().min(1).optional(),
977
+ /** 需报名时直达厂商支付宝小程序活动详情;由客户端 openLink 本地处理。 */
978
+ registrationUrl: z6.string().max(2048).optional(),
979
+ remainingQuota: z6.number().int().min(0).optional(),
980
+ sessions: z6.array(
981
+ z6.object({
982
+ sessionRef: z6.string(),
983
+ title: z6.string(),
984
+ startText: z6.string(),
985
+ endText: z6.string().optional(),
986
+ location: z6.string().optional(),
987
+ remainingQuota: z6.number().int().min(0).optional(),
988
+ status: z6.enum(["OPEN", "FULL", "CLOSED", "UNKNOWN"])
989
+ })
990
+ ),
991
+ guideSteps: z6.array(z6.string()),
992
+ guideItems: z6.array(z6.object({ title: z6.string(), description: z6.string().optional() })).optional(),
993
+ conditions: z6.array(z6.string()),
994
+ notice: z6.string().optional()
995
+ });
996
+ var promotionCardDataSchemas = {
997
+ "promotion-offer-list": promotionOfferListCardDataSchema,
998
+ "promotion-offer-detail": promotionOfferDetailCardDataSchema,
999
+ "promotion-entitlement-list": promotionEntitlementListCardDataSchema,
1000
+ "promotion-activity-category-list": promotionActivityCategoryListCardDataSchema,
1001
+ "promotion-best-deal": promotionBestDealCardDataSchema,
1002
+ "promotion-activity-list": promotionActivityListCardDataSchema,
1003
+ "promotion-activity-detail": promotionActivityDetailCardDataSchema
1004
+ };
1005
+
1006
+ // src/parking/cards.ts
1007
+ import { z as z7 } from "zod";
1008
+ var parkingOrderInfoSchema = z7.object({
1009
+ /** 停车秒数 */
1010
+ staySecond: z7.number().int().nonnegative().optional(),
1011
+ /** 停车费,单位分 */
1012
+ parkingFee: z7.number().int().nonnegative().optional(),
1013
+ /** 车牌绑定状态 */
1014
+ bindingStatus: z7.number().int().optional(),
1015
+ /** 车牌 */
1016
+ plateNumber: z7.string().min(1).optional(),
1017
+ /** 1=在场缴费,2=逃费/欠费 */
1018
+ orderType: z7.number().int(),
1019
+ /** 车场侧订单号 */
1020
+ spParkingOrderId: z7.string().min(1).optional(),
1021
+ /** 车场 ID(协议定 string) */
1022
+ parkingId: z7.string().min(1),
1023
+ /** 入场时间 */
1024
+ entranceTime: z7.string().min(1).optional(),
1025
+ /** 逗号分隔的能力枚举,如 "LEVEL_DISCOUNT,POINT_DISCOUNT,COUPON" */
1026
+ supportDiscount: z7.string().min(1).optional()
1027
+ });
1028
+ var parkingPaymentCardDataSchema = z7.object({
1029
+ quoteRef: z7.string().min(1),
1030
+ plateNo: z7.string().min(1),
1031
+ entryAtText: z7.string().optional(),
1032
+ durationText: z7.string().optional(),
1033
+ /** 费用明细(label + 金额字符串) */
1034
+ feeItems: z7.array(z7.object({ name: z7.string(), amountText: z7.string() })),
1035
+ totalText: z7.string(),
1036
+ discountText: z7.string().optional(),
1037
+ payableText: z7.string(),
1038
+ /** 当前请求主体的会员状态;旧历史卡可缺省。 */
1039
+ membership: z7.object({
1040
+ state: z7.enum(["unauthenticated", "unknown", "active", "not_enrolled", "closed", "unavailable"]),
1041
+ availablePoints: z7.number().int().min(0).optional()
1042
+ }).optional(),
1043
+ /** 服务端归一化后的支付入口;客户端不解析权益标题。 */
1044
+ paymentOptions: z7.object({
1045
+ direct: z7.object({
1046
+ /** 已应用积分时 Provider 未必能预览无积分金额;缺省时客户端不得提前承诺金额。 */
1047
+ payableText: z7.string().optional(),
1048
+ benefitRefs: z7.array(z7.string())
1049
+ }),
1050
+ points: z7.discriminatedUnion("kind", [
1051
+ z7.object({
1052
+ kind: z7.literal("exact"),
1053
+ pointsToUse: z7.number().int().positive(),
1054
+ payableText: z7.string(),
1055
+ benefitRefs: z7.array(z7.string()).min(1)
1056
+ }),
1057
+ z7.object({
1058
+ kind: z7.literal("requires_reprice"),
1059
+ title: z7.string().min(1),
1060
+ benefitRefs: z7.array(z7.string()).min(1)
1061
+ })
1062
+ ]).optional()
1063
+ }).optional(),
1064
+ /** 已生效权益 */
1065
+ appliedBenefits: z7.array(
1066
+ z7.object({
1067
+ benefitRef: z7.string(),
1068
+ title: z7.string(),
1069
+ discountText: z7.string().optional()
1070
+ })
1071
+ ),
1072
+ /** 可变更权益(reprice 候选;autoSelected 预勾选) */
1073
+ selectableBenefits: z7.array(
1074
+ z7.object({
1075
+ benefitRef: z7.string(),
1076
+ title: z7.string(),
1077
+ autoSelected: z7.boolean(),
1078
+ description: z7.string().optional(),
1079
+ /** 权益类型(券 / 积分抵扣 / 等级权益);客户端据此分组与判定互斥,不得从标题猜测 */
1080
+ kind: z7.enum(["points", "discount", "coupon", "other"]).optional(),
1081
+ /** 预估优惠金额文案(本地展示用;权威金额以 reprice 回填为准) */
1082
+ discountText: z7.string().optional(),
1083
+ /**
1084
+ * 与本权益互斥的类型。三类优惠默认可叠加,互斥是厂商按券配置的例外——
1085
+ * 标记 ['points'] 表示该券不可与积分抵扣叠加。判定双向生效。
1086
+ */
1087
+ exclusiveWithKinds: z7.array(z7.enum(["points", "discount", "coupon"])).optional()
1088
+ })
1089
+ ),
1090
+ /** 乐观锁(提交校验;过期 → 提示重新查询) */
1091
+ revision: z7.number().int().min(1),
1092
+ caveats: z7.array(z7.string()),
1093
+ /**
1094
+ * 支付交接包:客户端卡据 kind 调壳 tbox 能力收款——
1095
+ * kind:'pay' → openParkingPay(传 orderInfo,壳跳确认页/收银台);kind:'unpaid' → openParkingUnpaidOrder(传 orderNo)。
1096
+ * 缺省 = 走内部 confirm-payment(line)支付链。
1097
+ */
1098
+ payHandoff: z7.object({
1099
+ kind: z7.enum(["pay", "unpaid"]),
1100
+ parkingStoreId: z7.string().min(1).optional(),
1101
+ orderInfo: parkingOrderInfoSchema.optional(),
1102
+ orderNo: z7.string().min(1).optional()
1103
+ }).optional(),
1104
+ /**
1105
+ * 支付进度(缺省 = 未发起):一经写入这张报价单即终结,按钮恒置灰。
1106
+ * 报价是一次性的(token singleUse + revision 乐观锁),发起支付后不可再提交。
1107
+ */
1108
+ settlement: z7.object({
1109
+ state: z7.enum(["paying", "paid", "failed"]),
1110
+ text: z7.string().min(1)
1111
+ }).optional()
1112
+ });
1113
+ var parkingPaymentResultCardDataSchema = z7.object({
1114
+ paymentRef: z7.string().min(1),
1115
+ plateNo: z7.string(),
1116
+ status: z7.enum(["PAID", "CANCELLED", "UNKNOWN"]),
1117
+ amountText: z7.string().optional(),
1118
+ message: z7.string(),
1119
+ /** 失败/取消:可重新发起(重新查询报价) */
1120
+ retryable: z7.boolean().optional(),
1121
+ /** 离场时限提醒(PAID:缴费后免费离场窗口,超时重新计费) */
1122
+ leaveNotice: z7.string().optional(),
1123
+ /** 回执明细(车牌 / 停车时长 / 缴费时间等,服务端已格式化) */
1124
+ details: z7.array(z7.object({ label: z7.string(), value: z7.string() })).optional()
1125
+ });
1126
+ var parkingPaymentRecordsCardDataSchema = z7.object({
1127
+ items: z7.array(
1128
+ z7.object({
1129
+ recordRef: z7.string().min(1),
1130
+ plateNo: z7.string(),
1131
+ amountText: z7.string(),
1132
+ paidAtText: z7.string(),
1133
+ status: z7.enum(["PAID", "REFUNDED", "CLOSED", "UNKNOWN"]),
1134
+ statusText: z7.string().optional(),
1135
+ parkName: z7.string().optional(),
1136
+ plazaName: z7.string().optional(),
1137
+ /** 展开态字段(entry/exit/单号脱敏) */
1138
+ entryAtText: z7.string().optional(),
1139
+ exitAtText: z7.string().optional(),
1140
+ payOrderNoMasked: z7.string().optional(),
1141
+ orderCompleted: z7.boolean().optional(),
1142
+ invoiceEligible: z7.boolean().optional(),
1143
+ invoiceIssued: z7.boolean().optional()
1144
+ })
1145
+ ),
1146
+ total: z7.number().int().min(0),
1147
+ hasMore: z7.boolean(),
1148
+ /** 厂商口径 caveats(厂商事实,7 条并入) */
1149
+ caveats: z7.array(z7.string()),
1150
+ /** 详情加载、开票提交等动作反馈 */
1151
+ message: z7.string().optional()
1152
+ });
1153
+ var parkingVehicleManagementCardDataSchema = z7.object({
1154
+ bound: z7.array(z7.object({
1155
+ vehicleRef: z7.string(),
1156
+ plateNo: z7.string(),
1157
+ parked: z7.boolean().optional()
1158
+ })),
1159
+ message: z7.string().optional(),
1160
+ /**
1161
+ * 会员状态(缺省 = 未探测):仅 not_enrolled 才展示入会引导。
1162
+ * 与 parking-payment 的 membership 同源,避免两张卡对同一用户给出不同判断。
1163
+ */
1164
+ membership: z7.object({
1165
+ state: z7.enum(["unauthenticated", "unknown", "active", "not_enrolled", "closed", "unavailable"])
1166
+ }).optional()
1167
+ });
1168
+ var PARKING_PLATE_PATTERN = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-HJ-NP-Z][A-HJ-NP-Z](?:[A-HJ-NP-Z0-9]{6}|[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳])$/;
1169
+ var parkingInfoCardDataSchema = z7.object({
1170
+ kind: z7.enum(["chargeRules", "benefitPolicy", "vehicleLocation"]),
1171
+ title: z7.string().min(1),
1172
+ entries: z7.array(z7.object({ label: z7.string(), value: z7.string() }))
1173
+ });
1174
+ var parkingCardDataSchemas = {
1175
+ "parking-payment": parkingPaymentCardDataSchema,
1176
+ "parking-payment-result": parkingPaymentResultCardDataSchema,
1177
+ "parking-payment-records": parkingPaymentRecordsCardDataSchema,
1178
+ "parking-vehicle-management": parkingVehicleManagementCardDataSchema,
1179
+ "parking-info": parkingInfoCardDataSchema
413
1180
  };
414
1181
  export {
1182
+ AUTH_LOGIN_SERVICE,
1183
+ MALL_INFO_SERVICE,
415
1184
  MALL_SCOPE_KEY,
1185
+ MEMBER_ACCOUNT_SERVICE,
1186
+ MEMBER_BENEFITS_SERVICE,
1187
+ MEMBER_CARD_SERVICE,
1188
+ MEMBER_ENROLLMENT_SERVICE,
1189
+ MEMBER_PREFERENCE_PROMPTS,
1190
+ MEMBER_PREFERENCE_RECOMMENDATION_QUERIES,
1191
+ MEMBER_PREFERENCE_VALUES,
1192
+ MEMBER_PROFILE_SERVICE,
1193
+ PARKING_PAYMENT_SERVICE,
1194
+ PARKING_PLATE_PATTERN,
1195
+ PARKING_QUERY_SERVICE,
1196
+ PARKING_VEHICLE_SERVICE,
1197
+ PROMOTION_ACQUISITION_SERVICE,
1198
+ PROMOTION_ACTIVITIES_SERVICE,
1199
+ PROMOTION_ACTIVITY_ROUTING_POLICY,
1200
+ PROMOTION_ENTITLEMENTS_SERVICE,
1201
+ PROMOTION_OFFERS_SERVICE,
1202
+ SHOPPING_CATALOG_SERVICE,
1203
+ SHOPPING_CATEGORIES_SERVICE,
1204
+ SHOPPING_DIRECTORY_SERVICE,
1205
+ SHOPPING_SHOPS_SERVICE,
416
1206
  actionDraftSchema,
417
1207
  categoryListCardDataSchema,
1208
+ classifyMemberOutcome,
1209
+ createMallContextValidator,
418
1210
  createMallRuntimeAssembly,
419
1211
  customerServiceFaqCardDataSchema,
420
1212
  evidenceSchema,
1213
+ externalMemberRefOf,
421
1214
  extractMallScope,
422
1215
  httpsUrlSchema,
423
1216
  humanGuideListCardDataSchema,
@@ -425,16 +1218,23 @@ export {
425
1218
  locationHandoffCardDataSchema,
426
1219
  mallDirectoryCardDataSchema,
427
1220
  mallLocationSchema,
1221
+ mallScopeOf,
1222
+ mallScopeOrEmpty,
428
1223
  mallScopeSchema,
1224
+ mallSlot,
1225
+ mallSubjectIdOf,
429
1226
  mallUserRefSchema,
1227
+ memberAuthStateSchema,
430
1228
  memberCardDataSchemas,
431
1229
  memberCardSummaryCardDataSchema,
432
- memberCouponDetailCardDataSchema,
433
- memberCouponListCardDataSchema,
1230
+ memberEnrollmentCtaCardDataSchema,
434
1231
  memberEnrollmentFormCardDataSchema,
435
1232
  memberEnrollmentStatusCardDataSchema,
1233
+ memberGateCardOf,
436
1234
  memberInfoCardDataSchema,
1235
+ memberLoginCtaCardDataSchema,
437
1236
  memberPointUsageListCardDataSchema,
1237
+ memberPreferenceValueSchema,
438
1238
  memberStateSchema,
439
1239
  merchantDetailCardDataSchema,
440
1240
  merchantListCardDataSchema,
@@ -443,6 +1243,13 @@ export {
443
1243
  moneySchema,
444
1244
  nearbyMallListCardDataSchema,
445
1245
  pageInfoSchema,
1246
+ parkingCardDataSchemas,
1247
+ parkingInfoCardDataSchema,
1248
+ parkingOrderInfoSchema,
1249
+ parkingPaymentCardDataSchema,
1250
+ parkingPaymentRecordsCardDataSchema,
1251
+ parkingPaymentResultCardDataSchema,
1252
+ parkingVehicleManagementCardDataSchema,
446
1253
  parseMallLocation,
447
1254
  parseMallScope,
448
1255
  parseMallUserRef,
@@ -450,8 +1257,25 @@ export {
450
1257
  productComparisonCardDataSchema,
451
1258
  productDetailCardDataSchema,
452
1259
  productListCardDataSchema,
1260
+ promotionActivityCategoryListCardDataSchema,
1261
+ promotionActivityDetailCardDataSchema,
1262
+ promotionActivityListCardDataSchema,
1263
+ promotionBestDealCardDataSchema,
1264
+ promotionBumpInActivityCardDataSchema,
1265
+ promotionCardDataSchemas,
1266
+ promotionEntitlementListCardDataSchema,
1267
+ promotionOfferDetailCardDataSchema,
1268
+ promotionOfferListCardDataSchema,
1269
+ readLoginMallId,
453
1270
  reasonItemSchema,
1271
+ recommendMerchantsCardDataSchema,
454
1272
  refinementSchema,
455
- requireMallScope,
456
- shoppingGuideCardDataSchemas
1273
+ resolveMemberGate,
1274
+ shopDetailCardDataSchema,
1275
+ shopListCardDataSchema,
1276
+ shopLocationSchema,
1277
+ shopStatusSchema,
1278
+ shoppingGuideCardDataSchemas,
1279
+ toMallQueryContext,
1280
+ withMallScopeFromQuery
457
1281
  };