@uniforge/portal 0.1.0-alpha.2

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 (49) hide show
  1. package/dist/auth/index.d.cts +104 -0
  2. package/dist/auth/index.d.ts +104 -0
  3. package/dist/auth/index.js +194 -0
  4. package/dist/auth/index.js.map +1 -0
  5. package/dist/auth/index.mjs +160 -0
  6. package/dist/auth/index.mjs.map +1 -0
  7. package/dist/dashboard/index.d.cts +76 -0
  8. package/dist/dashboard/index.d.ts +76 -0
  9. package/dist/dashboard/index.js +158 -0
  10. package/dist/dashboard/index.js.map +1 -0
  11. package/dist/dashboard/index.mjs +129 -0
  12. package/dist/dashboard/index.mjs.map +1 -0
  13. package/dist/feature-flags/index.d.cts +75 -0
  14. package/dist/feature-flags/index.d.ts +75 -0
  15. package/dist/feature-flags/index.js +111 -0
  16. package/dist/feature-flags/index.js.map +1 -0
  17. package/dist/feature-flags/index.mjs +83 -0
  18. package/dist/feature-flags/index.mjs.map +1 -0
  19. package/dist/index.d.cts +15 -0
  20. package/dist/index.d.ts +15 -0
  21. package/dist/index.js +31 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/index.mjs +6 -0
  24. package/dist/index.mjs.map +1 -0
  25. package/dist/merchants/index.d.cts +100 -0
  26. package/dist/merchants/index.d.ts +100 -0
  27. package/dist/merchants/index.js +120 -0
  28. package/dist/merchants/index.js.map +1 -0
  29. package/dist/merchants/index.mjs +90 -0
  30. package/dist/merchants/index.mjs.map +1 -0
  31. package/dist/metrics/index.d.cts +83 -0
  32. package/dist/metrics/index.d.ts +83 -0
  33. package/dist/metrics/index.js +112 -0
  34. package/dist/metrics/index.js.map +1 -0
  35. package/dist/metrics/index.mjs +83 -0
  36. package/dist/metrics/index.mjs.map +1 -0
  37. package/dist/tickets/index.d.cts +96 -0
  38. package/dist/tickets/index.d.ts +96 -0
  39. package/dist/tickets/index.js +102 -0
  40. package/dist/tickets/index.js.map +1 -0
  41. package/dist/tickets/index.mjs +73 -0
  42. package/dist/tickets/index.mjs.map +1 -0
  43. package/dist/webhook-logs/index.d.cts +88 -0
  44. package/dist/webhook-logs/index.d.ts +88 -0
  45. package/dist/webhook-logs/index.js +111 -0
  46. package/dist/webhook-logs/index.js.map +1 -0
  47. package/dist/webhook-logs/index.mjs +82 -0
  48. package/dist/webhook-logs/index.mjs.map +1 -0
  49. package/package.json +70 -0
