@tbox.cn/app-contracts-mall 0.1.1 → 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 (78) hide show
  1. package/README.md +16 -2
  2. package/dist/alipay-activity/cards.d.ts +305 -0
  3. package/dist/assembly.d.ts +54 -0
  4. package/dist/chunk-KIZD6FZ2.js +43 -0
  5. package/dist/deployment.d.ts +42 -0
  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/guard.d.ts +50 -0
  15. package/dist/index.d.ts +22 -2
  16. package/dist/member/cards.d.ts +940 -0
  17. package/dist/parking/cards.d.ts +1271 -0
  18. package/dist/promotion/cards.d.ts +2529 -0
  19. package/dist/query-context.d.ts +47 -0
  20. package/dist/runtime.d.ts +20 -0
  21. package/dist/runtime.js +1281 -0
  22. package/dist/scope.d.ts +76 -0
  23. package/dist/server/index.d.ts +11 -0
  24. package/dist/server/index.js +80 -0
  25. package/dist/server/mall-context.d.ts +24 -0
  26. package/dist/server/mall-control-plane.d.ts +8 -0
  27. package/dist/server/request-credentials.d.ts +22 -0
  28. package/dist/services/customer-service.d.ts +11 -0
  29. package/dist/services/mall-info.d.ts +26 -0
  30. package/dist/services/member.d.ts +243 -9
  31. package/dist/services/parking.d.ts +105 -12
  32. package/dist/services/promotion.d.ts +100 -4
  33. package/dist/services/shopping-guide.d.ts +97 -0
  34. package/dist/shared/cards.d.ts +42 -0
  35. package/dist/shopping-guide/cards.d.ts +7039 -0
  36. package/package.json +19 -8
  37. package/src/alipay-activity/cards.ts +66 -0
  38. package/src/assembly.ts +103 -0
  39. package/src/deployment.ts +44 -0
  40. package/src/domain/activity.ts +66 -0
  41. package/src/domain/coupon.ts +3 -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 +206 -12
  46. package/src/domain/points.ts +3 -2
  47. package/src/domain/shopping-guide.ts +242 -0
  48. package/src/guard.ts +48 -0
  49. package/src/index.ts +22 -2
  50. package/src/member/cards.ts +209 -0
  51. package/src/parking/cards.ts +233 -0
  52. package/src/promotion/cards.ts +290 -0
  53. package/src/query-context.ts +81 -0
  54. package/src/runtime.ts +41 -0
  55. package/src/scope.ts +92 -0
  56. package/src/server/index.ts +11 -0
  57. package/src/server/mall-context.ts +39 -0
  58. package/src/server/mall-control-plane.ts +56 -0
  59. package/src/server/request-credentials.ts +43 -0
  60. package/src/service-slots.json +23 -0
  61. package/src/services/customer-service.ts +12 -0
  62. package/src/services/mall-info.ts +31 -0
  63. package/src/services/member.ts +354 -9
  64. package/src/services/parking.ts +161 -11
  65. package/src/services/promotion.ts +124 -4
  66. package/src/services/shopping-guide.ts +138 -0
  67. package/src/shared/cards.ts +25 -0
  68. package/src/shopping-guide/cards.ts +438 -0
  69. package/tests/assembly-validate-scope.test.ts +132 -0
  70. package/tests/cards.test.ts +586 -0
  71. package/tests/context-unification.test.ts +73 -0
  72. package/tests/mall-control-plane.test.ts +86 -0
  73. package/tests/member-status.test.ts +197 -0
  74. package/tests/query-context.test.ts +111 -0
  75. package/tests/request-credentials.test.ts +38 -0
  76. package/tests/resolve-primitives.test.ts +55 -0
  77. package/tests/service-slots.test.ts +78 -0
  78. package/tsconfig.json +1 -1
