@hot-updater/server 1.0.0-rc.1 → 1.0.0-rc.14

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 (194) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -1
  2. package/dist/adapters/databaseConstraintErrors.cjs +0 -1
  3. package/dist/adapters/databasePluginUtils.cjs +14 -1
  4. package/dist/adapters/databasePluginUtils.mjs +14 -2
  5. package/dist/adapters/drizzle.cjs +8 -3
  6. package/dist/adapters/drizzle.d.cts +0 -1
  7. package/dist/adapters/drizzle.d.mts +0 -1
  8. package/dist/adapters/drizzle.mjs +9 -3
  9. package/dist/adapters/drizzleCrud.cjs +93 -3
  10. package/dist/adapters/drizzleCrud.mjs +93 -5
  11. package/dist/adapters/drizzleLazyDB.cjs +2 -0
  12. package/dist/adapters/drizzleLazyDB.mjs +2 -0
  13. package/dist/adapters/drizzleQuery.cjs +3 -2
  14. package/dist/adapters/drizzleQuery.mjs +3 -1
  15. package/dist/adapters/kysely.cjs +1 -1
  16. package/dist/adapters/kysely.d.cts +0 -1
  17. package/dist/adapters/kysely.d.mts +0 -1
  18. package/dist/adapters/kysely.mjs +2 -1
  19. package/dist/adapters/kyselyCrud.cjs +44 -5
  20. package/dist/adapters/kyselyCrud.mjs +45 -6
  21. package/dist/adapters/kyselyQuery.cjs +2 -2
  22. package/dist/adapters/kyselyQuery.mjs +2 -1
  23. package/dist/adapters/mongodb.cjs +36 -1
  24. package/dist/adapters/mongodb.d.cts +1 -1
  25. package/dist/adapters/mongodb.d.mts +1 -1
  26. package/dist/adapters/mongodb.mjs +36 -0
  27. package/dist/adapters/mongodbCollections.cjs +2 -0
  28. package/dist/adapters/mongodbCollections.mjs +2 -0
  29. package/dist/adapters/mongodbQuery.cjs +17 -4
  30. package/dist/adapters/mongodbQuery.mjs +17 -4
  31. package/dist/adapters/mongodbReads.cjs +88 -30
  32. package/dist/adapters/mongodbReads.mjs +88 -29
  33. package/dist/adapters/mongodbWrites.cjs +1 -2
  34. package/dist/adapters/mongodbWrites.mjs +1 -1
  35. package/dist/adapters/prisma.cjs +44 -7
  36. package/dist/adapters/prisma.d.cts +0 -1
  37. package/dist/adapters/prisma.d.mts +0 -1
  38. package/dist/adapters/prisma.mjs +44 -6
  39. package/dist/adapters/prismaInsights.cjs +99 -0
  40. package/dist/adapters/prismaInsights.mjs +97 -0
  41. package/dist/adapters/prismaQuery.cjs +0 -1
  42. package/dist/adapters/prismaRows.cjs +7 -8
  43. package/dist/adapters/prismaRows.mjs +8 -8
  44. package/dist/apiKeys.cjs +6 -2
  45. package/dist/apiKeys.d.cts +0 -1
  46. package/dist/apiKeys.d.mts +0 -1
  47. package/dist/apiKeys.mjs +3 -3
  48. package/dist/createHotUpdaterCore.cjs +24 -9
  49. package/dist/createHotUpdaterCore.d.cts +1 -1
  50. package/dist/createHotUpdaterCore.d.mts +1 -1
  51. package/dist/createHotUpdaterCore.mjs +23 -9
  52. package/dist/db/createBundleDiff.cjs +2 -2
  53. package/dist/db/createBundleDiff.d.cts +1 -5
  54. package/dist/db/createBundleDiff.d.mts +1 -5
  55. package/dist/db/databasePluginCore.cjs +0 -1
  56. package/dist/db/fixedMigrator.cjs +2 -2
  57. package/dist/db/fixedMigrator.mjs +2 -2
  58. package/dist/db/fixedMigratorMongo.cjs +6 -4
  59. package/dist/db/fixedMigratorMongo.mjs +6 -4
  60. package/dist/db/index.d.cts +0 -1
  61. package/dist/db/index.d.mts +0 -1
  62. package/dist/db/releaseCatalog.cjs +0 -1
  63. package/dist/db/releaseCatalog.d.cts +0 -1
  64. package/dist/db/releaseCatalog.d.mts +0 -1
  65. package/dist/db/schema/insightsCollation.cjs +14 -0
  66. package/dist/db/schema/insightsCollation.mjs +14 -0
  67. package/dist/db/schema/sql.cjs +11 -7
  68. package/dist/db/schema/sql.mjs +8 -8
  69. package/dist/db/schemaGenerators.cjs +29 -9
  70. package/dist/db/schemaGenerators.mjs +29 -9
  71. package/dist/db/schemaReadiness.cjs +2 -0
  72. package/dist/db/schemaReadiness.d.cts +1 -0
  73. package/dist/db/schemaReadiness.d.mts +1 -0
  74. package/dist/db/schemaReadiness.mjs +2 -0
  75. package/dist/db/sqlMigrationExecution.cjs +1 -1
  76. package/dist/db/sqlMigrationExecution.mjs +1 -0
  77. package/dist/db/types.cjs +3 -1
  78. package/dist/db/types.d.cts +3 -6
  79. package/dist/db/types.d.mts +3 -6
  80. package/dist/db/types.mjs +2 -2
  81. package/dist/db/updateArtifacts.cjs +0 -1
  82. package/dist/handler.d.cts +1 -2
  83. package/dist/handler.d.mts +1 -2
  84. package/dist/handlerReleaseCatalogRoutes.cjs +0 -1
  85. package/dist/handlerReleaseManagementRoutes.cjs +0 -1
  86. package/dist/handlerTypes.d.cts +0 -1
  87. package/dist/handlerTypes.d.mts +0 -1
  88. package/dist/handlerVersionRoutes.d.cts +1 -0
  89. package/dist/handlerVersionRoutes.d.mts +1 -0
  90. package/dist/index.cjs +1 -1
  91. package/dist/index.d.cts +4 -4
  92. package/dist/index.d.mts +4 -4
  93. package/dist/index.mjs +1 -1
  94. package/dist/insights/domain.d.cts +41 -70
  95. package/dist/insights/domain.d.mts +41 -70
  96. package/dist/insights/errors.cjs +1 -8
  97. package/dist/insights/errors.mjs +2 -8
  98. package/dist/insights/eventInput.cjs +52 -7
  99. package/dist/insights/eventInput.mjs +51 -8
  100. package/dist/insights/provider.cjs +332 -0
  101. package/dist/insights/provider.d.cts +6 -0
  102. package/dist/insights/provider.d.mts +6 -0
  103. package/dist/insights/provider.mjs +332 -0
  104. package/dist/insights/queryInput.cjs +78 -43
  105. package/dist/insights/queryInput.mjs +76 -40
  106. package/dist/insights/routes.cjs +20 -25
  107. package/dist/insights/routes.mjs +22 -27
  108. package/dist/insights/types.d.cts +27 -12
  109. package/dist/insights/types.d.mts +27 -12
  110. package/dist/node.d.cts +0 -1
  111. package/dist/node.d.mts +0 -1
  112. package/dist/package.cjs +1 -1
  113. package/dist/package.mjs +1 -1
  114. package/dist/schema/index.cjs +17 -3
  115. package/dist/schema/index.mjs +4 -4
  116. package/dist/schema/v1_0_0.cjs +64 -35
  117. package/dist/schema/v1_0_0.mjs +64 -36
  118. package/dist/storageAccess.cjs +0 -1
  119. package/dist/types/index.d.cts +0 -1
  120. package/dist/types/index.d.mts +0 -1
  121. package/package.json +7 -7
  122. package/src/adapters/databasePluginTestDatabase.ts +15 -5
  123. package/src/adapters/databasePluginUtils.ts +24 -0
  124. package/src/adapters/drizzle.spec.ts +203 -5
  125. package/src/adapters/drizzle.ts +15 -3
  126. package/src/adapters/drizzleCrud.ts +200 -9
  127. package/src/adapters/drizzleLazyDB.ts +33 -6
  128. package/src/adapters/kysely.spec.ts +62 -0
  129. package/src/adapters/kysely.ts +7 -1
  130. package/src/adapters/kyselyCrud.ts +115 -7
  131. package/src/adapters/kyselyInsights.spec.ts +168 -0
  132. package/src/adapters/mongodb.integration.spec.ts +483 -0
  133. package/src/adapters/mongodb.spec.ts +89 -0
  134. package/src/adapters/mongodb.ts +59 -1
  135. package/src/adapters/mongodbCollections.ts +16 -0
  136. package/src/adapters/mongodbQuery.ts +22 -3
  137. package/src/adapters/mongodbReads.ts +78 -2
  138. package/src/adapters/mongodbTestClient.ts +107 -6
  139. package/src/adapters/mongodbTestFilter.ts +5 -1
  140. package/src/adapters/mongodbWrites.ts +1 -0
  141. package/src/adapters/prisma.spec.ts +270 -0
  142. package/src/adapters/prisma.ts +75 -2
  143. package/src/adapters/prismaInsights.ts +190 -0
  144. package/src/adapters/prismaRows.ts +17 -10
  145. package/src/adapters/prismaTestClient.ts +89 -7
  146. package/src/apiKeys.integration.spec.ts +1 -1
  147. package/src/createHotUpdaterCore.ts +21 -7
  148. package/src/db/databasePluginUpdateCheck.bench.ts +10 -0
  149. package/src/db/fixedMigrator.spec.ts +63 -0
  150. package/src/db/fixedMigratorMongo.spec.ts +70 -9
  151. package/src/db/fixedMigratorMongo.ts +10 -10
  152. package/src/db/index.spec.ts +6 -1
  153. package/src/db/schema/insightsCollation.ts +21 -0
  154. package/src/db/schema/sql.ts +8 -5
  155. package/src/db/schemaGenerators.ts +42 -13
  156. package/src/db/types.spec.ts +8 -0
  157. package/src/db/types.ts +10 -4
  158. package/src/handler-standalone.integration.spec.ts +5 -7
  159. package/src/index.ts +2 -2
  160. package/src/insights/domain.ts +44 -77
  161. package/src/insights/errors.ts +0 -7
  162. package/src/insights/eventInput.ts +55 -5
  163. package/src/insights/insights.integration.spec.ts +348 -17
  164. package/src/insights/provider.spec.ts +396 -0
  165. package/src/insights/provider.ts +611 -0
  166. package/src/insights/queryInput.ts +113 -73
  167. package/src/insights/routes.ts +37 -56
  168. package/src/insights/types.ts +47 -36
  169. package/src/schema/dsl-all-versions.spec.ts +1 -1
  170. package/src/schema/v1_0_0.spec.ts +77 -3
  171. package/src/schema/v1_0_0.ts +83 -37
  172. package/dist/insights/bounded/activeOverview.cjs +0 -87
  173. package/dist/insights/bounded/activeOverview.mjs +0 -85
  174. package/dist/insights/bounded/installationSearch.cjs +0 -42
  175. package/dist/insights/bounded/installationSearch.mjs +0 -42
  176. package/dist/insights/bounded/persistence.cjs +0 -39
  177. package/dist/insights/bounded/persistence.mjs +0 -38
  178. package/dist/insights/bounded/provider.cjs +0 -170
  179. package/dist/insights/bounded/provider.d.cts +0 -7
  180. package/dist/insights/bounded/provider.d.mts +0 -7
  181. package/dist/insights/bounded/provider.mjs +0 -170
  182. package/dist/insights/bounded/scan.cjs +0 -144
  183. package/dist/insights/bounded/scan.mjs +0 -138
  184. package/dist/insights/persistence.d.cts +0 -6
  185. package/dist/insights/persistence.d.mts +0 -6
  186. package/src/insights/bounded/activeOverview.spec.ts +0 -189
  187. package/src/insights/bounded/activeOverview.ts +0 -148
  188. package/src/insights/bounded/installationSearch.spec.ts +0 -130
  189. package/src/insights/bounded/installationSearch.ts +0 -69
  190. package/src/insights/bounded/persistence.ts +0 -43
  191. package/src/insights/bounded/provider.spec.ts +0 -219
  192. package/src/insights/bounded/provider.ts +0 -229
  193. package/src/insights/bounded/scan.ts +0 -235
  194. package/src/insights/persistence.ts +0 -10
@@ -14,15 +14,7 @@ type CreateBundleEventRequestBase = {
14
14
  readonly toReleaseId: string | null;
15
15
  };
16
16
  type CreateBundleEventRequest = (CreateBundleEventRequestBase & {
17
- readonly type: "UPDATE_APPLIED";
18
- readonly fromBundleId: string;
19
- readonly updateStrategy: "fingerprint" | "appVersion";
20
- }) | (CreateBundleEventRequestBase & {
21
- readonly type: "RECOVERED";
22
- readonly fromBundleId: string;
23
- readonly updateStrategy: "fingerprint" | "appVersion";
24
- }) | (CreateBundleEventRequestBase & {
25
- readonly type: "RELEASE_ADOPTED";
17
+ readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED";
26
18
  readonly fromBundleId: string;
27
19
  readonly updateStrategy: "fingerprint" | "appVersion";
28
20
  }) | (CreateBundleEventRequestBase & {
@@ -30,92 +22,71 @@ type CreateBundleEventRequest = (CreateBundleEventRequestBase & {
30
22
  readonly fromBundleId: null;
31
23
  readonly updateStrategy: null;
32
24
  });
33
- type BundleEventSummary = {
34
- readonly installed: number;
35
- readonly recovered: number;
36
- };
37
- type BundleEventSummaryByBundle = BundleEventSummary & {
38
- readonly bundleId: string;
39
- };
40
- type BundleEventInsightsWindow = "24h" | "7d" | "30d" | "all";
41
25
  type ActiveInstallationWindow = "24h" | "7d" | "30d";
42
- type InstallationSearchRow = {
26
+ type EventHistoryRow = {
27
+ readonly id: string;
43
28
  readonly installId: string;
29
+ readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED" | "UNCHANGED";
30
+ readonly fromBundleId: string | null;
31
+ readonly toBundleId: string;
44
32
  readonly username: string | null;
45
33
  readonly userId: string | null;
46
- readonly lastKnownBundleId: string;
47
- readonly latestStatus: "UPDATE_APPLIED" | "RECOVERED" | "RELEASE_ADOPTED" | "UNCHANGED";
48
34
  readonly platform: "ios" | "android";
49
35
  readonly appVersion: string;
50
36
  readonly channel: string;
51
37
  readonly cohort: string;
52
38
  readonly receivedAtMs: number;
53
39
  };
54
- type InstallationHistoryRow = {
55
- readonly id: string;
56
- readonly type: "UPDATE_APPLIED" | "RECOVERED";
40
+ type InstallationHistoryRow = EventHistoryRow & {
41
+ readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED";
57
42
  readonly fromBundleId: string;
58
- readonly toBundleId: string;
43
+ };
44
+ type InstallationRow = {
45
+ readonly installId: string;
59
46
  readonly username: string | null;
60
47
  readonly userId: string | null;
48
+ readonly lastKnownBundleId: string;
49
+ readonly pendingBundleId: string | null;
50
+ readonly pendingReleaseId: string | null;
51
+ readonly latestStatus: EventHistoryRow["type"];
61
52
  readonly platform: "ios" | "android";
62
53
  readonly appVersion: string;
63
54
  readonly channel: string;
64
55
  readonly cohort: string;
65
56
  readonly receivedAtMs: number;
66
57
  };
67
- type OffsetPaginationResult<TData> = {
68
- readonly data: readonly TData[];
69
- readonly pagination: {
70
- readonly total: number;
71
- readonly limit: number;
72
- readonly offset: number;
73
- };
58
+ type CursorPage<T> = {
59
+ readonly data: readonly T[];
60
+ readonly nextCursor: string | null;
74
61
  };
75
- type InsightsSeriesPoint = {
76
- readonly bucketStartMs: number;
77
- readonly value: number;
62
+ type EventCursorPage<T extends EventHistoryRow> = CursorPage<T> & {
63
+ readonly beforeReceivedAtMs: number;
78
64
  };
79
- type InsightsCohortPoint = {
80
- readonly cohort: string;
81
- readonly value: number;
65
+ type InsightsScope = {
66
+ readonly platform: "ios" | "android";
67
+ readonly channel: string;
82
68
  };
83
- type BundleEventInsightsResult = {
84
- readonly summary: BundleEventSummary;
85
- readonly series: {
86
- readonly installed: readonly InsightsSeriesPoint[];
87
- readonly recovered: readonly InsightsSeriesPoint[];
88
- };
89
- readonly cohorts: {
90
- readonly installed: readonly InsightsCohortPoint[];
91
- readonly recovered: readonly InsightsCohortPoint[];
92
- };
93
- readonly recentEvents: OffsetPaginationResult<InstallationHistoryRow>;
69
+ type InsightsBundleSelection = InsightsScope & {
70
+ readonly bundleId: string;
71
+ readonly outcome: "downloaded" | "applied" | "recovered" | "unchanged";
94
72
  };
95
- type BundleEventOverview = {
96
- readonly trackedInstallations: number;
97
- readonly bundles: readonly {
98
- readonly bundleId: string;
99
- readonly installations: number;
100
- }[];
73
+ type InsightsCountMeasurement = {
74
+ readonly count: number;
75
+ readonly measuredAtMs: number;
101
76
  };
102
- type ActiveInstallationOverview = {
103
- readonly asOfMs: number;
77
+ type ReportingOverview = InsightsScope & {
104
78
  readonly window: ActiveInstallationWindow;
105
- readonly activeInstallations: number;
106
- readonly series: readonly InsightsSeriesPoint[];
107
- readonly bundleSeries: readonly {
79
+ readonly sinceMs: number;
80
+ readonly beforeReceivedAtMs: number;
81
+ readonly reportingInstallations: InsightsCountMeasurement;
82
+ readonly bundle?: {
108
83
  readonly bundleId: string;
109
- readonly series: readonly InsightsSeriesPoint[];
110
- }[];
111
- readonly bundles: readonly {
112
- readonly bundleId: string;
113
- readonly installations: number;
114
- }[];
115
- };
116
- type ActiveInstallationInput = {
117
- readonly window: ActiveInstallationWindow;
118
- readonly userId?: string;
84
+ readonly reportingInstallations: InsightsCountMeasurement;
85
+ readonly downloadedReports: InsightsCountMeasurement;
86
+ readonly appliedReports: InsightsCountMeasurement;
87
+ readonly recoveredReports: InsightsCountMeasurement;
88
+ readonly unchangedReports: InsightsCountMeasurement;
89
+ };
119
90
  };
120
91
  //#endregion
121
- export { ActiveInstallationInput, ActiveInstallationOverview, ActiveInstallationWindow, BundleEventInsightsResult, BundleEventInsightsWindow, BundleEventOverview, BundleEventSummary, BundleEventSummaryByBundle, CreateBundleEventRequest, CreateBundleEventRequestBase, InsightsCohortPoint, InsightsSeriesPoint, InstallationHistoryRow, InstallationSearchRow, OffsetPaginationResult };
92
+ export { ActiveInstallationWindow, CreateBundleEventRequest, CreateBundleEventRequestBase, CursorPage, EventCursorPage, EventHistoryRow, InsightsBundleSelection, InsightsCountMeasurement, InsightsScope, InstallationHistoryRow, InstallationRow, ReportingOverview };
@@ -14,15 +14,7 @@ type CreateBundleEventRequestBase = {
14
14
  readonly toReleaseId: string | null;
15
15
  };
16
16
  type CreateBundleEventRequest = (CreateBundleEventRequestBase & {
17
- readonly type: "UPDATE_APPLIED";
18
- readonly fromBundleId: string;
19
- readonly updateStrategy: "fingerprint" | "appVersion";
20
- }) | (CreateBundleEventRequestBase & {
21
- readonly type: "RECOVERED";
22
- readonly fromBundleId: string;
23
- readonly updateStrategy: "fingerprint" | "appVersion";
24
- }) | (CreateBundleEventRequestBase & {
25
- readonly type: "RELEASE_ADOPTED";
17
+ readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED";
26
18
  readonly fromBundleId: string;
27
19
  readonly updateStrategy: "fingerprint" | "appVersion";
28
20
  }) | (CreateBundleEventRequestBase & {
@@ -30,92 +22,71 @@ type CreateBundleEventRequest = (CreateBundleEventRequestBase & {
30
22
  readonly fromBundleId: null;
31
23
  readonly updateStrategy: null;
32
24
  });
33
- type BundleEventSummary = {
34
- readonly installed: number;
35
- readonly recovered: number;
36
- };
37
- type BundleEventSummaryByBundle = BundleEventSummary & {
38
- readonly bundleId: string;
39
- };
40
- type BundleEventInsightsWindow = "24h" | "7d" | "30d" | "all";
41
25
  type ActiveInstallationWindow = "24h" | "7d" | "30d";
42
- type InstallationSearchRow = {
26
+ type EventHistoryRow = {
27
+ readonly id: string;
43
28
  readonly installId: string;
29
+ readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED" | "UNCHANGED";
30
+ readonly fromBundleId: string | null;
31
+ readonly toBundleId: string;
44
32
  readonly username: string | null;
45
33
  readonly userId: string | null;
46
- readonly lastKnownBundleId: string;
47
- readonly latestStatus: "UPDATE_APPLIED" | "RECOVERED" | "RELEASE_ADOPTED" | "UNCHANGED";
48
34
  readonly platform: "ios" | "android";
49
35
  readonly appVersion: string;
50
36
  readonly channel: string;
51
37
  readonly cohort: string;
52
38
  readonly receivedAtMs: number;
53
39
  };
54
- type InstallationHistoryRow = {
55
- readonly id: string;
56
- readonly type: "UPDATE_APPLIED" | "RECOVERED";
40
+ type InstallationHistoryRow = EventHistoryRow & {
41
+ readonly type: "UPDATE_DOWNLOADED" | "UPDATE_APPLIED" | "RECOVERED";
57
42
  readonly fromBundleId: string;
58
- readonly toBundleId: string;
43
+ };
44
+ type InstallationRow = {
45
+ readonly installId: string;
59
46
  readonly username: string | null;
60
47
  readonly userId: string | null;
48
+ readonly lastKnownBundleId: string;
49
+ readonly pendingBundleId: string | null;
50
+ readonly pendingReleaseId: string | null;
51
+ readonly latestStatus: EventHistoryRow["type"];
61
52
  readonly platform: "ios" | "android";
62
53
  readonly appVersion: string;
63
54
  readonly channel: string;
64
55
  readonly cohort: string;
65
56
  readonly receivedAtMs: number;
66
57
  };
67
- type OffsetPaginationResult<TData> = {
68
- readonly data: readonly TData[];
69
- readonly pagination: {
70
- readonly total: number;
71
- readonly limit: number;
72
- readonly offset: number;
73
- };
58
+ type CursorPage<T> = {
59
+ readonly data: readonly T[];
60
+ readonly nextCursor: string | null;
74
61
  };
75
- type InsightsSeriesPoint = {
76
- readonly bucketStartMs: number;
77
- readonly value: number;
62
+ type EventCursorPage<T extends EventHistoryRow> = CursorPage<T> & {
63
+ readonly beforeReceivedAtMs: number;
78
64
  };
79
- type InsightsCohortPoint = {
80
- readonly cohort: string;
81
- readonly value: number;
65
+ type InsightsScope = {
66
+ readonly platform: "ios" | "android";
67
+ readonly channel: string;
82
68
  };
83
- type BundleEventInsightsResult = {
84
- readonly summary: BundleEventSummary;
85
- readonly series: {
86
- readonly installed: readonly InsightsSeriesPoint[];
87
- readonly recovered: readonly InsightsSeriesPoint[];
88
- };
89
- readonly cohorts: {
90
- readonly installed: readonly InsightsCohortPoint[];
91
- readonly recovered: readonly InsightsCohortPoint[];
92
- };
93
- readonly recentEvents: OffsetPaginationResult<InstallationHistoryRow>;
69
+ type InsightsBundleSelection = InsightsScope & {
70
+ readonly bundleId: string;
71
+ readonly outcome: "downloaded" | "applied" | "recovered" | "unchanged";
94
72
  };
95
- type BundleEventOverview = {
96
- readonly trackedInstallations: number;
97
- readonly bundles: readonly {
98
- readonly bundleId: string;
99
- readonly installations: number;
100
- }[];
73
+ type InsightsCountMeasurement = {
74
+ readonly count: number;
75
+ readonly measuredAtMs: number;
101
76
  };
102
- type ActiveInstallationOverview = {
103
- readonly asOfMs: number;
77
+ type ReportingOverview = InsightsScope & {
104
78
  readonly window: ActiveInstallationWindow;
105
- readonly activeInstallations: number;
106
- readonly series: readonly InsightsSeriesPoint[];
107
- readonly bundleSeries: readonly {
79
+ readonly sinceMs: number;
80
+ readonly beforeReceivedAtMs: number;
81
+ readonly reportingInstallations: InsightsCountMeasurement;
82
+ readonly bundle?: {
108
83
  readonly bundleId: string;
109
- readonly series: readonly InsightsSeriesPoint[];
110
- }[];
111
- readonly bundles: readonly {
112
- readonly bundleId: string;
113
- readonly installations: number;
114
- }[];
115
- };
116
- type ActiveInstallationInput = {
117
- readonly window: ActiveInstallationWindow;
118
- readonly userId?: string;
84
+ readonly reportingInstallations: InsightsCountMeasurement;
85
+ readonly downloadedReports: InsightsCountMeasurement;
86
+ readonly appliedReports: InsightsCountMeasurement;
87
+ readonly recoveredReports: InsightsCountMeasurement;
88
+ readonly unchangedReports: InsightsCountMeasurement;
89
+ };
119
90
  };
120
91
  //#endregion
121
- export { ActiveInstallationInput, ActiveInstallationOverview, ActiveInstallationWindow, BundleEventInsightsResult, BundleEventInsightsWindow, BundleEventOverview, BundleEventSummary, BundleEventSummaryByBundle, CreateBundleEventRequest, CreateBundleEventRequestBase, InsightsCohortPoint, InsightsSeriesPoint, InstallationHistoryRow, InstallationSearchRow, OffsetPaginationResult };
92
+ export { ActiveInstallationWindow, CreateBundleEventRequest, CreateBundleEventRequestBase, CursorPage, EventCursorPage, EventHistoryRow, InsightsBundleSelection, InsightsCountMeasurement, InsightsScope, InstallationHistoryRow, InstallationRow, ReportingOverview };
@@ -1,15 +1,9 @@
1
1
  //#region src/insights/errors.ts
2
- var InsightsScanLimitExceededError = class extends Error {
3
- constructor(limit) {
4
- super(`Insights event scan exceeded ${limit} rows.`);
5
- this.limit = limit;
6
- this.name = "InsightsScanLimitExceededError";
7
- }
8
- };
9
2
  var InsightsBadRequestError = class extends Error {
10
3
  name = "InsightsBadRequestError";
11
4
  };
12
5
  var InsightsPayloadTooLargeError = class extends Error {
6
+ maximumBytes;
13
7
  name = "InsightsPayloadTooLargeError";
14
8
  constructor(maximumBytes) {
15
9
  super(`Event payload exceeds ${maximumBytes} bytes`);
@@ -19,4 +13,3 @@ var InsightsPayloadTooLargeError = class extends Error {
19
13
  //#endregion
20
14
  exports.InsightsBadRequestError = InsightsBadRequestError;
21
15
  exports.InsightsPayloadTooLargeError = InsightsPayloadTooLargeError;
22
- exports.InsightsScanLimitExceededError = InsightsScanLimitExceededError;
@@ -1,15 +1,9 @@
1
1
  //#region src/insights/errors.ts
2
- var InsightsScanLimitExceededError = class extends Error {
3
- constructor(limit) {
4
- super(`Insights event scan exceeded ${limit} rows.`);
5
- this.limit = limit;
6
- this.name = "InsightsScanLimitExceededError";
7
- }
8
- };
9
2
  var InsightsBadRequestError = class extends Error {
10
3
  name = "InsightsBadRequestError";
11
4
  };
12
5
  var InsightsPayloadTooLargeError = class extends Error {
6
+ maximumBytes;
13
7
  name = "InsightsPayloadTooLargeError";
14
8
  constructor(maximumBytes) {
15
9
  super(`Event payload exceeds ${maximumBytes} bytes`);
@@ -17,4 +11,4 @@ var InsightsPayloadTooLargeError = class extends Error {
17
11
  }
18
12
  };
19
13
  //#endregion
20
- export { InsightsBadRequestError, InsightsPayloadTooLargeError, InsightsScanLimitExceededError };
14
+ export { InsightsBadRequestError, InsightsPayloadTooLargeError };
@@ -1,8 +1,10 @@
1
1
  const require_errors = require("./errors.cjs");
2
+ let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
2
3
  //#region src/insights/eventInput.ts
3
4
  const MAX_EVENT_STRING_LENGTH = 1024;
4
- const EVENT_BODY_MAX_BYTES = 16 * 1024;
5
- const eventKeys = new Set([
5
+ const MAX_IDENTITY_LENGTH = 255;
6
+ const EVENT_BODY_MAX_BYTES = 16384;
7
+ const eventKeys = /* @__PURE__ */ new Set([
6
8
  "type",
7
9
  "installId",
8
10
  "toBundleId",
@@ -24,13 +26,18 @@ function isRecord(value) {
24
26
  }
25
27
  function requireStringField(payload, key) {
26
28
  const value = payload[key];
27
- if (typeof value !== "string" || value.length === 0 || value.length > MAX_EVENT_STRING_LENGTH) throw new require_errors.InsightsBadRequestError(`Invalid event field: ${key}`);
29
+ if (typeof value !== "string" || value.length === 0 || value.length > MAX_EVENT_STRING_LENGTH || new TextDecoder("utf-8", { ignoreBOM: true }).decode(new TextEncoder().encode(value)) !== value) throw new require_errors.InsightsBadRequestError(`Invalid event field: ${key}`);
28
30
  return value;
29
31
  }
30
32
  function requireNullableStringField(payload, key) {
31
33
  if (payload[key] === null) return null;
32
34
  return requireStringField(payload, key);
33
35
  }
36
+ function requireIdentityField(payload, key) {
37
+ const value = requireStringField(payload, key);
38
+ if (value.length > MAX_IDENTITY_LENGTH) throw new require_errors.InsightsBadRequestError(`Invalid event field: ${key}`);
39
+ return value;
40
+ }
34
41
  async function readBoundedText(request) {
35
42
  const contentLength = request.headers.get("content-length");
36
43
  const declaredByteLength = Number(contentLength);
@@ -66,9 +73,9 @@ function requireEvent(payload) {
66
73
  const platform = requireStringField(payload, "platform");
67
74
  if (platform !== "ios" && platform !== "android") throw new require_errors.InsightsBadRequestError("Invalid event field: platform");
68
75
  const base = {
69
- installId: requireStringField(payload, "installId"),
76
+ installId: requireIdentityField(payload, "installId"),
70
77
  toBundleId: requireStringField(payload, "toBundleId"),
71
- ...payload.userId === void 0 ? {} : { userId: requireStringField(payload, "userId") },
78
+ ...payload.userId === void 0 ? {} : { userId: requireIdentityField(payload, "userId") },
72
79
  ...payload.username === void 0 ? {} : { username: requireStringField(payload, "username") },
73
80
  platform,
74
81
  appVersion: requireStringField(payload, "appVersion"),
@@ -81,9 +88,9 @@ function requireEvent(payload) {
81
88
  };
82
89
  const type = requireStringField(payload, "type");
83
90
  switch (type) {
91
+ case "UPDATE_DOWNLOADED":
84
92
  case "UPDATE_APPLIED":
85
- case "RECOVERED":
86
- case "RELEASE_ADOPTED": {
93
+ case "RECOVERED": {
87
94
  const updateStrategy = requireStringField(payload, "updateStrategy");
88
95
  if (updateStrategy !== "fingerprint" && updateStrategy !== "appVersion") throw new require_errors.InsightsBadRequestError("Invalid event field: updateStrategy");
89
96
  return {
@@ -107,5 +114,43 @@ function requireEvent(payload) {
107
114
  async function parseBundleEventRequest(request) {
108
115
  return requireEvent(await parseJson(request));
109
116
  }
117
+ function createBundleEventRow(input) {
118
+ input = requireEvent(input);
119
+ const base = {
120
+ app_version: input.appVersion,
121
+ channel: input.channel,
122
+ from_release_id: input.fromReleaseId,
123
+ id: (0, _hot_updater_plugin_core.createUUIDv7)(),
124
+ install_id: input.installId,
125
+ platform: input.platform,
126
+ received_at_ms: Date.now(),
127
+ to_bundle_id: input.toBundleId,
128
+ to_release_id: input.toReleaseId,
129
+ user_id: input.userId ?? null,
130
+ metadata: {
131
+ cohort: input.cohort,
132
+ fingerprint_hash: input.fingerprintHash,
133
+ sdk_version: input.sdkVersion ?? null,
134
+ username: input.username ?? null,
135
+ update_strategy: input.updateStrategy
136
+ }
137
+ };
138
+ switch (input.type) {
139
+ case "UPDATE_DOWNLOADED":
140
+ case "UPDATE_APPLIED":
141
+ case "RECOVERED": return {
142
+ ...base,
143
+ from_bundle_id: input.fromBundleId,
144
+ type: input.type
145
+ };
146
+ case "UNCHANGED": return {
147
+ ...base,
148
+ from_bundle_id: null,
149
+ type: input.type
150
+ };
151
+ }
152
+ }
110
153
  //#endregion
154
+ exports.EVENT_BODY_MAX_BYTES = EVENT_BODY_MAX_BYTES;
155
+ exports.createBundleEventRow = createBundleEventRow;
111
156
  exports.parseBundleEventRequest = parseBundleEventRequest;
@@ -1,8 +1,10 @@
1
1
  import { InsightsBadRequestError, InsightsPayloadTooLargeError } from "./errors.mjs";
2
+ import { createUUIDv7 } from "@hot-updater/plugin-core";
2
3
  //#region src/insights/eventInput.ts
3
4
  const MAX_EVENT_STRING_LENGTH = 1024;
4
- const EVENT_BODY_MAX_BYTES = 16 * 1024;
5
- const eventKeys = new Set([
5
+ const MAX_IDENTITY_LENGTH = 255;
6
+ const EVENT_BODY_MAX_BYTES = 16384;
7
+ const eventKeys = /* @__PURE__ */ new Set([
6
8
  "type",
7
9
  "installId",
8
10
  "toBundleId",
@@ -24,13 +26,18 @@ function isRecord(value) {
24
26
  }
25
27
  function requireStringField(payload, key) {
26
28
  const value = payload[key];
27
- if (typeof value !== "string" || value.length === 0 || value.length > MAX_EVENT_STRING_LENGTH) throw new InsightsBadRequestError(`Invalid event field: ${key}`);
29
+ if (typeof value !== "string" || value.length === 0 || value.length > MAX_EVENT_STRING_LENGTH || new TextDecoder("utf-8", { ignoreBOM: true }).decode(new TextEncoder().encode(value)) !== value) throw new InsightsBadRequestError(`Invalid event field: ${key}`);
28
30
  return value;
29
31
  }
30
32
  function requireNullableStringField(payload, key) {
31
33
  if (payload[key] === null) return null;
32
34
  return requireStringField(payload, key);
33
35
  }
36
+ function requireIdentityField(payload, key) {
37
+ const value = requireStringField(payload, key);
38
+ if (value.length > MAX_IDENTITY_LENGTH) throw new InsightsBadRequestError(`Invalid event field: ${key}`);
39
+ return value;
40
+ }
34
41
  async function readBoundedText(request) {
35
42
  const contentLength = request.headers.get("content-length");
36
43
  const declaredByteLength = Number(contentLength);
@@ -66,9 +73,9 @@ function requireEvent(payload) {
66
73
  const platform = requireStringField(payload, "platform");
67
74
  if (platform !== "ios" && platform !== "android") throw new InsightsBadRequestError("Invalid event field: platform");
68
75
  const base = {
69
- installId: requireStringField(payload, "installId"),
76
+ installId: requireIdentityField(payload, "installId"),
70
77
  toBundleId: requireStringField(payload, "toBundleId"),
71
- ...payload.userId === void 0 ? {} : { userId: requireStringField(payload, "userId") },
78
+ ...payload.userId === void 0 ? {} : { userId: requireIdentityField(payload, "userId") },
72
79
  ...payload.username === void 0 ? {} : { username: requireStringField(payload, "username") },
73
80
  platform,
74
81
  appVersion: requireStringField(payload, "appVersion"),
@@ -81,9 +88,9 @@ function requireEvent(payload) {
81
88
  };
82
89
  const type = requireStringField(payload, "type");
83
90
  switch (type) {
91
+ case "UPDATE_DOWNLOADED":
84
92
  case "UPDATE_APPLIED":
85
- case "RECOVERED":
86
- case "RELEASE_ADOPTED": {
93
+ case "RECOVERED": {
87
94
  const updateStrategy = requireStringField(payload, "updateStrategy");
88
95
  if (updateStrategy !== "fingerprint" && updateStrategy !== "appVersion") throw new InsightsBadRequestError("Invalid event field: updateStrategy");
89
96
  return {
@@ -107,5 +114,41 @@ function requireEvent(payload) {
107
114
  async function parseBundleEventRequest(request) {
108
115
  return requireEvent(await parseJson(request));
109
116
  }
117
+ function createBundleEventRow(input) {
118
+ input = requireEvent(input);
119
+ const base = {
120
+ app_version: input.appVersion,
121
+ channel: input.channel,
122
+ from_release_id: input.fromReleaseId,
123
+ id: createUUIDv7(),
124
+ install_id: input.installId,
125
+ platform: input.platform,
126
+ received_at_ms: Date.now(),
127
+ to_bundle_id: input.toBundleId,
128
+ to_release_id: input.toReleaseId,
129
+ user_id: input.userId ?? null,
130
+ metadata: {
131
+ cohort: input.cohort,
132
+ fingerprint_hash: input.fingerprintHash,
133
+ sdk_version: input.sdkVersion ?? null,
134
+ username: input.username ?? null,
135
+ update_strategy: input.updateStrategy
136
+ }
137
+ };
138
+ switch (input.type) {
139
+ case "UPDATE_DOWNLOADED":
140
+ case "UPDATE_APPLIED":
141
+ case "RECOVERED": return {
142
+ ...base,
143
+ from_bundle_id: input.fromBundleId,
144
+ type: input.type
145
+ };
146
+ case "UNCHANGED": return {
147
+ ...base,
148
+ from_bundle_id: null,
149
+ type: input.type
150
+ };
151
+ }
152
+ }
110
153
  //#endregion
111
- export { parseBundleEventRequest };
154
+ export { EVENT_BODY_MAX_BYTES, createBundleEventRow, parseBundleEventRequest };