@harrylabsj/kiwi 0.7.19 → 0.7.21
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 +14 -1
- package/dist/a2a/node.js +9 -0
- package/dist/a2a/node.js.map +1 -1
- package/dist/a2a/server/index.d.ts +2 -1
- package/dist/a2a/server/index.js +1 -1
- package/dist/a2a/server/index.js.map +1 -1
- package/dist/a2a/server/pipeline.d.ts +25 -0
- package/dist/a2a/server/pipeline.js +50 -0
- package/dist/a2a/server/pipeline.js.map +1 -1
- package/dist/a2a/server/server.js +1 -0
- package/dist/a2a/server/server.js.map +1 -1
- package/dist/a2a/server/types.d.ts +6 -0
- package/dist/buyer-core/build-service.js +6 -1
- package/dist/buyer-core/build-service.js.map +1 -1
- package/dist/buyer-core/merchant-index.d.ts +2 -0
- package/dist/buyer-core/merchant-index.js +1 -0
- package/dist/buyer-core/merchant-index.js.map +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +46 -0
- package/dist/cli.js.map +1 -1
- package/dist/discovery/catalog-source/kiwi-source.js +5 -0
- package/dist/discovery/catalog-source/kiwi-source.js.map +1 -1
- package/dist/discovery/catalog-source/source.d.ts +2 -0
- package/dist/discovery/catalog-source/source.js.map +1 -1
- package/dist/merchant/stats-store.d.ts +74 -0
- package/dist/merchant/stats-store.js +147 -0
- package/dist/merchant/stats-store.js.map +1 -0
- package/dist/product-cli.d.ts +1 -1
- package/dist/product-cli.js +6 -1
- package/dist/product-cli.js.map +1 -1
- package/dist/product-merchant.d.ts +43 -0
- package/dist/product-merchant.js +75 -0
- package/dist/product-merchant.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 商家侧运营统计(merchant stats)——本地买家触达事实。
|
|
18
|
+
*
|
|
19
|
+
* 数据来源唯一:merchant 自己的 A2A 入站管线(InboundPipeline)在
|
|
20
|
+
* `message_received` 落账成功后写入一条 buyer_contact_events。数据只落
|
|
21
|
+
* 商家本地 DB(<dataDir>/a2a/stats.sqlite),永不上报任何远端。
|
|
22
|
+
*
|
|
23
|
+
* 语义:
|
|
24
|
+
* - 主键 message_id(INSERT OR IGNORE):与协议幂等(§20)对齐,
|
|
25
|
+
* 同一消息重放不重复计数;
|
|
26
|
+
* - distinct_buyers 仅在 KIWI_A2A_AUTH=signature 下有真实去重语义——
|
|
27
|
+
* loopback/none/bearer 模式下 buyer 身份坍缩(loopback 地址、
|
|
28
|
+
* "anonymous"、静态 token 身份),CLI 输出附带 identity_note 说明;
|
|
29
|
+
* - 天数一律 UTC(occurred_at ISO 串切前 10 位),与全仓时间处理一致。
|
|
30
|
+
*/
|
|
31
|
+
import { chmodSync, existsSync, mkdirSync } from "node:fs";
|
|
32
|
+
import path from "node:path";
|
|
33
|
+
import { DatabaseSync } from "node:sqlite";
|
|
34
|
+
import { requireIsoTimestamp, requireNonEmptyString } from "../negotiation/domain/common.js";
|
|
35
|
+
const STATS_SCHEMA = `
|
|
36
|
+
CREATE TABLE IF NOT EXISTS buyer_contact_events (
|
|
37
|
+
message_id TEXT PRIMARY KEY,
|
|
38
|
+
buyer_identity TEXT NOT NULL,
|
|
39
|
+
negotiation_id TEXT NOT NULL,
|
|
40
|
+
exchange_id TEXT,
|
|
41
|
+
action TEXT NOT NULL,
|
|
42
|
+
skus_json TEXT NOT NULL DEFAULT '[]',
|
|
43
|
+
occurred_at TEXT NOT NULL
|
|
44
|
+
);
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_buyer_contact_buyer ON buyer_contact_events(buyer_identity);
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_buyer_contact_time ON buyer_contact_events(occurred_at);
|
|
47
|
+
`;
|
|
48
|
+
/** 商家买家触达统计存储。写入面只有 recordBuyerContact;其余为聚合查询。 */
|
|
49
|
+
export class MerchantStatsStore {
|
|
50
|
+
db;
|
|
51
|
+
constructor(db) {
|
|
52
|
+
this.db = db;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 记录一次买家触达(INSERT OR IGNORE:同 message_id 幂等去重——协议层已
|
|
56
|
+
* 保证恰好一次调用,这里是崩溃/重试窗口的兜底)。
|
|
57
|
+
*/
|
|
58
|
+
recordBuyerContact(event) {
|
|
59
|
+
const messageId = requireNonEmptyString(event.message_id, "message_id");
|
|
60
|
+
const buyerIdentity = requireNonEmptyString(event.buyer_identity, "buyer_identity");
|
|
61
|
+
const negotiationId = requireNonEmptyString(event.negotiation_id, "negotiation_id");
|
|
62
|
+
const action = requireNonEmptyString(event.action, "action");
|
|
63
|
+
const occurredAt = requireIsoTimestamp(event.occurred_at, "occurred_at");
|
|
64
|
+
// SKU 去重(单条事件内同 SKU 重复出现只计一次触达)。
|
|
65
|
+
const skus = [...new Set(event.skus.filter((s) => typeof s === "string" && s !== ""))];
|
|
66
|
+
this.db
|
|
67
|
+
.prepare(`INSERT OR IGNORE INTO buyer_contact_events
|
|
68
|
+
(message_id, buyer_identity, negotiation_id, exchange_id, action, skus_json, occurred_at)
|
|
69
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
|
70
|
+
.run(messageId, buyerIdentity, negotiationId, event.exchange_id === "" ? null : event.exchange_id, action, JSON.stringify(skus), occurredAt);
|
|
71
|
+
}
|
|
72
|
+
/** 窗口总量(sinceDay 含当天,UTC `YYYY-MM-DD`)。 */
|
|
73
|
+
totalsSince(sinceDay) {
|
|
74
|
+
const row = this.db
|
|
75
|
+
.prepare(`SELECT COUNT(DISTINCT buyer_identity) AS distinct_buyers,
|
|
76
|
+
COUNT(*) AS contact_events,
|
|
77
|
+
COUNT(DISTINCT negotiation_id) AS negotiations
|
|
78
|
+
FROM buyer_contact_events
|
|
79
|
+
WHERE substr(occurred_at, 1, 10) >= ?`)
|
|
80
|
+
.get(sinceDay);
|
|
81
|
+
return {
|
|
82
|
+
distinct_buyers: row.distinct_buyers,
|
|
83
|
+
contact_events: row.contact_events,
|
|
84
|
+
negotiations: row.negotiations,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** 按日聚合(只返回有数据的天;零填充由调用方做)。 */
|
|
88
|
+
dailySince(sinceDay) {
|
|
89
|
+
const rows = this.db
|
|
90
|
+
.prepare(`SELECT substr(occurred_at, 1, 10) AS day,
|
|
91
|
+
COUNT(DISTINCT buyer_identity) AS distinct_buyers,
|
|
92
|
+
COUNT(*) AS contact_events,
|
|
93
|
+
COUNT(DISTINCT negotiation_id) AS negotiations
|
|
94
|
+
FROM buyer_contact_events
|
|
95
|
+
WHERE substr(occurred_at, 1, 10) >= ?
|
|
96
|
+
GROUP BY day
|
|
97
|
+
ORDER BY day`)
|
|
98
|
+
.all(sinceDay);
|
|
99
|
+
return rows.map((r) => ({
|
|
100
|
+
day: r.day,
|
|
101
|
+
distinct_buyers: r.distinct_buyers,
|
|
102
|
+
contact_events: r.contact_events,
|
|
103
|
+
negotiations: r.negotiations,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
/** SKU 热度榜(按触达事件数降序,sku 升序兜底,截断 limit)。 */
|
|
107
|
+
topSkus(sinceDay, limit) {
|
|
108
|
+
const rows = this.db
|
|
109
|
+
.prepare(`SELECT je.value AS sku,
|
|
110
|
+
COUNT(*) AS contact_events,
|
|
111
|
+
COUNT(DISTINCT buyer_identity) AS distinct_buyers,
|
|
112
|
+
COUNT(DISTINCT negotiation_id) AS negotiations
|
|
113
|
+
FROM buyer_contact_events,
|
|
114
|
+
json_each(buyer_contact_events.skus_json) AS je
|
|
115
|
+
WHERE substr(occurred_at, 1, 10) >= ?
|
|
116
|
+
GROUP BY je.value
|
|
117
|
+
ORDER BY contact_events DESC, sku ASC
|
|
118
|
+
LIMIT ?`)
|
|
119
|
+
.all(sinceDay, limit);
|
|
120
|
+
return rows.map((r) => ({
|
|
121
|
+
sku: r.sku,
|
|
122
|
+
contact_events: r.contact_events,
|
|
123
|
+
distinct_buyers: r.distinct_buyers,
|
|
124
|
+
negotiations: r.negotiations,
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
close() {
|
|
128
|
+
this.db.close();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** 打开(必要时创建)本地统计存储;目录 0700 / 文件 0600。 */
|
|
132
|
+
export function openMerchantStatsStore(options) {
|
|
133
|
+
if (options.dbPath === ":memory:") {
|
|
134
|
+
const db = new DatabaseSync(":memory:");
|
|
135
|
+
db.exec(STATS_SCHEMA);
|
|
136
|
+
return new MerchantStatsStore(db);
|
|
137
|
+
}
|
|
138
|
+
const dir = path.dirname(options.dbPath);
|
|
139
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
140
|
+
chmodSync(dir, 0o700);
|
|
141
|
+
const db = new DatabaseSync(options.dbPath);
|
|
142
|
+
if (existsSync(options.dbPath))
|
|
143
|
+
chmodSync(options.dbPath, 0o600);
|
|
144
|
+
db.exec(STATS_SCHEMA);
|
|
145
|
+
return new MerchantStatsStore(db);
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=stats-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats-store.js","sourceRoot":"","sources":["../../src/merchant/stats-store.ts"],"names":[],"mappings":"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"}
|
package/dist/product-cli.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export declare const DEFAULT_PROFILE_PATH: string;
|
|
|
42
42
|
*/
|
|
43
43
|
export declare function writeDefaultProfile(yaml: string, profilePath?: string): void;
|
|
44
44
|
/** 与 package.json / USAGE 同步的产品版本。 */
|
|
45
|
-
export declare const PRODUCT_VERSION = "0.7.
|
|
45
|
+
export declare const PRODUCT_VERSION = "0.7.21";
|
|
46
46
|
/**
|
|
47
47
|
* 缺省 kiwi-catalog 地址(单一来源,cli.ts 各处解析一致)。
|
|
48
48
|
*
|
package/dist/product-cli.js
CHANGED
|
@@ -51,7 +51,7 @@ export function writeDefaultProfile(yaml, profilePath) {
|
|
|
51
51
|
writeFileSync(target, yaml, { mode: 0o600 });
|
|
52
52
|
}
|
|
53
53
|
/** 与 package.json / USAGE 同步的产品版本。 */
|
|
54
|
-
export const PRODUCT_VERSION = "0.7.
|
|
54
|
+
export const PRODUCT_VERSION = "0.7.21";
|
|
55
55
|
/**
|
|
56
56
|
* 缺省 kiwi-catalog 地址(单一来源,cli.ts 各处解析一致)。
|
|
57
57
|
*
|
|
@@ -101,6 +101,11 @@ Usage:
|
|
|
101
101
|
反代 → 起 A2A 节点,退出时清理 Caddy
|
|
102
102
|
(需已安装 Caddy)
|
|
103
103
|
kiwi merchant listings [D2] 已发布 Listing 查看 —— 尚未实现
|
|
104
|
+
kiwi merchant stats [--days N] [--data-dir <dir>]
|
|
105
|
+
商家侧运营统计:去重买家数 / 触达事件 /
|
|
106
|
+
磋商数 / SKU 热度(本地 stats.sqlite,
|
|
107
|
+
数据只在商家本机,不上报;天数 UTC,
|
|
108
|
+
缺省 14 天,1-90)
|
|
104
109
|
kiwi merchant status [D1] Merchant 运行时状态 —— 尚未实现
|
|
105
110
|
kiwi merchant doctor [D3] Merchant 侧组件健康 —— 尚未实现
|
|
106
111
|
|
package/dist/product-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-cli.js","sourceRoot":"","sources":["../src/product-cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE3F;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,WAAoB;IACpE,MAAM,MAAM,GAAG,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,oBAAoB,CAAC;IACvF,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,sCAAsC;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,qCAAqC,CAAC;AAEzE,MAAM,UAAU,GAAG;;;;;;;;;;;CAWlB,CAAC;AAEF,MAAM,aAAa,GAAG
|
|
1
|
+
{"version":3,"file":"product-cli.js","sourceRoot":"","sources":["../src/product-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 harrylabsj
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { type ContactTotals, type DailyBucket, type SkuStat } from "./merchant/stats-store.js";
|
|
18
|
+
export interface MerchantStatsOptions {
|
|
19
|
+
/** merchant agent_id(报告标识,不参与查询)。 */
|
|
20
|
+
agentId: string;
|
|
21
|
+
/** 节点数据目录(resolveServeDataDir 解析后的 dataDir;统计库在 <dataDir>/a2a/)。 */
|
|
22
|
+
dataDir: string;
|
|
23
|
+
/** 回看天数(缺省 14,clamp 1..90;天数一律 UTC)。 */
|
|
24
|
+
days?: number;
|
|
25
|
+
/** 可注入时钟(RFC 3339);缺省 new Date().toISOString()。 */
|
|
26
|
+
now?: () => string;
|
|
27
|
+
}
|
|
28
|
+
export interface MerchantStatsReport {
|
|
29
|
+
ok: true;
|
|
30
|
+
agent_id: string;
|
|
31
|
+
days: number;
|
|
32
|
+
identity_note: string;
|
|
33
|
+
totals: ContactTotals;
|
|
34
|
+
today: {
|
|
35
|
+
distinct_buyers: number;
|
|
36
|
+
contact_events: number;
|
|
37
|
+
};
|
|
38
|
+
/** 零填充的 N 天窗口(升序,含今天)。 */
|
|
39
|
+
daily: DailyBucket[];
|
|
40
|
+
top_skus: SkuStat[];
|
|
41
|
+
}
|
|
42
|
+
/** 读本地买家触达统计(merchant start 运行并收到买家消息后才有数据;缺省报错)。 */
|
|
43
|
+
export declare function merchantStats(options: MerchantStatsOptions): MerchantStatsReport;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2026 harrylabsj
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* `kiwi merchant` 命令面(product-strategy rev1.1 §2.3/§19)。
|
|
19
|
+
*
|
|
20
|
+
* - stats:商家侧运营统计(本地 <dataDir>/a2a/stats.sqlite,由 merchant A2A
|
|
21
|
+
* 节点在收到买家 KNP 消息时自动收集;数据只在商家本机,永不上报)。
|
|
22
|
+
* 回答两个问题:多少个不同的买家联系过我、讨论了哪些商品(SKU)。
|
|
23
|
+
*/
|
|
24
|
+
import { existsSync } from "node:fs";
|
|
25
|
+
import path from "node:path";
|
|
26
|
+
import { openMerchantStatsStore, } from "./merchant/stats-store.js";
|
|
27
|
+
/** 身份语义说明:distinct_buyers 只在 signature 模式下是真实去重买家。 */
|
|
28
|
+
const IDENTITY_NOTE = "买家身份依赖传输层认证:signature 模式下为真实去重买家;loopback/none/bearer 模式会聚合买家";
|
|
29
|
+
const DEFAULT_DAYS = 14;
|
|
30
|
+
const MAX_DAYS = 90;
|
|
31
|
+
const TOP_SKU_LIMIT = 20;
|
|
32
|
+
/** UTC 日串加减天数(`YYYY-MM-DD`)。 */
|
|
33
|
+
function shiftDay(day, delta) {
|
|
34
|
+
return new Date(Date.parse(`${day}T00:00:00Z`) + delta * 86_400_000).toISOString().slice(0, 10);
|
|
35
|
+
}
|
|
36
|
+
/** 读本地买家触达统计(merchant start 运行并收到买家消息后才有数据;缺省报错)。 */
|
|
37
|
+
export function merchantStats(options) {
|
|
38
|
+
const now = (options.now ?? (() => new Date().toISOString()))();
|
|
39
|
+
const today = now.slice(0, 10);
|
|
40
|
+
const requested = options.days ?? DEFAULT_DAYS;
|
|
41
|
+
const days = Math.max(1, Math.min(MAX_DAYS, Math.trunc(requested)));
|
|
42
|
+
const sinceDay = shiftDay(today, -(days - 1));
|
|
43
|
+
const dbPath = path.join(options.dataDir, "a2a", "stats.sqlite");
|
|
44
|
+
if (!existsSync(dbPath)) {
|
|
45
|
+
throw new Error(`尚无买家沟通数据(${dbPath} 不存在)——商家服务启动并收到买家消息后会自动收集(kiwi merchant start)`);
|
|
46
|
+
}
|
|
47
|
+
const store = openMerchantStatsStore({ dbPath });
|
|
48
|
+
try {
|
|
49
|
+
const totals = store.totalsSince(sinceDay);
|
|
50
|
+
const todayTotals = store.totalsSince(today);
|
|
51
|
+
const byDay = new Map(store.dailySince(sinceDay).map((d) => [d.day, d]));
|
|
52
|
+
const daily = [];
|
|
53
|
+
for (let i = 0; i < days; i++) {
|
|
54
|
+
const day = shiftDay(sinceDay, i);
|
|
55
|
+
daily.push(byDay.get(day) ?? { day, distinct_buyers: 0, contact_events: 0, negotiations: 0 });
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
ok: true,
|
|
59
|
+
agent_id: options.agentId,
|
|
60
|
+
days,
|
|
61
|
+
identity_note: IDENTITY_NOTE,
|
|
62
|
+
totals,
|
|
63
|
+
today: {
|
|
64
|
+
distinct_buyers: todayTotals.distinct_buyers,
|
|
65
|
+
contact_events: todayTotals.contact_events,
|
|
66
|
+
},
|
|
67
|
+
daily,
|
|
68
|
+
top_skus: store.topSkus(sinceDay, TOP_SKU_LIMIT),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
store.close();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=product-merchant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-merchant.js","sourceRoot":"","sources":["../src/product-merchant.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED