@tbox.cn/app-contracts-mall 0.2.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/dist/alipay-activity/cards.d.ts +305 -0
- package/dist/assembly.d.ts +73 -7
- package/dist/chunk-KIZD6FZ2.js +43 -0
- package/dist/deployment.d.ts +32 -33
- package/dist/domain/activity.d.ts +64 -0
- package/dist/domain/coupon.d.ts +2 -0
- package/dist/domain/entitlement.d.ts +53 -0
- package/dist/domain/offer.d.ts +111 -0
- package/dist/domain/operation.d.ts +22 -0
- package/dist/domain/parking.d.ts +195 -12
- package/dist/domain/points.d.ts +3 -2
- package/dist/domain/shopping-guide.d.ts +201 -0
- package/dist/index.d.ts +15 -2
- package/dist/mall-scope-url.d.ts +13 -0
- package/dist/member/cards.d.ts +636 -213
- package/dist/parking/cards.d.ts +1271 -0
- package/dist/promotion/cards.d.ts +2529 -0
- package/dist/query-context.d.ts +47 -0
- package/dist/runtime.d.ts +12 -2
- package/dist/runtime.js +940 -86
- package/dist/scope.d.ts +42 -15
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +92 -0
- package/dist/server/mall-context.d.ts +24 -0
- package/dist/server/mall-control-plane.d.ts +10 -0
- package/dist/server/request-credentials.d.ts +22 -0
- package/dist/services/customer-service.d.ts +11 -0
- package/dist/services/mall-info.d.ts +39 -0
- package/dist/services/member.d.ts +188 -31
- package/dist/services/parking.d.ts +115 -11
- package/dist/services/promotion.d.ts +100 -4
- package/dist/services/shopping-guide.d.ts +97 -0
- package/dist/shared/cards.d.ts +42 -0
- package/dist/shopping-guide/cards.d.ts +3399 -561
- package/package.json +19 -7
- package/src/alipay-activity/cards.ts +66 -0
- package/src/assembly.ts +159 -0
- package/src/deployment.ts +44 -0
- package/src/domain/activity.ts +66 -0
- package/src/domain/coupon.ts +11 -0
- package/src/domain/discount.ts +6 -0
- package/src/domain/entitlement.ts +56 -0
- package/src/domain/offer.ts +120 -0
- package/src/domain/operation.ts +40 -0
- package/src/domain/parking.ts +207 -0
- package/src/domain/points.ts +15 -0
- package/src/domain/shopping-guide.ts +242 -0
- package/src/events/index.ts +10 -0
- package/src/guard.ts +48 -0
- package/src/index.ts +34 -0
- package/src/mall-scope-url.ts +21 -0
- package/src/member/cards.ts +209 -0
- package/src/parking/cards.ts +233 -0
- package/src/promotion/cards.ts +290 -0
- package/src/query-context.ts +81 -0
- package/src/runtime.ts +43 -0
- package/src/scope.ts +92 -0
- package/src/server/index.ts +11 -0
- package/src/server/mall-context.ts +39 -0
- package/src/server/mall-control-plane.ts +92 -0
- package/src/server/request-credentials.ts +43 -0
- package/src/service-slots.json +26 -0
- package/src/services/customer-service.ts +12 -0
- package/src/services/mall-info.ts +48 -0
- package/src/services/member.ts +386 -0
- package/src/services/parking.ts +182 -0
- package/src/services/promotion.ts +126 -0
- package/src/services/shopping-guide.ts +138 -0
- package/src/shared/cards.ts +25 -0
- package/src/shopping-guide/cards.ts +438 -0
- package/tests/assembly-validate-scope.test.ts +132 -0
- package/tests/cards.test.ts +586 -0
- package/tests/context-unification.test.ts +73 -0
- package/tests/mall-control-plane.test.ts +169 -0
- package/tests/mall-scope-url.test.ts +59 -0
- package/tests/member-status.test.ts +197 -0
- package/tests/query-context.test.ts +111 -0
- package/tests/request-credentials.test.ts +38 -0
- package/tests/resolve-primitives.test.ts +55 -0
- package/tests/service-slots.test.ts +83 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +5 -0
- package/dist/shopping-guide/ports.d.ts +0 -216
package/package.json
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tbox.cn/app-contracts-mall",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "商圈领域契约(TIER1,types + runtime):Port 接口 + MallEventMap + 领域 DTO + scope/装配器运行时。",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"import": "./dist/runtime.js"
|
|
10
|
+
},
|
|
11
|
+
"./server": {
|
|
12
|
+
"types": "./dist/server/index.d.ts",
|
|
13
|
+
"import": "./dist/server/index.js"
|
|
10
14
|
}
|
|
11
15
|
},
|
|
12
16
|
"files": [
|
|
13
17
|
"dist",
|
|
18
|
+
"src",
|
|
19
|
+
"tests",
|
|
20
|
+
"tsconfig.json",
|
|
21
|
+
"tsconfig.build.json",
|
|
14
22
|
"README.md",
|
|
15
23
|
"LICENSE"
|
|
16
24
|
],
|
|
@@ -21,16 +29,20 @@
|
|
|
21
29
|
"access": "public"
|
|
22
30
|
},
|
|
23
31
|
"dependencies": {
|
|
24
|
-
"@tbox.cn/app-contracts": "
|
|
25
|
-
"zod": "
|
|
32
|
+
"@tbox.cn/app-contracts": "0.10.0",
|
|
33
|
+
"zod": "3.25.76"
|
|
26
34
|
},
|
|
27
35
|
"devDependencies": {
|
|
28
|
-
"
|
|
29
|
-
"
|
|
36
|
+
"@tbox.cn/app-sdk": "0.19.0",
|
|
37
|
+
"tsup": "8.5.1",
|
|
38
|
+
"typescript": "5.9.3",
|
|
39
|
+
"vitest": "4.1.10",
|
|
40
|
+
"happy-dom": "20.11.2"
|
|
30
41
|
},
|
|
31
42
|
"license": "MIT",
|
|
32
43
|
"scripts": {
|
|
33
|
-
"build": "tsc -p tsconfig.build.json && tsup src/runtime.ts --format esm --external @ag-ui/core --out-dir dist",
|
|
34
|
-
"typecheck": "tsc --noEmit"
|
|
44
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json && tsup src/runtime.ts src/server/index.ts --format esm --external @ag-ui/core --out-dir dist",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"test": "vitest run"
|
|
35
47
|
}
|
|
36
48
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 支付宝「碰出惊喜」互动营销活动卡片数据契约。
|
|
3
|
+
* alipay-activity 专属——与 promotion 通用卡型解耦,独立维护。
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
|
|
7
|
+
/** 单张优惠券奖品 */
|
|
8
|
+
const bumpInVoucherSchema = z.object({
|
|
9
|
+
prizeId: z.string(),
|
|
10
|
+
voucherName: z.string(),
|
|
11
|
+
voucherType: z.string(),
|
|
12
|
+
reductionAmount: z.string(),
|
|
13
|
+
thresholdAmountText: z.string(),
|
|
14
|
+
unit: z.string(),
|
|
15
|
+
merchantName: z.string(),
|
|
16
|
+
merchantLogo: z.string().optional(),
|
|
17
|
+
itemLogo: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
export type BumpInVoucher = z.infer<typeof bumpInVoucherSchema>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 碰出惊喜活动生命周期状态(支付宝 IoT NSP 权威枚举):
|
|
23
|
+
* NOT_START 未开始 / INIT 初始化 / PROCESSING 进行中 / FINISH 已完成 / RECEIVED 已领奖。
|
|
24
|
+
* RECEIVED 是用户级终态(奖励已领取),其余为活动级状态。
|
|
25
|
+
*/
|
|
26
|
+
export const bumpInActStatusSchema = z.enum([
|
|
27
|
+
'NOT_START',
|
|
28
|
+
'INIT',
|
|
29
|
+
'PROCESSING',
|
|
30
|
+
'FINISH',
|
|
31
|
+
'RECEIVED',
|
|
32
|
+
]);
|
|
33
|
+
export type BumpInActStatus = z.infer<typeof bumpInActStatusSchema>;
|
|
34
|
+
|
|
35
|
+
/** promotion-bumpin-activity:进度 + 奖励池,detail/banner 双模式 */
|
|
36
|
+
export const promotionBumpInActivityCardDataSchema = z.object({
|
|
37
|
+
activityRef: z.string(),
|
|
38
|
+
title: z.string(),
|
|
39
|
+
mainTitle: z.string().optional(),
|
|
40
|
+
coverUrl: z.string().optional(),
|
|
41
|
+
/** 联单活动全幅背景图 URL(与 coverUrl 互斥;backgroundUrl 存在时头部采用全幅覆盖布局) */
|
|
42
|
+
backgroundUrl: z.string().optional(),
|
|
43
|
+
/** 左上角活动类型胶囊标签,如"碰一下联单" */
|
|
44
|
+
tagLabel: z.string().optional(),
|
|
45
|
+
cardLogoUrl: z.string().optional(),
|
|
46
|
+
actStatus: bumpInActStatusSchema,
|
|
47
|
+
totalProgress: z.string().optional(),
|
|
48
|
+
currentProgress: z.string().optional(),
|
|
49
|
+
progressUnit: z.string().optional(),
|
|
50
|
+
startAtText: z.string().optional(),
|
|
51
|
+
endAtText: z.string().optional(),
|
|
52
|
+
description: z.string().optional(),
|
|
53
|
+
vouchers: z.array(bumpInVoucherSchema),
|
|
54
|
+
mode: z.enum(['detail', 'banner']).default('detail'),
|
|
55
|
+
/** bar(线性进度条,默认)| steps(圆形步骤节点,适合联单任务) */
|
|
56
|
+
progressStyle: z.enum(['bar', 'steps']).default('bar'),
|
|
57
|
+
/** 参与步骤(联单活动 guide.steps;banner 模式用于渲染步骤进度节点) */
|
|
58
|
+
steps: z.array(z.object({ title: z.string(), description: z.string().optional() })).optional(),
|
|
59
|
+
});
|
|
60
|
+
export type PromotionBumpInActivityCardData = z.infer<typeof promotionBumpInActivityCardDataSchema>;
|
|
61
|
+
|
|
62
|
+
export const alipayActivityCardDataSchemas = {
|
|
63
|
+
'promotion-bumpin-activity': promotionBumpInActivityCardDataSchema,
|
|
64
|
+
} as const;
|
|
65
|
+
|
|
66
|
+
export type AlipayActivityCardType = keyof typeof alipayActivityCardDataSchemas;
|
package/src/assembly.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 商圈装配器(011 B2:TIER1 领域运行时):
|
|
3
|
+
* 纯函数——extractScopeKey/validateScope/extractMallScope,
|
|
4
|
+
* SDK 原语(ScopeSessionRegistry/ProviderRegistry)组合在模板装配点完成(011 L1)。
|
|
5
|
+
*
|
|
6
|
+
* 不 import app-sdk(依赖方向:contracts-mall → contracts;SDK 不依赖 TIER1)。
|
|
7
|
+
*
|
|
8
|
+
* integrations v4 恒动态:参考表(instances 注册表)纯元数据,永不充当解析闸门——
|
|
9
|
+
* 白名单/动态判定(dynamicMalls/mallIdAllowed)退役。任意合法拓扑形态(注册表缺席/非空)
|
|
10
|
+
* 均支持动态 mallId 会话;实例集限制是 provider 业务限制的表达位(槽 instances 激活表
|
|
11
|
+
* 显式键集 → 数据面 INSTANCE_NOT_FOUND),非框架限制。WS/HTTP 两形态共享单一形状守卫核。
|
|
12
|
+
*/
|
|
13
|
+
import type { RequestContext, ScopeAssemblyContract } from '@tbox.cn/app-contracts';
|
|
14
|
+
import type { MallDeploymentControlPlane } from './deployment';
|
|
15
|
+
import {
|
|
16
|
+
extractMallScope,
|
|
17
|
+
parseMallScope,
|
|
18
|
+
MALL_SCOPE_KEY,
|
|
19
|
+
type MallScope,
|
|
20
|
+
} from './scope';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* mall 域登录换码槽(integrations services 键;TIER1 拥有 mall 域槽位词汇——
|
|
24
|
+
* provider 包与模板装配点经本常量收敛,禁止各处拼写 'auth.alipay-login' 字面量)。
|
|
25
|
+
*/
|
|
26
|
+
export const AUTH_LOGIN_SERVICE = 'auth.alipay-login';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* mall 域装配形状(TIER0 ScopeAssemblyContract 的 TIER1 具体化;W3-3 自 module-mall-core 下沉):
|
|
30
|
+
* module-mall-core register 期注册于 ctx.domainAssemblies(SCOPE_ASSEMBLY_KIND),
|
|
31
|
+
* 消费方(模板装配点/module-mall-home/SDK)按本类型泛型断言查表——域模块间零包依赖
|
|
32
|
+
* (workspace-dag 铁律:跨模块走注册表 + 契约类型)。
|
|
33
|
+
* 成员 = 模板装配点(validateContext/scopeSessions/start 装点/WS 双钩)最小必要性合集。
|
|
34
|
+
*/
|
|
35
|
+
export interface MallScopeAssembly extends ScopeAssemblyContract {
|
|
36
|
+
/** 控制平面(只读快照;纯元数据参考表——展示/目录/默认解析消费,非闸门) */
|
|
37
|
+
readonly controlPlane: Readonly<MallDeploymentControlPlane>;
|
|
38
|
+
/** root config.miniAppId(登录槽 code2Session 入参真源;enhance 回填 + default 兜底共用) */
|
|
39
|
+
readonly rootMiniAppId: string | undefined;
|
|
40
|
+
/** scope 键提取(SDK ScopeSessionRegistry 注入点) */
|
|
41
|
+
extractScopeKey(ctx: RequestContext): string;
|
|
42
|
+
/** scope 形状校验(SDK ScopeSessionRegistry 注入点 + HTTP validateContext 同核) */
|
|
43
|
+
validateScope(attributes: Record<string, unknown>): boolean;
|
|
44
|
+
/** 提取 MallScope(模块 handler 前置;无 scope → undefined 由调用方降级) */
|
|
45
|
+
extractMallScope(ctx: RequestContext): MallScope | undefined;
|
|
46
|
+
/** 领域扁平 scope(原始形态;ActionGrant/memory 隔离等消费) */
|
|
47
|
+
buildScope(attributes: Record<string, unknown>): Record<string, string>;
|
|
48
|
+
/** 扁平 scope + mallName 回填(scopeSessions 注入点;三级回退见 withMallName) */
|
|
49
|
+
buildScopeWithMallName(attributes: Record<string, unknown>): Record<string, string>;
|
|
50
|
+
/** instanceId 提取(integrations 槽解析轴;SDK 零领域注入点) */
|
|
51
|
+
instanceIdOf(scope: Record<string, string>): string;
|
|
52
|
+
/** 域默认值(SDK ctx.scopeDefaults 视图唯一直接消费面) */
|
|
53
|
+
readonly scopeDefaults: Readonly<Record<string, unknown>> | undefined;
|
|
54
|
+
/** 016:默认商圈 HELLO context(无 URL 参数访问时的服务端兜底;缺省 defaultMallId → undefined) */
|
|
55
|
+
defaultMallContext(): Record<string, unknown> | undefined;
|
|
56
|
+
/** D1:ENHANCE_CTX 双职责(miniAppId 回填 + mall.info 预热;fail-soft——抛错/超时原 context 继续) */
|
|
57
|
+
enhanceHelloContext(context: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 形状守卫核(WS/HTTP 两形态共享单一来源):
|
|
62
|
+
* - mall 键缺席 → true(非 mall 部署/无 context 放行——校验面不因缺 mall 拒绝;
|
|
63
|
+
* '' scopeKey = 全局会话);
|
|
64
|
+
* - mall 键在场 → mallId 非空串(会话边界键唯一硬要求;miniAppId 可选——
|
|
65
|
+
* 客户端发送侧本就条件附加,v4 起服务端不再要求)。
|
|
66
|
+
*/
|
|
67
|
+
export function isValidMallShape(attributes: Record<string, unknown>): boolean {
|
|
68
|
+
const mall = attributes[MALL_SCOPE_KEY];
|
|
69
|
+
if (!mall || typeof mall !== 'object') return true;
|
|
70
|
+
const mallId = (mall as Record<string, unknown>).mallId;
|
|
71
|
+
return typeof mallId === 'string' && mallId.length > 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** 装配器产物:模板注入 createScopeSessionRegistry 的 extractor/validator + 领域提取函数 */
|
|
75
|
+
export interface MallRuntimeAssembly {
|
|
76
|
+
/**
|
|
77
|
+
* scope 键提取(SDK ScopeSessionRegistry 注入点):
|
|
78
|
+
* mall scope 在场 → mallId;防御兜底 ''(主通路:无 mall context 不触发 bootstrap,
|
|
79
|
+
* 本函数不会被无 scope 会话调用)。
|
|
80
|
+
*/
|
|
81
|
+
extractScopeKey(ctx: RequestContext): string;
|
|
82
|
+
/** scope 形状校验(SDK ScopeSessionRegistry 注入点):单一形状守卫核(白名单判定已退役) */
|
|
83
|
+
validateScope(attributes: Record<string, unknown>): boolean;
|
|
84
|
+
/** 011 D1:领域扁平 scope(回显 + ActionGrant 签发/校验单一来源) */
|
|
85
|
+
buildScope(attributes: Record<string, unknown>): Record<string, string>;
|
|
86
|
+
/** 提取 MallScope(模块 handler 前置;无 scope → undefined 由调用方降级) */
|
|
87
|
+
extractMallScope(ctx: RequestContext): MallScope | undefined;
|
|
88
|
+
/** 控制平面(只读快照;纯元数据参考表——展示/目录/默认解析消费,非闸门) */
|
|
89
|
+
controlPlane: Readonly<MallDeploymentControlPlane>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function createMallRuntimeAssembly(
|
|
93
|
+
controlPlane: MallDeploymentControlPlane,
|
|
94
|
+
): MallRuntimeAssembly {
|
|
95
|
+
return {
|
|
96
|
+
extractScopeKey(ctx: RequestContext): string {
|
|
97
|
+
// 防御兜底 ''(全局会话):主通路中无 mall context 的连接不触发 bootstrap(ws-server 语义),
|
|
98
|
+
// 有 mall context 则 mallId 必非空(isValidMallShape 已守卫)
|
|
99
|
+
const scope = extractMallScope(ctx);
|
|
100
|
+
return scope?.mallId ?? '';
|
|
101
|
+
},
|
|
102
|
+
validateScope(attributes: Record<string, unknown>): boolean {
|
|
103
|
+
// 形状不过(mall 键在场但 mallId 缺失/空)→ console.error 提示配置排查方向
|
|
104
|
+
const ok = isValidMallShape(attributes);
|
|
105
|
+
if (!ok) {
|
|
106
|
+
console.error(
|
|
107
|
+
'[MALL] HELLO context 形状非法(需 mall.mallId 非空——URL 参数 ?mallId=;miniAppId 可选)',
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return ok;
|
|
111
|
+
},
|
|
112
|
+
buildScope(attributes: Record<string, unknown>): Record<string, string> {
|
|
113
|
+
const scope = parseMallScope(attributes);
|
|
114
|
+
if (!scope) return {};
|
|
115
|
+
// miniAppId 可选:按在场透传(ActionGrant 签发/校验双端同构——同函数双调用,形状天然一致)
|
|
116
|
+
return {
|
|
117
|
+
mallId: scope.mallId,
|
|
118
|
+
...(scope.miniAppId !== undefined ? { miniAppId: scope.miniAppId } : {}),
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
extractMallScope,
|
|
122
|
+
controlPlane,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* HTTP validateContext 形态(上下文统一化全局面注入点):与 WS validateScope
|
|
128
|
+
* 共享同一形状守卫核(isValidMallShape)——单一来源,勿再分叉。
|
|
129
|
+
* HTTP 面消费 mallId-only 形状(login/dev-login 的 body.context 有独立归一化,
|
|
130
|
+
* 不套 MallScope 全形状);miniAppId 不要求(消费点自补:linked-panel 自查表;
|
|
131
|
+
* WS 面由 enhanceContext 补——两形态不对称有内在一致性,勿补对称)。
|
|
132
|
+
*/
|
|
133
|
+
export function createMallContextValidator(): (attributes: Record<string, unknown>) => boolean {
|
|
134
|
+
return isValidMallShape;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 014 T1:buildScope 包装——从控制平面参考表回填 mallName(自 mall 模板 deployment.ts
|
|
139
|
+
* 迁入,单一模板统一化 W1-①)。
|
|
140
|
+
* scopeFlat(mallId[+miniAppId])→ HELLO_ACK.mallScope 回显,mallName 为壳品牌区
|
|
141
|
+
* (ChatHeader)服务端真源。
|
|
142
|
+
*
|
|
143
|
+
* 三级回退(动态商场):参考表命中 → mall.name;未命中 → fallbackName?.(mallId)
|
|
144
|
+
* (mall.info 槽缓存)→ 双 miss 原样返回(降级)。
|
|
145
|
+
*/
|
|
146
|
+
export function withMallName(
|
|
147
|
+
assembly: MallRuntimeAssembly,
|
|
148
|
+
controlPlane: MallDeploymentControlPlane,
|
|
149
|
+
fallbackName?: (mallId: string) => string | undefined,
|
|
150
|
+
): (attributes: Record<string, unknown>) => Record<string, string> {
|
|
151
|
+
return (attributes) => {
|
|
152
|
+
const scope = assembly.buildScope(attributes);
|
|
153
|
+
const mallId = parseMallScope(attributes)?.mallId;
|
|
154
|
+
const mall = mallId ? controlPlane.malls.find((m) => m.mallId === mallId) : undefined;
|
|
155
|
+
if (mall) return { ...scope, mallName: mall.name };
|
|
156
|
+
const fallback = mallId ? fallbackName?.(mallId) : undefined;
|
|
157
|
+
return fallback ? { ...scope, mallName: fallback } : scope;
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 商圈部署控制平面(纯 mall 域两键:零重复收敛):
|
|
3
|
+
* malls(参考表——纯元数据,v4 起永不充当解析闸门)+ defaultMallId(默认商圈)。
|
|
4
|
+
* 构造来源 = mallControlPlaneOf 投影(server/mall-control-plane.ts):root instances
|
|
5
|
+
* 注册表(integrations v4)→ 本形状;无参考表 → 空平面(模板装配零拓扑分支)。
|
|
6
|
+
* provider 绑定唯一真源 = config/integrations.json(integrations v4:绑定组整组继承 + catalog 派生,
|
|
7
|
+
* 真源 providers.md)——控制面不再承载
|
|
8
|
+
* providerTemplates/providerInstances(换码走 resolveLoginExchange、旁路 bumpin 走
|
|
9
|
+
* config/bumpin.json 配置面)。无内联密钥(loader 断言在模板层)。
|
|
10
|
+
* 014:deployment(miniAppId/agentId/components)整体移除——零消费方(代码即事实),
|
|
11
|
+
* 能力开关 = 模块 add/remove,非部署级 feature 裁剪。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** 商圈白名单项 */
|
|
15
|
+
export interface MallDeploymentMall {
|
|
16
|
+
mallId: string;
|
|
17
|
+
name: string;
|
|
18
|
+
/** 客服电话(可选;shopping-guide customer-service-faq 卡 link 拨打条目消费,缺省不渲染) */
|
|
19
|
+
contactPhone?: string;
|
|
20
|
+
/** 小程序 appId(可选拓扑值;mall 级共享——HELLO context.mall.miniAppId 的配置承载,供默认商圈拼装) */
|
|
21
|
+
miniAppId?: string;
|
|
22
|
+
/**
|
|
23
|
+
* 地理坐标(可选;有值时参与 /api/m/mall-home/nearby-mall 就近推荐;缺省不参与排序)。
|
|
24
|
+
* 坐标系:WGS-84(高德/支付宝 getLocation 默认输出)。
|
|
25
|
+
*/
|
|
26
|
+
location?: {
|
|
27
|
+
lat: number;
|
|
28
|
+
lon: number;
|
|
29
|
+
/** 展示地址(可选;推荐 Banner 展示用) */
|
|
30
|
+
address?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 部署控制平面(mallControlPlaneOf 投影产物;provider 绑定迁 integrations 后纯两键) */
|
|
35
|
+
export interface MallDeploymentControlPlane {
|
|
36
|
+
/** 商圈参考表(纯元数据:目录/展示/默认解析;v4 起非会话闸门) */
|
|
37
|
+
malls: MallDeploymentMall[];
|
|
38
|
+
/**
|
|
39
|
+
* 默认商圈(可选):无 URL 参数访问时服务端补入 HELLO context 的 mallId。
|
|
40
|
+
* 来源 = normalizeInstances(显式 ?? 单实例唯一解);参考表缺席时仍可在场
|
|
41
|
+
* (env 注入动态默认形态——defaultInstanceId 独立键);URL 显式参数优先级更高。
|
|
42
|
+
*/
|
|
43
|
+
defaultMallId?: string;
|
|
44
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 营销活动域模型(015,TIER1):活动聚合 + 场次 + 参与指南。
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface PromotionActivity {
|
|
6
|
+
/** 报名/详情深链(provider 出参快照,数据驱动;缺省 = 无报名通道) */
|
|
7
|
+
registrationUrl?: string;
|
|
8
|
+
readonly activityRef: string;
|
|
9
|
+
readonly title: string;
|
|
10
|
+
readonly subtitle?: string;
|
|
11
|
+
readonly coverUrl?: string;
|
|
12
|
+
readonly categoryId?: string;
|
|
13
|
+
/** 是否需要报名 */
|
|
14
|
+
readonly registrationRequired: boolean;
|
|
15
|
+
/** 剩余名额(厂商事实,可缺省) */
|
|
16
|
+
readonly remainingQuota?: number;
|
|
17
|
+
readonly startAt?: string;
|
|
18
|
+
readonly endAt?: string;
|
|
19
|
+
/** 活动关联 Offer(可领取优惠券等) */
|
|
20
|
+
readonly offerRefs: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* 联单/累计型活动(N 笔累计解锁奖励;卡片走 steps 进度形态)。
|
|
23
|
+
* 厂商中立语义标志:由 provider 按厂商侧活动类型枚举映射(如支付宝 actType=N_COUNT_TYPE),
|
|
24
|
+
* 消费方不得用标题关键字自行判定。
|
|
25
|
+
*/
|
|
26
|
+
readonly linkedOrder?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* 活动生命周期状态(厂商侧枚举经 provider 映射为中立语义,如支付宝碰出惊喜
|
|
29
|
+
* NOT_START/INIT/PROCESSING/FINISH/RECEIVED)。缺省 = 无法判定,消费方按进行中兜底展示。
|
|
30
|
+
*/
|
|
31
|
+
readonly activityStatus?: string;
|
|
32
|
+
/** 首页资源位没有独立详情时为 true;用于调整卡片文案而不改变历史活动语义。 */
|
|
33
|
+
readonly jumpOnly?: boolean;
|
|
34
|
+
/** 资源位跳转按钮文案,缺省由卡片按活动/资源位语义生成。 */
|
|
35
|
+
readonly jumpLabel?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PromotionActivityPage {
|
|
39
|
+
readonly items: readonly PromotionActivity[];
|
|
40
|
+
readonly nextCursor?: string;
|
|
41
|
+
readonly hasMore: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 活动场次 */
|
|
45
|
+
export interface ActivitySession {
|
|
46
|
+
readonly sessionRef: string;
|
|
47
|
+
readonly title: string;
|
|
48
|
+
readonly startAt: string;
|
|
49
|
+
readonly endAt?: string;
|
|
50
|
+
readonly location?: string;
|
|
51
|
+
readonly remainingQuota?: number;
|
|
52
|
+
readonly status: 'OPEN' | 'FULL' | 'CLOSED' | 'UNKNOWN';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 参与指南(步骤 + 条款) */
|
|
56
|
+
export interface ActivityGuide {
|
|
57
|
+
readonly steps: ReadonlyArray<{ readonly title: string; readonly description?: string }>;
|
|
58
|
+
readonly conditions: readonly string[];
|
|
59
|
+
readonly notice?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface PromotionActivityDetail extends PromotionActivity {
|
|
63
|
+
readonly description?: string;
|
|
64
|
+
readonly sessions: readonly ActivitySession[];
|
|
65
|
+
readonly guide?: ActivityGuide;
|
|
66
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** 优惠券(商圈领域 DTO) */
|
|
2
|
+
export interface Coupon {
|
|
3
|
+
couponId: string;
|
|
4
|
+
title: string;
|
|
5
|
+
/** 可抵扣金额(元) */
|
|
6
|
+
amount: number;
|
|
7
|
+
status: 'AVAILABLE' | 'USED' | 'EXPIRED';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** 免费券领取通道;缺省由消费方保持既有直领语义。 */
|
|
11
|
+
export type FreeCouponClaimMode = 'DIRECT' | 'REDIRECT';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 营销权益(已领取资产)域模型(015,TIER1)。
|
|
3
|
+
*/
|
|
4
|
+
import type { OfferType } from './offer';
|
|
5
|
+
|
|
6
|
+
export type EntitlementStatus = 'EFFECTIVE' | 'USED' | 'EXPIRED' | 'INVALID' | 'UNKNOWN';
|
|
7
|
+
|
|
8
|
+
export interface PromotionEntitlement {
|
|
9
|
+
readonly entitlementRef: string;
|
|
10
|
+
readonly offerRef?: string;
|
|
11
|
+
readonly title: string;
|
|
12
|
+
/** 厂商券面图;相对路径由 Provider Adapter 归一为 HTTPS URL。 */
|
|
13
|
+
readonly imageUrl?: string;
|
|
14
|
+
readonly entitlementType: OfferType;
|
|
15
|
+
readonly status: EntitlementStatus;
|
|
16
|
+
/** 已授权 C 端详情使用的完整券码(不得写入日志) */
|
|
17
|
+
readonly code?: string;
|
|
18
|
+
readonly codeMasked?: string;
|
|
19
|
+
/** 小程序券码区域是否允许生成二维码;状态置灰不影响该能力。 */
|
|
20
|
+
readonly qrCodeEnabled?: boolean;
|
|
21
|
+
readonly stores?: ReadonlyArray<{
|
|
22
|
+
storeId: string;
|
|
23
|
+
storeName: string;
|
|
24
|
+
businessName?: string;
|
|
25
|
+
imageUrl?: string;
|
|
26
|
+
address?: string;
|
|
27
|
+
floor?: string;
|
|
28
|
+
latitude?: number;
|
|
29
|
+
longitude?: number;
|
|
30
|
+
}>;
|
|
31
|
+
/** 生效/过期窗口(ISO8601) */
|
|
32
|
+
readonly validFrom?: string;
|
|
33
|
+
readonly validUntil?: string;
|
|
34
|
+
/** 原生券面有效期文案(例如“含领取之日起7天内有效”)。 */
|
|
35
|
+
readonly validityText?: string;
|
|
36
|
+
/** 抵扣价值(cents;PERCENTAGE 类为折扣分子) */
|
|
37
|
+
readonly valueCents?: number;
|
|
38
|
+
readonly discountPercent?: number;
|
|
39
|
+
readonly thresholdText?: string;
|
|
40
|
+
readonly benefitText?: string;
|
|
41
|
+
readonly usageNotice?: string;
|
|
42
|
+
readonly guaranteeText?: string;
|
|
43
|
+
readonly usageSceneText?: string;
|
|
44
|
+
/** 使用时间(如 00:00:00 至 23:59:59)。 */
|
|
45
|
+
readonly usageTimeText?: string;
|
|
46
|
+
/** 可领取时间窗口。 */
|
|
47
|
+
readonly claimTimeText?: string;
|
|
48
|
+
/** 原生券面“使用规则”富文本。 */
|
|
49
|
+
readonly usageRuleText?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface PromotionEntitlementPage {
|
|
53
|
+
readonly items: readonly PromotionEntitlement[];
|
|
54
|
+
readonly nextCursor?: string;
|
|
55
|
+
readonly hasMore: boolean;
|
|
56
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 营销 Offer 域模型(015:POC marketing domain/offer 精华沉淀,TIER1)。
|
|
3
|
+
* 五类 facet 判别联合 + 可用性事实 + 参与方式;金额 cents(域内 number)。
|
|
4
|
+
*/
|
|
5
|
+
import type { FreeCouponClaimMode } from './coupon';
|
|
6
|
+
|
|
7
|
+
/** 券面值类型 */
|
|
8
|
+
export interface CouponFacet {
|
|
9
|
+
readonly kind: 'COUPON';
|
|
10
|
+
readonly discountType: 'AMOUNT' | 'PERCENTAGE';
|
|
11
|
+
/** AMOUNT → cents;PERCENTAGE → 折扣率分子(85 = 8.5 折) */
|
|
12
|
+
readonly value: number;
|
|
13
|
+
/** 使用门槛(cents) */
|
|
14
|
+
readonly thresholdCents?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface BundleFacet {
|
|
18
|
+
readonly kind: 'BUNDLE';
|
|
19
|
+
readonly items: ReadonlyArray<{ readonly name: string; readonly quantity: number }>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface PromotionFacet {
|
|
23
|
+
readonly kind: 'PROMOTION';
|
|
24
|
+
readonly ruleType: 'FULL_REDUCTION' | 'DISCOUNT' | 'LADDER';
|
|
25
|
+
readonly ruleDescription: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ActivityFacet {
|
|
29
|
+
readonly kind: 'ACTIVITY';
|
|
30
|
+
readonly registrationRequired: boolean;
|
|
31
|
+
readonly capacity?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface GrouponFacet {
|
|
35
|
+
readonly kind: 'GROUPON';
|
|
36
|
+
readonly requiredParticipants: number;
|
|
37
|
+
readonly groupExpiresInSeconds?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type OfferFacet = CouponFacet | BundleFacet | PromotionFacet | ActivityFacet | GrouponFacet;
|
|
41
|
+
|
|
42
|
+
export type OfferType = 'COUPON' | 'BUNDLE' | 'PROMOTION' | 'ACTIVITY' | 'GROUPON';
|
|
43
|
+
|
|
44
|
+
/** 可用性(厂商事实,非客户端推断) */
|
|
45
|
+
export interface OfferAvailability {
|
|
46
|
+
readonly status: 'AVAILABLE' | 'UNAVAILABLE' | 'REQUIRES_ACTION' | 'UNKNOWN';
|
|
47
|
+
readonly reasonCodes: readonly string[];
|
|
48
|
+
readonly evaluatedAt: string;
|
|
49
|
+
/** true = 厂商实时评估;false = 目录静态推断(领取前须厂商校验) */
|
|
50
|
+
readonly authoritative: boolean;
|
|
51
|
+
readonly requiredActions?: readonly string[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type ParticipationMode =
|
|
55
|
+
| 'AUTOMATIC_DISCOUNT'
|
|
56
|
+
| 'CLAIM_THEN_PURCHASE'
|
|
57
|
+
| 'REGISTER_THEN_ATTEND'
|
|
58
|
+
| 'GROUP_PURCHASE'
|
|
59
|
+
| 'UNKNOWN';
|
|
60
|
+
|
|
61
|
+
export interface OfferParticipation {
|
|
62
|
+
readonly mode: ParticipationMode;
|
|
63
|
+
readonly steps: ReadonlyArray<{ readonly title: string; readonly description: string }>;
|
|
64
|
+
readonly requirements?: readonly string[];
|
|
65
|
+
readonly notice?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** 营销 Offer(厂商实例聚合根引用) */
|
|
69
|
+
export interface PromotionOffer {
|
|
70
|
+
readonly offerRef: string;
|
|
71
|
+
readonly providerInstanceId?: string;
|
|
72
|
+
readonly offerType: OfferType;
|
|
73
|
+
readonly title: string;
|
|
74
|
+
readonly subtitle?: string;
|
|
75
|
+
readonly description?: string;
|
|
76
|
+
readonly imageUrl?: string;
|
|
77
|
+
/** Provider 直出的 C 端展示文案,避免客户端从金额/规则反推语义。 */
|
|
78
|
+
readonly priceText?: string;
|
|
79
|
+
readonly originalPriceText?: string;
|
|
80
|
+
readonly discountLabel?: string;
|
|
81
|
+
readonly claimActionLabel?: string;
|
|
82
|
+
/** 券的小程序详情入口;付费券抢购、免费券 REDIRECT 均由客户端在弹窗内唤起。 */
|
|
83
|
+
readonly purchaseUrl?: string;
|
|
84
|
+
/** 仅免费券消费;付费券始终使用 purchaseUrl 跳转。 */
|
|
85
|
+
readonly freeCouponClaimMode?: FreeCouponClaimMode;
|
|
86
|
+
readonly stockText?: string;
|
|
87
|
+
readonly usageNoticeText?: string;
|
|
88
|
+
readonly usageSceneText?: string;
|
|
89
|
+
readonly usageTimeText?: string;
|
|
90
|
+
readonly claimTimeText?: string;
|
|
91
|
+
/** Provider 直出的有效期文案(如「含领取之日起 7 天内有效」)。 */
|
|
92
|
+
readonly validityText?: string;
|
|
93
|
+
readonly usageRuleText?: string;
|
|
94
|
+
readonly guaranteeText?: string;
|
|
95
|
+
readonly tags: readonly string[];
|
|
96
|
+
/** ISO8601 有效期 [start, end] */
|
|
97
|
+
readonly validity: { readonly start?: string; readonly end: string };
|
|
98
|
+
readonly facets: readonly OfferFacet[];
|
|
99
|
+
readonly participation?: OfferParticipation;
|
|
100
|
+
readonly availability: OfferAvailability;
|
|
101
|
+
/** 领取/参与入口的厂商外部绑定(activityId 等,不透明) */
|
|
102
|
+
readonly externalBinding?: Readonly<Record<string, string>>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Offer 分页(cursor 透传) */
|
|
106
|
+
export interface PromotionOfferPage {
|
|
107
|
+
readonly items: readonly PromotionOffer[];
|
|
108
|
+
readonly nextCursor?: string;
|
|
109
|
+
readonly hasMore: boolean;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** 最优优惠测算(calculateBestDeal) */
|
|
113
|
+
export interface PromotionBestDeal {
|
|
114
|
+
readonly offerRef: string;
|
|
115
|
+
readonly title: string;
|
|
116
|
+
/** 预估优惠(cents) */
|
|
117
|
+
readonly estimatedSavingCents: number;
|
|
118
|
+
readonly reason: string;
|
|
119
|
+
readonly candidatesConsidered: number;
|
|
120
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 营销写操作域模型(015,TIER1):POC MarketingOperation 状态机沉淀。
|
|
3
|
+
* CREATED → EXECUTING → SUCCEEDED | PARTIAL | REJECTED | PENDING_AUTHORITY。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type PromotionOperationStatus =
|
|
7
|
+
| 'CREATED'
|
|
8
|
+
| 'EXECUTING'
|
|
9
|
+
| 'SUCCEEDED'
|
|
10
|
+
| 'PARTIAL'
|
|
11
|
+
| 'REJECTED'
|
|
12
|
+
| 'PENDING_AUTHORITY';
|
|
13
|
+
|
|
14
|
+
/** 操作终态(模块出卡只关心四态;CREATED/EXECUTING 为过程态不出卡) */
|
|
15
|
+
export type PromotionOperationOutcome = Extract<
|
|
16
|
+
PromotionOperationStatus,
|
|
17
|
+
'SUCCEEDED' | 'PARTIAL' | 'REJECTED' | 'PENDING_AUTHORITY'
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
export interface PromotionOperation {
|
|
21
|
+
readonly operationRef: string;
|
|
22
|
+
readonly status: PromotionOperationStatus;
|
|
23
|
+
readonly offerRef: string;
|
|
24
|
+
/** 厂商操作引用(对账/查询用,不透明) */
|
|
25
|
+
readonly externalOperationRef?: string;
|
|
26
|
+
/** 成功领取后的券码(脱敏) */
|
|
27
|
+
readonly codeMasked?: string;
|
|
28
|
+
/** 厂商错误码(30013 未授权 / 636·637 库存 / 638 重复 / 30017 不合格 等) */
|
|
29
|
+
readonly code?: string;
|
|
30
|
+
readonly message?: string;
|
|
31
|
+
readonly observedAt: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** acquire 的厂商拒绝语义分类(错误码映射产物,出卡文案用) */
|
|
35
|
+
export type PromotionRejectionKind =
|
|
36
|
+
| 'AUTH_FAILED'
|
|
37
|
+
| 'OUT_OF_STOCK'
|
|
38
|
+
| 'ALREADY_ACQUIRED'
|
|
39
|
+
| 'NOT_ELIGIBLE'
|
|
40
|
+
| 'UNKNOWN';
|