@@ -0,0 +1,76 @@
1
+ interface DashboardMetrics {
2
+ totalInstalls: number;
3
+ activeMerchants: number;
4
+ monthlyRevenue: string;
5
+ churnRate: number;
6
+ }
7
+ interface DashboardActivity {
8
+ id: string;
9
+ title: string;
10
+ description?: string;
11
+ timestamp: Date;
12
+ type: 'install' | 'uninstall' | 'upgrade' | 'downgrade' | 'payment' | 'error';
13
+ shopDomain?: string;
14
+ }
15
+ type DashboardTimeRange = 'day' | 'week' | 'month' | 'quarter' | 'year';
16
+ interface MetricsSnapshot {
17
+ metrics: DashboardMetrics;
18
+ timestamp: Date;
19
+ timeRange: DashboardTimeRange;
20
+ }
21
+ interface DashboardConfig {
22
+ metricsDataSource: MetricsDataSource;
23
+ activityDataSource: ActivityDataSource;
24
+ defaultTimeRange?: DashboardTimeRange;
25
+ defaultActivityLimit?: number;
26
+ }
27
+ interface MetricsDataSource {
28
+ countShops(filter?: string): Promise<number>;
29
+ countActiveShops(): Promise<number>;
30
+ sumRevenue(since: Date): Promise<number>;
31
+ countChurned(since: Date): Promise<number>;
32
+ getInstallTimeline(range: DashboardTimeRange): Promise<{
33
+ date: string;
34
+ count: number;
35
+ }[]>;
36
+ }
37
+ interface ActivityDataSource {
38
+ getRecentActivities(limit: number): Promise<DashboardActivity[]>;
39
+ getActivitiesByShop(shopDomain: string, limit: number): Promise<DashboardActivity[]>;
40
+ getActivitiesByType(type: string, limit: number): Promise<DashboardActivity[]>;
41
+ }
42
+
43
+ declare class MetricsService {
44
+ private readonly dataSource;
45
+ constructor(dataSource: MetricsDataSource);
46
+ getMetrics(range?: DashboardTimeRange): Promise<DashboardMetrics>;
47
+ getMetricsSnapshot(range?: DashboardTimeRange): Promise<MetricsSnapshot>;
48
+ calculateChurnRate(totalShops: number, churnedShops: number): number;
49
+ formatRevenue(amount: number, currency?: string): string;
50
+ private getStartDate;
51
+ }
52
+
53
+ declare class ActivityService {
54
+ private readonly dataSource;
55
+ constructor(dataSource: ActivityDataSource);
56
+ getRecentActivity(limit?: number): Promise<DashboardActivity[]>;
57
+ getActivityByShop(shopDomain: string, limit?: number): Promise<DashboardActivity[]>;
58
+ getActivityFeed(options?: {
59
+ limit?: number;
60
+ types?: string[];
61
+ shopDomain?: string;
62
+ }): Promise<DashboardActivity[]>;
63
+ }
64
+
65
+ interface DashboardData {
66
+ metrics: DashboardMetrics;
67
+ recentActivity: DashboardActivity[];
68
+ }
69
+ declare class DashboardService {
70
+ private readonly metricsService;
71
+ private readonly activityService;
72
+ constructor(metricsDataSource: MetricsDataSource, activityDataSource: ActivityDataSource);
73
+ getDashboardData(range?: DashboardTimeRange): Promise<DashboardData>;
74
+ }
75
+
76
+ export { type ActivityDataSource, ActivityService, type DashboardActivity, type DashboardConfig, type DashboardData, type DashboardMetrics, DashboardService, type DashboardTimeRange, type MetricsDataSource, MetricsService, type MetricsSnapshot };
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/dashboard/index.ts
21
+ var dashboard_exports = {};
22
+ __export(dashboard_exports, {
23
+ ActivityService: () => ActivityService,
24
+ DashboardService: () => DashboardService,
25
+ MetricsService: () => MetricsService
26
+ });
27
+ module.exports = __toCommonJS(dashboard_exports);
28
+
29
+ // src/dashboard/metrics-service.ts
30
+ var MetricsService = class {
31
+ dataSource;
32
+ constructor(dataSource) {
33
+ this.dataSource = dataSource;
34
+ }
35
+ async getMetrics(range) {
36
+ const timeRange = range ?? "month";
37
+ const since = this.getStartDate(timeRange);
38
+ const [totalInstalls, activeMerchants, revenueAmount, churnedShops] = await Promise.all([
39
+ this.dataSource.countShops(),
40
+ this.dataSource.countActiveShops(),
41
+ this.dataSource.sumRevenue(since),
42
+ this.dataSource.countChurned(since)
43
+ ]);
44
+ const churnRate = this.calculateChurnRate(totalInstalls, churnedShops);
45
+ return {
46
+ totalInstalls,
47
+ activeMerchants,
48
+ monthlyRevenue: this.formatRevenue(revenueAmount),
49
+ churnRate
50
+ };
51
+ }
52
+ async getMetricsSnapshot(range) {
53
+ const timeRange = range ?? "month";
54
+ const metrics = await this.getMetrics(timeRange);
55
+ return {
56
+ metrics,
57
+ timestamp: /* @__PURE__ */ new Date(),
58
+ timeRange
59
+ };
60
+ }
61
+ calculateChurnRate(totalShops, churnedShops) {
62
+ if (totalShops <= 0) {
63
+ return 0;
64
+ }
65
+ const rate = churnedShops / totalShops * 100;
66
+ return Math.round(rate * 100) / 100;
67
+ }
68
+ formatRevenue(amount, currency) {
69
+ const cur = currency ?? "USD";
70
+ return new Intl.NumberFormat("en-US", {
71
+ style: "currency",
72
+ currency: cur
73
+ }).format(amount);
74
+ }
75
+ getStartDate(range) {
76
+ const now = /* @__PURE__ */ new Date();
77
+ switch (range) {
78
+ case "day":
79
+ return new Date(now.getTime() - 24 * 60 * 60 * 1e3);
80
+ case "week":
81
+ return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
82
+ case "month":
83
+ return new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
84
+ case "quarter":
85
+ return new Date(now.getTime() - 90 * 24 * 60 * 60 * 1e3);
86
+ case "year":
87
+ return new Date(now.getTime() - 365 * 24 * 60 * 60 * 1e3);
88
+ }
89
+ }
90
+ };
91
+
92
+ // src/dashboard/activity-service.ts
93
+ var DEFAULT_ACTIVITY_LIMIT = 20;
94
+ var ActivityService = class {
95
+ dataSource;
96
+ constructor(dataSource) {
97
+ this.dataSource = dataSource;
98
+ }
99
+ async getRecentActivity(limit) {
100
+ return this.dataSource.getRecentActivities(limit ?? DEFAULT_ACTIVITY_LIMIT);
101
+ }
102
+ async getActivityByShop(shopDomain, limit) {
103
+ return this.dataSource.getActivitiesByShop(
104
+ shopDomain,
105
+ limit ?? DEFAULT_ACTIVITY_LIMIT
106
+ );
107
+ }
108
+ async getActivityFeed(options) {
109
+ const limit = options?.limit ?? DEFAULT_ACTIVITY_LIMIT;
110
+ if (options?.shopDomain !== void 0) {
111
+ const activities = await this.dataSource.getActivitiesByShop(
112
+ options.shopDomain,
113
+ limit
114
+ );
115
+ if (options.types !== void 0 && options.types.length > 0) {
116
+ return activities.filter((a) => options.types.includes(a.type));
117
+ }
118
+ return activities;
119
+ }
120
+ if (options?.types !== void 0 && options.types.length > 0) {
121
+ const results = [];
122
+ for (const type of options.types) {
123
+ const activities = await this.dataSource.getActivitiesByType(
124
+ type,
125
+ limit
126
+ );
127
+ results.push(...activities);
128
+ }
129
+ results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
130
+ return results.slice(0, limit);
131
+ }
132
+ return this.dataSource.getRecentActivities(limit);
133
+ }
134
+ };
135
+
136
+ // src/dashboard/dashboard-service.ts
137
+ var DashboardService = class {
138
+ metricsService;
139
+ activityService;
140
+ constructor(metricsDataSource, activityDataSource) {
141
+ this.metricsService = new MetricsService(metricsDataSource);
142
+ this.activityService = new ActivityService(activityDataSource);
143
+ }
144
+ async getDashboardData(range) {
145
+ const [metrics, recentActivity] = await Promise.all([
146
+ this.metricsService.getMetrics(range),
147
+ this.activityService.getRecentActivity()
148
+ ]);
149
+ return { metrics, recentActivity };
150
+ }
151
+ };
152
+ // Annotate the CommonJS export names for ESM import in node:
153
+ 0 && (module.exports = {
154
+ ActivityService,
155
+ DashboardService,
156
+ MetricsService
157
+ });
158
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/dashboard/index.ts","../../src/dashboard/metrics-service.ts","../../src/dashboard/activity-service.ts","../../src/dashboard/dashboard-service.ts"],"sourcesContent":["export type {\n DashboardMetrics,\n DashboardActivity,\n DashboardTimeRange,\n MetricsSnapshot,\n DashboardConfig,\n MetricsDataSource,\n ActivityDataSource,\n} from './types.js';\n\nexport { MetricsService } from './metrics-service.js';\nexport { ActivityService } from './activity-service.js';\nexport { DashboardService } from './dashboard-service.js';\nexport type { DashboardData } from './dashboard-service.js';\n","import type {\n DashboardMetrics,\n DashboardTimeRange,\n MetricsDataSource,\n MetricsSnapshot,\n} from './types.js';\n\nexport class MetricsService {\n private readonly dataSource: MetricsDataSource;\n\n constructor(dataSource: MetricsDataSource) {\n this.dataSource = dataSource;\n }\n\n async getMetrics(range?: DashboardTimeRange): Promise<DashboardMetrics> {\n const timeRange = range ?? 'month';\n const since = this.getStartDate(timeRange);\n\n const [totalInstalls, activeMerchants, revenueAmount, churnedShops] =\n await Promise.all([\n this.dataSource.countShops(),\n this.dataSource.countActiveShops(),\n this.dataSource.sumRevenue(since),\n this.dataSource.countChurned(since),\n ]);\n\n const churnRate = this.calculateChurnRate(totalInstalls, churnedShops);\n\n return {\n totalInstalls,\n activeMerchants,\n monthlyRevenue: this.formatRevenue(revenueAmount),\n churnRate,\n };\n }\n\n async getMetricsSnapshot(\n range?: DashboardTimeRange,\n ): Promise<MetricsSnapshot> {\n const timeRange = range ?? 'month';\n const metrics = await this.getMetrics(timeRange);\n\n return {\n metrics,\n timestamp: new Date(),\n timeRange,\n };\n }\n\n calculateChurnRate(totalShops: number, churnedShops: number): number {\n if (totalShops <= 0) {\n return 0;\n }\n const rate = (churnedShops / totalShops) * 100;\n return Math.round(rate * 100) / 100;\n }\n\n formatRevenue(amount: number, currency?: string): string {\n const cur = currency ?? 'USD';\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: cur,\n }).format(amount);\n }\n\n private getStartDate(range: DashboardTimeRange): Date {\n const now = new Date();\n switch (range) {\n case 'day':\n return new Date(now.getTime() - 24 * 60 * 60 * 1000);\n case 'week':\n return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\n case 'month':\n return new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n case 'quarter':\n return new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);\n case 'year':\n return new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000);\n }\n }\n}\n","import type { ActivityDataSource, DashboardActivity } from './types.js';\n\nconst DEFAULT_ACTIVITY_LIMIT = 20;\n\nexport class ActivityService {\n private readonly dataSource: ActivityDataSource;\n\n constructor(dataSource: ActivityDataSource) {\n this.dataSource = dataSource;\n }\n\n async getRecentActivity(limit?: number): Promise<DashboardActivity[]> {\n return this.dataSource.getRecentActivities(limit ?? DEFAULT_ACTIVITY_LIMIT);\n }\n\n async getActivityByShop(\n shopDomain: string,\n limit?: number,\n ): Promise<DashboardActivity[]> {\n return this.dataSource.getActivitiesByShop(\n shopDomain,\n limit ?? DEFAULT_ACTIVITY_LIMIT,\n );\n }\n\n async getActivityFeed(options?: {\n limit?: number;\n types?: string[];\n shopDomain?: string;\n }): Promise<DashboardActivity[]> {\n const limit = options?.limit ?? DEFAULT_ACTIVITY_LIMIT;\n\n if (options?.shopDomain !== undefined) {\n const activities = await this.dataSource.getActivitiesByShop(\n options.shopDomain,\n limit,\n );\n if (options.types !== undefined && options.types.length > 0) {\n return activities.filter((a) => options.types!.includes(a.type));\n }\n return activities;\n }\n\n if (options?.types !== undefined && options.types.length > 0) {\n const results: DashboardActivity[] = [];\n for (const type of options.types) {\n const activities = await this.dataSource.getActivitiesByType(\n type,\n limit,\n );\n results.push(...activities);\n }\n results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n return results.slice(0, limit);\n }\n\n return this.dataSource.getRecentActivities(limit);\n }\n}\n","import type {\n ActivityDataSource,\n DashboardActivity,\n DashboardMetrics,\n DashboardTimeRange,\n MetricsDataSource,\n} from './types.js';\nimport { MetricsService } from './metrics-service.js';\nimport { ActivityService } from './activity-service.js';\n\nexport interface DashboardData {\n metrics: DashboardMetrics;\n recentActivity: DashboardActivity[];\n}\n\nexport class DashboardService {\n private readonly metricsService: MetricsService;\n private readonly activityService: ActivityService;\n\n constructor(\n metricsDataSource: MetricsDataSource,\n activityDataSource: ActivityDataSource,\n ) {\n this.metricsService = new MetricsService(metricsDataSource);\n this.activityService = new ActivityService(activityDataSource);\n }\n\n async getDashboardData(range?: DashboardTimeRange): Promise<DashboardData> {\n const [metrics, recentActivity] = await Promise.all([\n this.metricsService.getMetrics(range),\n this.activityService.getRecentActivity(),\n ]);\n\n return { metrics, recentActivity };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,129 @@
1
+ // src/dashboard/metrics-service.ts
2
+ var MetricsService = class {
3
+ dataSource;
4
+ constructor(dataSource) {
5
+ this.dataSource = dataSource;
6
+ }
7
+ async getMetrics(range) {
8
+ const timeRange = range ?? "month";
9
+ const since = this.getStartDate(timeRange);
10
+ const [totalInstalls, activeMerchants, revenueAmount, churnedShops] = await Promise.all([
11
+ this.dataSource.countShops(),
12
+ this.dataSource.countActiveShops(),
13
+ this.dataSource.sumRevenue(since),
14
+ this.dataSource.countChurned(since)
15
+ ]);
16
+ const churnRate = this.calculateChurnRate(totalInstalls, churnedShops);
17
+ return {
18
+ totalInstalls,
19
+ activeMerchants,
20
+ monthlyRevenue: this.formatRevenue(revenueAmount),
21
+ churnRate
22
+ };
23
+ }
24
+ async getMetricsSnapshot(range) {
25
+ const timeRange = range ?? "month";
26
+ const metrics = await this.getMetrics(timeRange);
27
+ return {
28
+ metrics,
29
+ timestamp: /* @__PURE__ */ new Date(),
30
+ timeRange
31
+ };
32
+ }
33
+ calculateChurnRate(totalShops, churnedShops) {
34
+ if (totalShops <= 0) {
35
+ return 0;
36
+ }
37
+ const rate = churnedShops / totalShops * 100;
38
+ return Math.round(rate * 100) / 100;
39
+ }
40
+ formatRevenue(amount, currency) {
41
+ const cur = currency ?? "USD";
42
+ return new Intl.NumberFormat("en-US", {
43
+ style: "currency",
44
+ currency: cur
45
+ }).format(amount);
46
+ }
47
+ getStartDate(range) {
48
+ const now = /* @__PURE__ */ new Date();
49
+ switch (range) {
50
+ case "day":
51
+ return new Date(now.getTime() - 24 * 60 * 60 * 1e3);
52
+ case "week":
53
+ return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
54
+ case "month":
55
+ return new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
56
+ case "quarter":
57
+ return new Date(now.getTime() - 90 * 24 * 60 * 60 * 1e3);
58
+ case "year":
59
+ return new Date(now.getTime() - 365 * 24 * 60 * 60 * 1e3);
60
+ }
61
+ }
62
+ };
63
+
64
+ // src/dashboard/activity-service.ts
65
+ var DEFAULT_ACTIVITY_LIMIT = 20;
66
+ var ActivityService = class {
67
+ dataSource;
68
+ constructor(dataSource) {
69
+ this.dataSource = dataSource;
70
+ }
71
+ async getRecentActivity(limit) {
72
+ return this.dataSource.getRecentActivities(limit ?? DEFAULT_ACTIVITY_LIMIT);
73
+ }
74
+ async getActivityByShop(shopDomain, limit) {
75
+ return this.dataSource.getActivitiesByShop(
76
+ shopDomain,
77
+ limit ?? DEFAULT_ACTIVITY_LIMIT
78
+ );
79
+ }
80
+ async getActivityFeed(options) {
81
+ const limit = options?.limit ?? DEFAULT_ACTIVITY_LIMIT;
82
+ if (options?.shopDomain !== void 0) {
83
+ const activities = await this.dataSource.getActivitiesByShop(
84
+ options.shopDomain,
85
+ limit
86
+ );
87
+ if (options.types !== void 0 && options.types.length > 0) {
88
+ return activities.filter((a) => options.types.includes(a.type));
89
+ }
90
+ return activities;
91
+ }
92
+ if (options?.types !== void 0 && options.types.length > 0) {
93
+ const results = [];
94
+ for (const type of options.types) {
95
+ const activities = await this.dataSource.getActivitiesByType(
96
+ type,
97
+ limit
98
+ );
99
+ results.push(...activities);
100
+ }
101
+ results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
102
+ return results.slice(0, limit);
103
+ }
104
+ return this.dataSource.getRecentActivities(limit);
105
+ }
106
+ };
107
+
108
+ // src/dashboard/dashboard-service.ts
109
+ var DashboardService = class {
110
+ metricsService;
111
+ activityService;
112
+ constructor(metricsDataSource, activityDataSource) {
113
+ this.metricsService = new MetricsService(metricsDataSource);
114
+ this.activityService = new ActivityService(activityDataSource);
115
+ }
116
+ async getDashboardData(range) {
117
+ const [metrics, recentActivity] = await Promise.all([
118
+ this.metricsService.getMetrics(range),
119
+ this.activityService.getRecentActivity()
120
+ ]);
121
+ return { metrics, recentActivity };
122
+ }
123
+ };
124
+ export {
125
+ ActivityService,
126
+ DashboardService,
127
+ MetricsService
128
+ };
129
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/dashboard/metrics-service.ts","../../src/dashboard/activity-service.ts","../../src/dashboard/dashboard-service.ts"],"sourcesContent":["import type {\n DashboardMetrics,\n DashboardTimeRange,\n MetricsDataSource,\n MetricsSnapshot,\n} from './types.js';\n\nexport class MetricsService {\n private readonly dataSource: MetricsDataSource;\n\n constructor(dataSource: MetricsDataSource) {\n this.dataSource = dataSource;\n }\n\n async getMetrics(range?: DashboardTimeRange): Promise<DashboardMetrics> {\n const timeRange = range ?? 'month';\n const since = this.getStartDate(timeRange);\n\n const [totalInstalls, activeMerchants, revenueAmount, churnedShops] =\n await Promise.all([\n this.dataSource.countShops(),\n this.dataSource.countActiveShops(),\n this.dataSource.sumRevenue(since),\n this.dataSource.countChurned(since),\n ]);\n\n const churnRate = this.calculateChurnRate(totalInstalls, churnedShops);\n\n return {\n totalInstalls,\n activeMerchants,\n monthlyRevenue: this.formatRevenue(revenueAmount),\n churnRate,\n };\n }\n\n async getMetricsSnapshot(\n range?: DashboardTimeRange,\n ): Promise<MetricsSnapshot> {\n const timeRange = range ?? 'month';\n const metrics = await this.getMetrics(timeRange);\n\n return {\n metrics,\n timestamp: new Date(),\n timeRange,\n };\n }\n\n calculateChurnRate(totalShops: number, churnedShops: number): number {\n if (totalShops <= 0) {\n return 0;\n }\n const rate = (churnedShops / totalShops) * 100;\n return Math.round(rate * 100) / 100;\n }\n\n formatRevenue(amount: number, currency?: string): string {\n const cur = currency ?? 'USD';\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: cur,\n }).format(amount);\n }\n\n private getStartDate(range: DashboardTimeRange): Date {\n const now = new Date();\n switch (range) {\n case 'day':\n return new Date(now.getTime() - 24 * 60 * 60 * 1000);\n case 'week':\n return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\n case 'month':\n return new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n case 'quarter':\n return new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);\n case 'year':\n return new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000);\n }\n }\n}\n","import type { ActivityDataSource, DashboardActivity } from './types.js';\n\nconst DEFAULT_ACTIVITY_LIMIT = 20;\n\nexport class ActivityService {\n private readonly dataSource: ActivityDataSource;\n\n constructor(dataSource: ActivityDataSource) {\n this.dataSource = dataSource;\n }\n\n async getRecentActivity(limit?: number): Promise<DashboardActivity[]> {\n return this.dataSource.getRecentActivities(limit ?? DEFAULT_ACTIVITY_LIMIT);\n }\n\n async getActivityByShop(\n shopDomain: string,\n limit?: number,\n ): Promise<DashboardActivity[]> {\n return this.dataSource.getActivitiesByShop(\n shopDomain,\n limit ?? DEFAULT_ACTIVITY_LIMIT,\n );\n }\n\n async getActivityFeed(options?: {\n limit?: number;\n types?: string[];\n shopDomain?: string;\n }): Promise<DashboardActivity[]> {\n const limit = options?.limit ?? DEFAULT_ACTIVITY_LIMIT;\n\n if (options?.shopDomain !== undefined) {\n const activities = await this.dataSource.getActivitiesByShop(\n options.shopDomain,\n limit,\n );\n if (options.types !== undefined && options.types.length > 0) {\n return activities.filter((a) => options.types!.includes(a.type));\n }\n return activities;\n }\n\n if (options?.types !== undefined && options.types.length > 0) {\n const results: DashboardActivity[] = [];\n for (const type of options.types) {\n const activities = await this.dataSource.getActivitiesByType(\n type,\n limit,\n );\n results.push(...activities);\n }\n results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n return results.slice(0, limit);\n }\n\n return this.dataSource.getRecentActivities(limit);\n }\n}\n","import type {\n ActivityDataSource,\n DashboardActivity,\n DashboardMetrics,\n DashboardTimeRange,\n MetricsDataSource,\n} from './types.js';\nimport { MetricsService } from './metrics-service.js';\nimport { ActivityService } from './activity-service.js';\n\nexport interface DashboardData {\n metrics: DashboardMetrics;\n recentActivity: DashboardActivity[];\n}\n\nexport class DashboardService {\n private readonly metricsService: MetricsService;\n private readonly activityService: ActivityService;\n\n constructor(\n metricsDataSource: MetricsDataSource,\n activityDataSource: ActivityDataSource,\n ) {\n this.metricsService = new MetricsService(metricsDataSource);\n this.activityService = new ActivityService(activityDataSource);\n }\n\n async getDashboardData(range?: DashboardTimeRange): Promise<DashboardData> {\n const [metrics, recentActivity] = await Promise.all([\n this.metricsService.getMetrics(range),\n this.activityService.getRecentActivity(),\n ]);\n\n return { metrics, recentActivity };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,75 @@
1
+ interface FeatureFlag {
2
+ id: string;
3
+ key: string;
4
+ name: string;
5
+ description?: string;
6
+ enabled: boolean;
7
+ rolloutPercentage: number;
8
+ targetShops: string[];
9
+ excludedShops: string[];
10
+ createdAt: Date;
11
+ updatedAt: Date;
12
+ createdBy: string;
13
+ }
14
+ interface FeatureFlagCreateInput {
15
+ key: string;
16
+ name: string;
17
+ description?: string;
18
+ enabled?: boolean;
19
+ rolloutPercentage?: number;
20
+ targetShops?: string[];
21
+ excludedShops?: string[];
22
+ createdBy: string;
23
+ }
24
+ interface FeatureFlagUpdateInput {
25
+ name?: string;
26
+ description?: string;
27
+ enabled?: boolean;
28
+ rolloutPercentage?: number;
29
+ targetShops?: string[];
30
+ excludedShops?: string[];
31
+ }
32
+ type FeatureFlagEvaluationReason = 'targeted' | 'excluded' | 'rollout' | 'default' | 'disabled' | 'not_found';
33
+ interface FeatureFlagEvaluation {
34
+ flagKey: string;
35
+ enabled: boolean;
36
+ reason: FeatureFlagEvaluationReason;
37
+ }
38
+ interface FeatureFlagListResult {
39
+ flags: FeatureFlag[];
40
+ total: number;
41
+ }
42
+ interface FeatureFlagFilter {
43
+ enabled?: boolean;
44
+ search?: string;
45
+ }
46
+
47
+ interface FeatureFlagDataSource {
48
+ create(input: FeatureFlagCreateInput): Promise<FeatureFlag>;
49
+ getById(flagId: string): Promise<FeatureFlag | null>;
50
+ getByKey(key: string): Promise<FeatureFlag | null>;
51
+ list(filter?: FeatureFlagFilter): Promise<FeatureFlagListResult>;
52
+ update(flagId: string, input: FeatureFlagUpdateInput): Promise<FeatureFlag | null>;
53
+ delete(flagId: string): Promise<boolean>;
54
+ }
55
+
56
+ declare class FeatureFlagService {
57
+ private readonly dataSource;
58
+ constructor(dataSource: FeatureFlagDataSource);
59
+ createFlag(input: FeatureFlagCreateInput): Promise<FeatureFlag>;
60
+ getFlag(flagId: string): Promise<FeatureFlag | null>;
61
+ getFlagByKey(key: string): Promise<FeatureFlag | null>;
62
+ listFlags(filter?: FeatureFlagFilter): Promise<FeatureFlagListResult>;
63
+ updateFlag(flagId: string, input: FeatureFlagUpdateInput): Promise<FeatureFlag | null>;
64
+ deleteFlag(flagId: string): Promise<boolean>;
65
+ toggleFlag(flagId: string, enabled: boolean): Promise<FeatureFlag | null>;
66
+ }
67
+
68
+ declare class FeatureFlagEvaluator {
69
+ private readonly dataSource;
70
+ constructor(dataSource: FeatureFlagDataSource);
71
+ evaluate(flagKey: string, shopDomain: string): Promise<FeatureFlagEvaluation>;
72
+ evaluateAll(shopDomain: string): Promise<Record<string, FeatureFlagEvaluation>>;
73
+ }
74
+
75
+ export { type FeatureFlag, type FeatureFlagCreateInput, type FeatureFlagDataSource, type FeatureFlagEvaluation, type FeatureFlagEvaluationReason, FeatureFlagEvaluator, type FeatureFlagFilter, type FeatureFlagListResult, FeatureFlagService, type FeatureFlagUpdateInput };
@@ -0,0 +1,75 @@
1
+ interface FeatureFlag {
2
+ id: string;
3
+ key: string;
4
+ name: string;
5
+ description?: string;
6
+ enabled: boolean;
7
+ rolloutPercentage: number;
8
+ targetShops: string[];
9
+ excludedShops: string[];
10
+ createdAt: Date;
11
+ updatedAt: Date;
12
+ createdBy: string;
13
+ }
14
+ interface FeatureFlagCreateInput {
15
+ key: string;
16
+ name: string;
17
+ description?: string;
18
+ enabled?: boolean;
19
+ rolloutPercentage?: number;
20
+ targetShops?: string[];
21
+ excludedShops?: string[];
22
+ createdBy: string;
23
+ }
24
+ interface FeatureFlagUpdateInput {
25
+ name?: string;
26
+ description?: string;
27
+ enabled?: boolean;
28
+ rolloutPercentage?: number;
29
+ targetShops?: string[];
30
+ excludedShops?: string[];
31
+ }
32
+ type FeatureFlagEvaluationReason = 'targeted' | 'excluded' | 'rollout' | 'default' | 'disabled' | 'not_found';
33
+ interface FeatureFlagEvaluation {
34
+ flagKey: string;
35
+ enabled: boolean;
36
+ reason: FeatureFlagEvaluationReason;
37
+ }
38
+ interface FeatureFlagListResult {
39
+ flags: FeatureFlag[];
40
+ total: number;
41
+ }
42
+ interface FeatureFlagFilter {
43
+ enabled?: boolean;
44
+ search?: string;
45
+ }
46
+
47
+ interface FeatureFlagDataSource {
48
+ create(input: FeatureFlagCreateInput): Promise<FeatureFlag>;
49
+ getById(flagId: string): Promise<FeatureFlag | null>;
50
+ getByKey(key: string): Promise<FeatureFlag | null>;
51
+ list(filter?: FeatureFlagFilter): Promise<FeatureFlagListResult>;
52
+ update(flagId: string, input: FeatureFlagUpdateInput): Promise<FeatureFlag | null>;
53
+ delete(flagId: string): Promise<boolean>;
54
+ }
55
+
56
+ declare class FeatureFlagService {
57
+ private readonly dataSource;
58
+ constructor(dataSource: FeatureFlagDataSource);
59
+ createFlag(input: FeatureFlagCreateInput): Promise<FeatureFlag>;
60
+ getFlag(flagId: string): Promise<FeatureFlag | null>;
61
+ getFlagByKey(key: string): Promise<FeatureFlag | null>;
62
+ listFlags(filter?: FeatureFlagFilter): Promise<FeatureFlagListResult>;
63
+ updateFlag(flagId: string, input: FeatureFlagUpdateInput): Promise<FeatureFlag | null>;
64
+ deleteFlag(flagId: string): Promise<boolean>;
65
+ toggleFlag(flagId: string, enabled: boolean): Promise<FeatureFlag | null>;
66
+ }
67
+
68
+ declare class FeatureFlagEvaluator {
69
+ private readonly dataSource;
70
+ constructor(dataSource: FeatureFlagDataSource);
71
+ evaluate(flagKey: string, shopDomain: string): Promise<FeatureFlagEvaluation>;
72
+ evaluateAll(shopDomain: string): Promise<Record<string, FeatureFlagEvaluation>>;
73
+ }
74
+
75
+ export { type FeatureFlag, type FeatureFlagCreateInput, type FeatureFlagDataSource, type FeatureFlagEvaluation, type FeatureFlagEvaluationReason, FeatureFlagEvaluator, type FeatureFlagFilter, type FeatureFlagListResult, FeatureFlagService, type FeatureFlagUpdateInput };
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/feature-flags/index.ts
21
+ var feature_flags_exports = {};
22
+ __export(feature_flags_exports, {
23
+ FeatureFlagEvaluator: () => FeatureFlagEvaluator,
24
+ FeatureFlagService: () => FeatureFlagService
25
+ });
26
+ module.exports = __toCommonJS(feature_flags_exports);
27
+
28
+ // src/feature-flags/feature-flag-service.ts
29
+ var FLAG_KEY_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
30
+ var FeatureFlagService = class {
31
+ dataSource;
32
+ constructor(dataSource) {
33
+ this.dataSource = dataSource;
34
+ }
35
+ async createFlag(input) {
36
+ if (!FLAG_KEY_PATTERN.test(input.key)) {
37
+ throw new Error(
38
+ `Invalid flag key "${input.key}". Keys must be alphanumeric and may contain hyphens or underscores.`
39
+ );
40
+ }
41
+ return this.dataSource.create(input);
42
+ }
43
+ async getFlag(flagId) {
44
+ return this.dataSource.getById(flagId);
45
+ }
46
+ async getFlagByKey(key) {
47
+ return this.dataSource.getByKey(key);
48
+ }
49
+ async listFlags(filter) {
50
+ return this.dataSource.list(filter);
51
+ }
52
+ async updateFlag(flagId, input) {
53
+ return this.dataSource.update(flagId, input);
54
+ }
55
+ async deleteFlag(flagId) {
56
+ return this.dataSource.delete(flagId);
57
+ }
58
+ async toggleFlag(flagId, enabled) {
59
+ return this.dataSource.update(flagId, { enabled });
60
+ }
61
+ };
62
+
63
+ // src/feature-flags/feature-flag-evaluator.ts
64
+ function hashToPercentage(input) {
65
+ let hash = 5381;
66
+ for (let i = 0; i < input.length; i++) {
67
+ hash = hash * 33 ^ input.charCodeAt(i);
68
+ }
69
+ return Math.abs(hash) % 100;
70
+ }
71
+ var FeatureFlagEvaluator = class {
72
+ dataSource;
73
+ constructor(dataSource) {
74
+ this.dataSource = dataSource;
75
+ }
76
+ async evaluate(flagKey, shopDomain) {
77
+ const flag = await this.dataSource.getByKey(flagKey);
78
+ if (!flag) {
79
+ return { flagKey, enabled: false, reason: "not_found" };
80
+ }
81
+ if (!flag.enabled) {
82
+ return { flagKey, enabled: false, reason: "disabled" };
83
+ }
84
+ if (flag.excludedShops.includes(shopDomain)) {
85
+ return { flagKey, enabled: false, reason: "excluded" };
86
+ }
87
+ if (flag.targetShops.includes(shopDomain)) {
88
+ return { flagKey, enabled: true, reason: "targeted" };
89
+ }
90
+ if (flag.rolloutPercentage > 0) {
91
+ const bucket = hashToPercentage(flagKey + shopDomain);
92
+ const enabled = bucket < flag.rolloutPercentage;
93
+ return { flagKey, enabled, reason: "rollout" };
94
+ }
95
+ return { flagKey, enabled: flag.enabled, reason: "default" };
96
+ }
97
+ async evaluateAll(shopDomain) {
98
+ const { flags } = await this.dataSource.list();
99
+ const result = {};
100
+ for (const flag of flags) {
101
+ result[flag.key] = await this.evaluate(flag.key, shopDomain);
102
+ }
103
+ return result;
104
+ }
105
+ };
106
+ // Annotate the CommonJS export names for ESM import in node:
107
+ 0 && (module.exports = {
108
+ FeatureFlagEvaluator,
109
+ FeatureFlagService
110
+ });
111
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/feature-flags/index.ts","../../src/feature-flags/feature-flag-service.ts","../../src/feature-flags/feature-flag-evaluator.ts"],"sourcesContent":["export type {\n FeatureFlag,\n FeatureFlagCreateInput,\n FeatureFlagUpdateInput,\n FeatureFlagEvaluation,\n FeatureFlagEvaluationReason,\n FeatureFlagListResult,\n FeatureFlagFilter,\n} from './types.js';\n\nexport type { FeatureFlagDataSource } from './feature-flag-data-source.js';\n\nexport { FeatureFlagService } from './feature-flag-service.js';\nexport { FeatureFlagEvaluator } from './feature-flag-evaluator.js';\n","import type { FeatureFlagDataSource } from './feature-flag-data-source.js';\nimport type {\n FeatureFlag,\n FeatureFlagCreateInput,\n FeatureFlagFilter,\n FeatureFlagListResult,\n FeatureFlagUpdateInput,\n} from './types.js';\n\nconst FLAG_KEY_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;\n\nexport class FeatureFlagService {\n private readonly dataSource: FeatureFlagDataSource;\n\n constructor(dataSource: FeatureFlagDataSource) {\n this.dataSource = dataSource;\n }\n\n async createFlag(input: FeatureFlagCreateInput): Promise<FeatureFlag> {\n if (!FLAG_KEY_PATTERN.test(input.key)) {\n throw new Error(\n `Invalid flag key \"${input.key}\". Keys must be alphanumeric and may contain hyphens or underscores.`,\n );\n }\n return this.dataSource.create(input);\n }\n\n async getFlag(flagId: string): Promise<FeatureFlag | null> {\n return this.dataSource.getById(flagId);\n }\n\n async getFlagByKey(key: string): Promise<FeatureFlag | null> {\n return this.dataSource.getByKey(key);\n }\n\n async listFlags(\n filter?: FeatureFlagFilter,\n ): Promise<FeatureFlagListResult> {\n return this.dataSource.list(filter);\n }\n\n async updateFlag(\n flagId: string,\n input: FeatureFlagUpdateInput,\n ): Promise<FeatureFlag | null> {\n return this.dataSource.update(flagId, input);\n }\n\n async deleteFlag(flagId: string): Promise<boolean> {\n return this.dataSource.delete(flagId);\n }\n\n async toggleFlag(\n flagId: string,\n enabled: boolean,\n ): Promise<FeatureFlag | null> {\n return this.dataSource.update(flagId, { enabled });\n }\n}\n","import type { FeatureFlagDataSource } from './feature-flag-data-source.js';\nimport type { FeatureFlagEvaluation } from './types.js';\n\n/**\n * Simple djb2 hash for deterministic rollout.\n * Returns a value in [0, 99].\n */\nfunction hashToPercentage(input: string): number {\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n return Math.abs(hash) % 100;\n}\n\nexport class FeatureFlagEvaluator {\n private readonly dataSource: FeatureFlagDataSource;\n\n constructor(dataSource: FeatureFlagDataSource) {\n this.dataSource = dataSource;\n }\n\n async evaluate(\n flagKey: string,\n shopDomain: string,\n ): Promise<FeatureFlagEvaluation> {\n const flag = await this.dataSource.getByKey(flagKey);\n\n if (!flag) {\n return { flagKey, enabled: false, reason: 'not_found' };\n }\n\n if (!flag.enabled) {\n return { flagKey, enabled: false, reason: 'disabled' };\n }\n\n if (flag.excludedShops.includes(shopDomain)) {\n return { flagKey, enabled: false, reason: 'excluded' };\n }\n\n if (flag.targetShops.includes(shopDomain)) {\n return { flagKey, enabled: true, reason: 'targeted' };\n }\n\n if (flag.rolloutPercentage > 0) {\n const bucket = hashToPercentage(flagKey + shopDomain);\n const enabled = bucket < flag.rolloutPercentage;\n return { flagKey, enabled, reason: 'rollout' };\n }\n\n return { flagKey, enabled: flag.enabled, reason: 'default' };\n }\n\n async evaluateAll(\n shopDomain: string,\n ): Promise<Record<string, FeatureFlagEvaluation>> {\n const { flags } = await this.dataSource.list();\n const result: Record<string, FeatureFlagEvaluation> = {};\n\n for (const flag of flags) {\n result[flag.key] = await this.evaluate(flag.key, shopDomain);\n }\n\n return result;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSA,IAAM,mBAAmB;AAElB,IAAM,qBAAN,MAAyB;AAAA,EACb;AAAA,EAEjB,YAAY,YAAmC;AAC7C,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,MAAM,WAAW,OAAqD;AACpE,QAAI,CAAC,iBAAiB,KAAK,MAAM,GAAG,GAAG;AACrC,YAAM,IAAI;AAAA,QACR,qBAAqB,MAAM,GAAG;AAAA,MAChC;AAAA,IACF;AACA,WAAO,KAAK,WAAW,OAAO,KAAK;AAAA,EACrC;AAAA,EAEA,MAAM,QAAQ,QAA6C;AACzD,WAAO,KAAK,WAAW,QAAQ,MAAM;AAAA,EACvC;AAAA,EAEA,MAAM,aAAa,KAA0C;AAC3D,WAAO,KAAK,WAAW,SAAS,GAAG;AAAA,EACrC;AAAA,EAEA,MAAM,UACJ,QACgC;AAChC,WAAO,KAAK,WAAW,KAAK,MAAM;AAAA,EACpC;AAAA,EAEA,MAAM,WACJ,QACA,OAC6B;AAC7B,WAAO,KAAK,WAAW,OAAO,QAAQ,KAAK;AAAA,EAC7C;AAAA,EAEA,MAAM,WAAW,QAAkC;AACjD,WAAO,KAAK,WAAW,OAAO,MAAM;AAAA,EACtC;AAAA,EAEA,MAAM,WACJ,QACA,SAC6B;AAC7B,WAAO,KAAK,WAAW,OAAO,QAAQ,EAAE,QAAQ,CAAC;AAAA,EACnD;AACF;;;ACnDA,SAAS,iBAAiB,OAAuB;AAC/C,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,WAAQ,OAAO,KAAM,MAAM,WAAW,CAAC;AAAA,EACzC;AACA,SAAO,KAAK,IAAI,IAAI,IAAI;AAC1B;AAEO,IAAM,uBAAN,MAA2B;AAAA,EACf;AAAA,EAEjB,YAAY,YAAmC;AAC7C,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,MAAM,SACJ,SACA,YACgC;AAChC,UAAM,OAAO,MAAM,KAAK,WAAW,SAAS,OAAO;AAEnD,QAAI,CAAC,MAAM;AACT,aAAO,EAAE,SAAS,SAAS,OAAO,QAAQ,YAAY;AAAA,IACxD;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO,EAAE,SAAS,SAAS,OAAO,QAAQ,WAAW;AAAA,IACvD;AAEA,QAAI,KAAK,cAAc,SAAS,UAAU,GAAG;AAC3C,aAAO,EAAE,SAAS,SAAS,OAAO,QAAQ,WAAW;AAAA,IACvD;AAEA,QAAI,KAAK,YAAY,SAAS,UAAU,GAAG;AACzC,aAAO,EAAE,SAAS,SAAS,MAAM,QAAQ,WAAW;AAAA,IACtD;AAEA,QAAI,KAAK,oBAAoB,GAAG;AAC9B,YAAM,SAAS,iBAAiB,UAAU,UAAU;AACpD,YAAM,UAAU,SAAS,KAAK;AAC9B,aAAO,EAAE,SAAS,SAAS,QAAQ,UAAU;AAAA,IAC/C;AAEA,WAAO,EAAE,SAAS,SAAS,KAAK,SAAS,QAAQ,UAAU;AAAA,EAC7D;AAAA,EAEA,MAAM,YACJ,YACgD;AAChD,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,WAAW,KAAK;AAC7C,UAAM,SAAgD,CAAC;AAEvD,eAAW,QAAQ,OAAO;AACxB,aAAO,KAAK,GAAG,IAAI,MAAM,KAAK,SAAS,KAAK,KAAK,UAAU;AAAA,IAC7D;AAEA,WAAO;AAAA,EACT;AACF;","names":[]}