@@ -1,6 +1,126 @@
1
- import type { Coupon } from '../domain/coupon';
1
+ /**
2
+ * 营销域 Port(015:四 Port 重写,breaking 0.3.0——替换旧单方法 PromotionQueryPort)。
3
+ * 结构类型子集接口——模块完整实现 extends 本接口,消费方仅依赖契约包。
4
+ * C 端主体经 ctx.requestContext.credentials(X2);externalMemberRef 由消费方经 member 域
5
+ * 状态服务解析('member.status' 判定 + externalMemberRefOf 取值,SubjectBindingPort 已 deprecated)。
6
+ */
7
+ import type { MallScope } from '../scope';
8
+ import type { RequestContext } from '@tbox.cn/app-contracts';
9
+ import type { OfferType, PromotionOffer, PromotionOfferPage, PromotionBestDeal } from '../domain/offer';
10
+ import type { PromotionEntitlement, PromotionEntitlementPage } from '../domain/entitlement';
11
+ import type {
12
+ ActivitySession,
13
+ PromotionActivityDetail,
14
+ PromotionActivityPage,
15
+ } from '../domain/activity';
16
+ import type { PromotionOperation } from '../domain/operation';
2
17
 
3
- /** PromotionQueryPort:营销资格查询(scenario 出券用) */
4
- export interface PromotionQueryPort {
5
- queryEligibleCoupons(userId: string): Promise<Coupon[]>;
18
+ // ===== 营销域 service slot 词汇(与 service-slots.json 同锁) =====
19
+
20
+ export const PROMOTION_OFFERS_SERVICE = 'promotion.offers';
21
+ export const PROMOTION_ENTITLEMENTS_SERVICE = 'promotion.entitlements';
22
+ export const PROMOTION_ACTIVITIES_SERVICE = 'promotion.activities';
23
+ export const PROMOTION_ACQUISITION_SERVICE = 'promotion.acquisition';
24
+
25
+ /** 查询上下文(scope + 主体 + 请求;credentials 为 C 端用户 Token 唯一来源) */
26
+ export interface PromotionQueryContext {
27
+ readonly scope: MallScope;
28
+ readonly subjectId?: string;
29
+ readonly requestContext: RequestContext;
30
+ }
31
+
32
+ /**
33
+ * 活动卡路由策略:provider 按请求 scope 声明是否由专属活动组件承接。
34
+ * 契约只描述能力,不携带厂商名称或卡片实现细节。
35
+ */
36
+ export const PROMOTION_ACTIVITY_ROUTING_POLICY = 'promotion.activity-routing';
37
+ export type PromotionActivityRoutingPolicy = (reqCtx: RequestContext) => boolean;
38
+
39
+ export interface PromotionSearchInput {
40
+ readonly keyword?: string;
41
+ readonly scene?: string;
42
+ readonly offerTypes?: readonly OfferType[];
43
+ readonly cursor?: string;
44
+ readonly limit?: number;
45
+ }
46
+
47
+ // ===== 1. PromotionOfferQueryPort:Offer 查询/推荐/测算 =====
48
+
49
+ export interface PromotionOfferQueryPort {
50
+ searchOffers(q: PromotionQueryContext, input: PromotionSearchInput): Promise<PromotionOfferPage>;
51
+ /** offerRef 精查;entitlementRef 反查关联 offer;keyword 模糊兜底(LLM 泛指词路由) */
52
+ getOfferDetail(
53
+ q: PromotionQueryContext,
54
+ input: { offerRef?: string; entitlementRef?: string; keyword?: string },
55
+ ): Promise<PromotionOffer | null>;
56
+ recommendOffers(q: PromotionQueryContext, input: PromotionSearchInput): Promise<readonly PromotionOffer[]>;
57
+ /** 可选的适用门店明细;无厂商端点时由调用方保留 notice 降级。 */
58
+ listOfferStores?(q: PromotionQueryContext, offerRef: string): Promise<readonly PromotionStoreSummary[]>;
59
+ /** 最优优惠测算(厂商无此能力可缺省;工具侧不应伪造测算卡) */
60
+ calculateBestDeal?(
61
+ q: PromotionQueryContext,
62
+ input: { currentAmountCents: number; candidateOfferRefs?: readonly string[] },
63
+ ): Promise<PromotionBestDeal>;
64
+ }
65
+
66
+ export interface PromotionStoreSummary {
67
+ readonly storeId: string;
68
+ readonly storeName: string;
69
+ readonly businessName?: string;
70
+ readonly address?: string;
71
+ readonly floor?: string;
72
+ }
73
+
74
+ // ===== 2. PromotionEntitlementPort:已领取资产 =====
75
+
76
+ export interface PromotionEntitlementPort {
77
+ listEntitlements(q: PromotionQueryContext, input: PromotionSearchInput): Promise<PromotionEntitlementPage>;
78
+ getEntitlementDetail(q: PromotionQueryContext, entitlementRef: string): Promise<PromotionEntitlement | null>;
79
+ }
80
+
81
+ // ===== 3. PromotionActivityPort:活动(含场次/指南) =====
82
+
83
+ /** 活动分类(SPEZ-016:活动分类列表;厂商无分类端点时实现方可缺省) */
84
+ export interface PromotionActivityCategoryRecord {
85
+ readonly categoryId: string;
86
+ readonly name: string;
87
+ readonly parentId?: string;
88
+ }
89
+
90
+ export interface PromotionActivityPort {
91
+ listActivities(
92
+ q: PromotionQueryContext,
93
+ input: {
94
+ categoryId?: string;
95
+ keyword?: string;
96
+ dataScope?: 'CURRENT' | 'HISTORY';
97
+ registrationRequired?: boolean;
98
+ startsAfter?: string;
99
+ endsBefore?: string;
100
+ cursor?: string;
101
+ limit?: number;
102
+ },
103
+ ): Promise<PromotionActivityPage>;
104
+ getActivityDetail(q: PromotionQueryContext, activityRef: string): Promise<PromotionActivityDetail | null>;
105
+ /** 独立场次查询,保留旧营销组件的只读接口语义。 */
106
+ listActivitySessions?(q: PromotionQueryContext, activityRef: string): Promise<readonly ActivitySession[]>;
107
+ /** 活动分类(optional——实现未接分类端点时调用方 ?. 降级) */
108
+ listActivityCategories?(): Promise<readonly PromotionActivityCategoryRecord[]>;
109
+ }
110
+
111
+ // ===== 4. PromotionAcquisitionPort:领取写通道 =====
112
+
113
+ export interface PromotionAcquisitionPort {
114
+ /**
115
+ * 领取/报名(写操作)。
116
+ * 幂等:同 idempotencyKey 重复调用返回首果(厂商侧或调用方兜底)。
117
+ * externalMemberRef 由调用方经 member 域状态服务解析(member 域跨模块供给:
118
+ * 'member.status' 判定 + externalMemberRefOf 取真实卡号或 opaque 引用)。
119
+ */
120
+ acquire(
121
+ q: PromotionQueryContext,
122
+ input: { offerRef: string; externalMemberRef: string; idempotencyKey: string },
123
+ ): Promise<PromotionOperation>;
124
+ /** 操作查询(悬挂 PENDING_AUTHORITY 收口用,可缺省) */
125
+ getOperation?(q: PromotionQueryContext, operationRef: string): Promise<PromotionOperation | null>;
6
126
  }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * 导购域 Port 接口(011 S7:shopping-guide 6 Port,TIER1 结构类型子集)。
3
+ * 模块完整实现 extends 本接口;消费方(其他模块)仅依赖契约包。
4
+ * 领域模型见 domain/shopping-guide.ts。
5
+ */
6
+ import type { MallScope } from '../scope';
7
+ import type { RequestContext } from '@tbox.cn/app-contracts';
8
+ import type {
9
+ ProductRecord,
10
+ ProductFacetsRecord,
11
+ ShopRecord,
12
+ CategoryRecord,
13
+ MallDirectoryRecord,
14
+ ShopLocationRecord,
15
+ HumanGuideRecord,
16
+ NearbyMallRecord,
17
+ } from '../domain/shopping-guide';
18
+
19
+ // ===== 导购域 service slot 词汇(与 service-slots.json 同锁) =====
20
+
21
+ export const SHOPPING_CATALOG_SERVICE = 'shopping-guide.catalog';
22
+ export const SHOPPING_SHOPS_SERVICE = 'shopping-guide.shops';
23
+ export const SHOPPING_CATEGORIES_SERVICE = 'shopping-guide.categories';
24
+ export const SHOPPING_DIRECTORY_SERVICE = 'shopping-guide.directory';
25
+
26
+ // ===== 查询上下文(mall scope + 主体) =====
27
+
28
+ export interface ShoppingQueryContext {
29
+ readonly scope: MallScope;
30
+ readonly subjectId?: string;
31
+ readonly requestContext: RequestContext;
32
+ }
33
+
34
+ // ===== 分页 =====
35
+
36
+ export interface ShoppingPage<T> {
37
+ readonly items: readonly T[];
38
+ readonly page: number;
39
+ readonly pageSize: number;
40
+ readonly total: number;
41
+ readonly hasMore: boolean;
42
+ }
43
+
44
+ // ===== 1. CatalogQueryPort:商品目录 =====
45
+
46
+ export interface ProductSearchCriteria {
47
+ readonly ctx: ShoppingQueryContext;
48
+ /** 单值关键词(简单调用方兼容);与 keywords 并存时以 keywords 为准 */
49
+ readonly keyword?: string;
50
+ /** 多角度搜索词组(模型拆词产物):provider 应逐词查询并去重合并(OR 语义),禁止拼串 */
51
+ readonly keywords?: readonly string[];
52
+ readonly categoryCode?: string;
53
+ readonly brandCode?: string;
54
+ readonly minPriceMinor?: number;
55
+ readonly maxPriceMinor?: number;
56
+ readonly floorCode?: string;
57
+ readonly buildingCode?: string;
58
+ readonly page: number;
59
+ readonly pageSize: number;
60
+ readonly marketableOnly?: boolean;
61
+ }
62
+
63
+ export interface CatalogQueryPort {
64
+ searchProducts(criteria: ProductSearchCriteria): Promise<ShoppingPage<ProductRecord>>;
65
+ getProduct(productId: string, ctx: ShoppingQueryContext): Promise<ProductRecord | null>;
66
+ getFacets(criteria: ProductSearchCriteria): Promise<ProductFacetsRecord>;
67
+ }
68
+
69
+ // ===== 2. ShopDirectoryQueryPort:门店目录 =====
70
+
71
+ export interface ShopSearchCriteria {
72
+ readonly ctx: ShoppingQueryContext;
73
+ /** 单值关键词(简单调用方兼容);与 keywords 并存时以 keywords 为准 */
74
+ readonly keyword?: string;
75
+ /** 多角度搜索词组(模型拆词产物):provider 应逐词查询并去重合并(OR 语义),禁止拼串 */
76
+ readonly keywords?: readonly string[];
77
+ readonly brandCode?: string;
78
+ readonly businessCategory?: string;
79
+ readonly floorCode?: string;
80
+ readonly buildingCode?: string;
81
+ readonly page: number;
82
+ readonly pageSize: number;
83
+ }
84
+
85
+ export interface ShopDirectoryQueryPort {
86
+ searchShops(criteria: ShopSearchCriteria): Promise<ShoppingPage<ShopRecord>>;
87
+ getShop(shopId: string, ctx: ShoppingQueryContext): Promise<ShopRecord | null>;
88
+ /**
89
+ * 商场概览快照(可选能力口):品牌导览聚合——楼层 + 业态(权威计数)+ 对 C 透出的预览门店。
90
+ * ⚠️ stores 为首页预览子集非全量(概览卡语义),全量浏览走 searchShops。
91
+ * provider 未实现(缺省)→ 概览问句降级 searchShops 零参。
92
+ */
93
+ fetchStoreOverview?(ctx: ShoppingQueryContext): Promise<MallOverviewSnapshot | null>;
94
+ }
95
+
96
+ /** 商场概览快照(indexBrandGuideAgg 形态归一):mall-overview preTool 出概览 shop-list 卡的数据源 */
97
+ export interface MallOverviewSnapshot {
98
+ readonly mallId: string;
99
+ /** 楼层名列表(如 B1/1F/2F…,agg.floors) */
100
+ readonly floors: readonly string[];
101
+ /** 业态字典(场景 tag + 权威门店计数,agg.tags→CategoryRecord:name=业态、merchantCount=storeNum) */
102
+ readonly categories: readonly CategoryRecord[];
103
+ /** 预览门店(agg.stores——首页透出口径子集,非全量) */
104
+ readonly stores: readonly ShopRecord[];
105
+ readonly observedAt: string;
106
+ }
107
+
108
+ /** @deprecated 使用 ShopSearchCriteria */
109
+ export type MerchantSearchCriteria = ShopSearchCriteria;
110
+ /** @deprecated 使用 ShopDirectoryQueryPort */
111
+ export type MerchantDirectoryQueryPort = ShopDirectoryQueryPort;
112
+
113
+ // ===== 3. CommercialCategoryQueryPort:业态分类 =====
114
+
115
+ export interface CommercialCategoryQueryPort {
116
+ listCategories(ctx: ShoppingQueryContext): Promise<readonly CategoryRecord[]>;
117
+ }
118
+
119
+ // ===== 4. MallDirectoryQueryPort:楼栋-楼层目录 =====
120
+
121
+ export interface MallDirectoryQueryPort {
122
+ getDirectory(ctx: ShoppingQueryContext): Promise<MallDirectoryRecord | null>;
123
+ }
124
+
125
+ // ===== 5. AssistanceQueryPort:人工导购协助 =====
126
+ // (客服 FAQ/知识库两方法已拆分至 customer-service.ts CustomerServiceQueryPort——2026-08-31 客服模块拆分)
127
+
128
+ export interface AssistanceQueryPort {
129
+ listHumanGuides(merchantId: string, ctx: ShoppingQueryContext): Promise<readonly HumanGuideRecord[]>;
130
+ }
131
+
132
+ // ===== 6. NavigationPort:位置/附近商场/浏览历史 =====
133
+
134
+ export interface NavigationPort {
135
+ getLocation(shopId: string, ctx: ShoppingQueryContext): Promise<ShopLocationRecord | null>;
136
+ listNearbyMalls(ctx: ShoppingQueryContext, query?: string): Promise<readonly NearbyMallRecord[]>;
137
+ listBrowsingHistory(ctx: ShoppingQueryContext, page: number, pageSize: number): Promise<ShoppingPage<ProductRecord>>;
138
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 商圈通用卡片片段(0.3.2 D4:actionDraftSchema 单源——从 shopping-guide/cards.ts 抽出,
3
+ * 四域条目动作共用;index.ts 与 runtime.ts 均 re-export 本文件,M2 导出面)。
4
+ */
5
+
6
+ import { z } from 'zod';
7
+
8
+ /**
9
+ * 卡内条目动作草稿(015 F1:判别联合——仅客户端本地语义,write 变体无 token 机制支撑不进)。
10
+ * - send:发消息(value 缺省用 label);link:打开 URL(tel:/https:)。
11
+ * 渲染端经 card-action-handler 既有通道分发(零新机制);zod 判别联合天然拒未知 kind。
12
+ */
13
+ export const actionDraftSchema = z.discriminatedUnion('kind', [
14
+ z.object({
15
+ kind: z.literal('send'),
16
+ label: z.string().min(1),
17
+ /** 发给服务端 AI 的完整指令(可含隐藏上下文如 merchantId);缺省用 label */
18
+ value: z.string().optional(),
19
+ /** 用户气泡展示文本(有值时 sendMessage 走 visible=false 隐藏,只展示此文本为气泡副本);
20
+ * 缺省则 visible=true,直接展示 value/label */
21
+ visibleValue: z.string().optional(),
22
+ }),
23
+ z.object({ kind: z.literal('link'), label: z.string().min(1), url: z.string().min(1) }),
24
+ ]);
25
+ export type ActionDraft = z.infer<typeof actionDraftSchema>;