@hot-updater/plugin-insights 1.0.0-rc.40 → 1.0.0-rc.42
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/dist/client/index.cjs +32 -36
- package/dist/client/index.d.cts +8 -8
- package/dist/client/index.d.mts +8 -8
- package/dist/client/index.mjs +32 -36
- package/dist/server/adminReads.cjs +78 -0
- package/dist/server/adminReads.d.cts +30 -0
- package/dist/server/adminReads.d.mts +30 -0
- package/dist/server/adminReads.mjs +77 -0
- package/dist/server/index.cjs +3 -0
- package/dist/server/index.d.cts +3 -2
- package/dist/server/index.d.mts +3 -2
- package/dist/server/index.mjs +2 -1
- package/package.json +5 -5
package/dist/client/index.cjs
CHANGED
|
@@ -21,16 +21,22 @@ const normalizeUserId = (user) => {
|
|
|
21
21
|
* ```ts
|
|
22
22
|
* import { HotUpdater, insights } from "@hot-updater/react-native";
|
|
23
23
|
*
|
|
24
|
-
* const
|
|
25
|
-
*
|
|
26
|
-
* analytics.setUser({ userId: "user-123" });
|
|
24
|
+
* export const hotUpdater = HotUpdater.init({ baseURL, plugins: [insights()] });
|
|
25
|
+
* hotUpdater.insights.setUser({ userId: "user-123" });
|
|
27
26
|
* ```
|
|
28
27
|
*/
|
|
29
|
-
const insights = (options = {}) => {
|
|
28
|
+
const insights = (options = {}) => (0, _hot_updater_protocol.defineClientPlugin)({
|
|
29
|
+
id: "insights",
|
|
30
|
+
setup: (pluginContext) => setUpInsights(options, pluginContext)
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* One instance's Insights: its context, device state, and delivery queue,
|
|
34
|
+
* created by each `setup`, so a plugin object set up by two instances keeps
|
|
35
|
+
* their reports apart.
|
|
36
|
+
*/
|
|
37
|
+
const setUpInsights = (options, pluginContext) => {
|
|
30
38
|
let context = null;
|
|
31
39
|
let state = null;
|
|
32
|
-
/** A user set before setup, applied once the plugin has storage. */
|
|
33
|
-
let pendingUser = null;
|
|
34
40
|
/** A download in this runtime: a later no-change report would hide it. */
|
|
35
41
|
let didDownload = false;
|
|
36
42
|
let lastDownloadedSelection = null;
|
|
@@ -217,37 +223,27 @@ const insights = (options = {}) => {
|
|
|
217
223
|
if (event.report !== null) state.recordReport(event.report);
|
|
218
224
|
else state.forgetReport();
|
|
219
225
|
};
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
send = require_sender.createInsightsEventSender(pluginContext.fetch, {
|
|
231
|
-
admit,
|
|
232
|
-
settle
|
|
233
|
-
});
|
|
234
|
-
return {
|
|
235
|
-
onAppReady,
|
|
236
|
-
onUpdateCheck,
|
|
237
|
-
onBundleDownloaded,
|
|
238
|
-
onUpdateError,
|
|
239
|
-
onHttpResponse
|
|
240
|
-
};
|
|
241
|
-
},
|
|
242
|
-
setUser(user) {
|
|
243
|
-
const userId = normalizeUserId(user);
|
|
244
|
-
if (state === null) {
|
|
245
|
-
pendingUser = { userId };
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
state.writeUserId(userId);
|
|
249
|
-
}
|
|
226
|
+
context = pluginContext;
|
|
227
|
+
const pluginState = require_state.createInsightsState(pluginContext.storage);
|
|
228
|
+
state = pluginState;
|
|
229
|
+
const api = Object.freeze({ setUser: (user) => {
|
|
230
|
+
pluginState.writeUserId(normalizeUserId(user));
|
|
231
|
+
} });
|
|
232
|
+
if (pluginContext.isDebugBuild && options.debug !== true) return { api };
|
|
233
|
+
send = require_sender.createInsightsEventSender(pluginContext.fetch, {
|
|
234
|
+
admit,
|
|
235
|
+
settle
|
|
250
236
|
});
|
|
237
|
+
return {
|
|
238
|
+
api,
|
|
239
|
+
hooks: {
|
|
240
|
+
onAppReady,
|
|
241
|
+
onUpdateCheck,
|
|
242
|
+
onBundleDownloaded,
|
|
243
|
+
onUpdateError,
|
|
244
|
+
onHttpResponse
|
|
245
|
+
}
|
|
246
|
+
};
|
|
251
247
|
};
|
|
252
248
|
//#endregion
|
|
253
249
|
exports.insights = insights;
|
package/dist/client/index.d.cts
CHANGED
|
@@ -11,15 +11,16 @@ interface InsightsOptions {
|
|
|
11
11
|
interface InsightsUser {
|
|
12
12
|
readonly userId: string | number;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
/** Insights on the instance `HotUpdater.init` returns, as `hotUpdater.insights`. */
|
|
15
|
+
interface InsightsClient {
|
|
16
16
|
/**
|
|
17
17
|
* Attaches the signed-in user's id to later reports, or clears it with
|
|
18
|
-
* `null`. It persists on the device
|
|
19
|
-
* called before `HotUpdater.init`.
|
|
18
|
+
* `null`. It persists on the device and sends nothing by itself.
|
|
20
19
|
*/
|
|
21
20
|
setUser(user: InsightsUser | null): void;
|
|
22
21
|
}
|
|
22
|
+
/** The `insights()` plugin: it adds `hotUpdater.insights`. */
|
|
23
|
+
type InsightsPlugin = HotUpdaterClientPlugin<"insights", InsightsClient>;
|
|
23
24
|
/**
|
|
24
25
|
* Reports update adoption to a server that runs the `insights()` server
|
|
25
26
|
* plugin: launches (at most once a UTC day while nothing changes), downloads,
|
|
@@ -31,11 +32,10 @@ interface InsightsPlugin extends HotUpdaterClientPlugin {
|
|
|
31
32
|
* ```ts
|
|
32
33
|
* import { HotUpdater, insights } from "@hot-updater/react-native";
|
|
33
34
|
*
|
|
34
|
-
* const
|
|
35
|
-
*
|
|
36
|
-
* analytics.setUser({ userId: "user-123" });
|
|
35
|
+
* export const hotUpdater = HotUpdater.init({ baseURL, plugins: [insights()] });
|
|
36
|
+
* hotUpdater.insights.setUser({ userId: "user-123" });
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
39
|
declare const insights: (options?: InsightsOptions) => InsightsPlugin;
|
|
40
40
|
//#endregion
|
|
41
|
-
export { InsightsOptions, InsightsPlugin, InsightsUser, insights };
|
|
41
|
+
export { InsightsClient, InsightsOptions, InsightsPlugin, InsightsUser, insights };
|
package/dist/client/index.d.mts
CHANGED
|
@@ -11,15 +11,16 @@ interface InsightsOptions {
|
|
|
11
11
|
interface InsightsUser {
|
|
12
12
|
readonly userId: string | number;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
/** Insights on the instance `HotUpdater.init` returns, as `hotUpdater.insights`. */
|
|
15
|
+
interface InsightsClient {
|
|
16
16
|
/**
|
|
17
17
|
* Attaches the signed-in user's id to later reports, or clears it with
|
|
18
|
-
* `null`. It persists on the device
|
|
19
|
-
* called before `HotUpdater.init`.
|
|
18
|
+
* `null`. It persists on the device and sends nothing by itself.
|
|
20
19
|
*/
|
|
21
20
|
setUser(user: InsightsUser | null): void;
|
|
22
21
|
}
|
|
22
|
+
/** The `insights()` plugin: it adds `hotUpdater.insights`. */
|
|
23
|
+
type InsightsPlugin = HotUpdaterClientPlugin<"insights", InsightsClient>;
|
|
23
24
|
/**
|
|
24
25
|
* Reports update adoption to a server that runs the `insights()` server
|
|
25
26
|
* plugin: launches (at most once a UTC day while nothing changes), downloads,
|
|
@@ -31,11 +32,10 @@ interface InsightsPlugin extends HotUpdaterClientPlugin {
|
|
|
31
32
|
* ```ts
|
|
32
33
|
* import { HotUpdater, insights } from "@hot-updater/react-native";
|
|
33
34
|
*
|
|
34
|
-
* const
|
|
35
|
-
*
|
|
36
|
-
* analytics.setUser({ userId: "user-123" });
|
|
35
|
+
* export const hotUpdater = HotUpdater.init({ baseURL, plugins: [insights()] });
|
|
36
|
+
* hotUpdater.insights.setUser({ userId: "user-123" });
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
39
|
declare const insights: (options?: InsightsOptions) => InsightsPlugin;
|
|
40
40
|
//#endregion
|
|
41
|
-
export { InsightsOptions, InsightsPlugin, InsightsUser, insights };
|
|
41
|
+
export { InsightsClient, InsightsOptions, InsightsPlugin, InsightsUser, insights };
|
package/dist/client/index.mjs
CHANGED
|
@@ -20,16 +20,22 @@ const normalizeUserId = (user) => {
|
|
|
20
20
|
* ```ts
|
|
21
21
|
* import { HotUpdater, insights } from "@hot-updater/react-native";
|
|
22
22
|
*
|
|
23
|
-
* const
|
|
24
|
-
*
|
|
25
|
-
* analytics.setUser({ userId: "user-123" });
|
|
23
|
+
* export const hotUpdater = HotUpdater.init({ baseURL, plugins: [insights()] });
|
|
24
|
+
* hotUpdater.insights.setUser({ userId: "user-123" });
|
|
26
25
|
* ```
|
|
27
26
|
*/
|
|
28
|
-
const insights = (options = {}) => {
|
|
27
|
+
const insights = (options = {}) => defineClientPlugin({
|
|
28
|
+
id: "insights",
|
|
29
|
+
setup: (pluginContext) => setUpInsights(options, pluginContext)
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* One instance's Insights: its context, device state, and delivery queue,
|
|
33
|
+
* created by each `setup`, so a plugin object set up by two instances keeps
|
|
34
|
+
* their reports apart.
|
|
35
|
+
*/
|
|
36
|
+
const setUpInsights = (options, pluginContext) => {
|
|
29
37
|
let context = null;
|
|
30
38
|
let state = null;
|
|
31
|
-
/** A user set before setup, applied once the plugin has storage. */
|
|
32
|
-
let pendingUser = null;
|
|
33
39
|
/** A download in this runtime: a later no-change report would hide it. */
|
|
34
40
|
let didDownload = false;
|
|
35
41
|
let lastDownloadedSelection = null;
|
|
@@ -216,37 +222,27 @@ const insights = (options = {}) => {
|
|
|
216
222
|
if (event.report !== null) state.recordReport(event.report);
|
|
217
223
|
else state.forgetReport();
|
|
218
224
|
};
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
send = createInsightsEventSender(pluginContext.fetch, {
|
|
230
|
-
admit,
|
|
231
|
-
settle
|
|
232
|
-
});
|
|
233
|
-
return {
|
|
234
|
-
onAppReady,
|
|
235
|
-
onUpdateCheck,
|
|
236
|
-
onBundleDownloaded,
|
|
237
|
-
onUpdateError,
|
|
238
|
-
onHttpResponse
|
|
239
|
-
};
|
|
240
|
-
},
|
|
241
|
-
setUser(user) {
|
|
242
|
-
const userId = normalizeUserId(user);
|
|
243
|
-
if (state === null) {
|
|
244
|
-
pendingUser = { userId };
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
state.writeUserId(userId);
|
|
248
|
-
}
|
|
225
|
+
context = pluginContext;
|
|
226
|
+
const pluginState = createInsightsState(pluginContext.storage);
|
|
227
|
+
state = pluginState;
|
|
228
|
+
const api = Object.freeze({ setUser: (user) => {
|
|
229
|
+
pluginState.writeUserId(normalizeUserId(user));
|
|
230
|
+
} });
|
|
231
|
+
if (pluginContext.isDebugBuild && options.debug !== true) return { api };
|
|
232
|
+
send = createInsightsEventSender(pluginContext.fetch, {
|
|
233
|
+
admit,
|
|
234
|
+
settle
|
|
249
235
|
});
|
|
236
|
+
return {
|
|
237
|
+
api,
|
|
238
|
+
hooks: {
|
|
239
|
+
onAppReady,
|
|
240
|
+
onUpdateCheck,
|
|
241
|
+
onBundleDownloaded,
|
|
242
|
+
onUpdateError,
|
|
243
|
+
onHttpResponse
|
|
244
|
+
}
|
|
245
|
+
};
|
|
250
246
|
};
|
|
251
247
|
//#endregion
|
|
252
248
|
export { insights };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const require_model = require("./model.cjs");
|
|
2
|
+
const require_provider = require("./provider.cjs");
|
|
3
|
+
//#region src/server/adminReads.ts
|
|
4
|
+
/** The reads over the `insights()` API tooling assembled on the server's database. */
|
|
5
|
+
const createInsightsReads = (api) => ({
|
|
6
|
+
...require_provider.createInsightsProvider(require_model.createInsightsModel(api)),
|
|
7
|
+
getRetention: async () => api.retention,
|
|
8
|
+
getUpdateFailures: api.getUpdateFailures
|
|
9
|
+
});
|
|
10
|
+
/** The `error` a failed admin route answered with, or a message naming its status. */
|
|
11
|
+
const errorOf = async (response, path) => {
|
|
12
|
+
const body = await response.json().catch(() => null);
|
|
13
|
+
return new Error(typeof body === "object" && body !== null && typeof Reflect.get(body, "error") === "string" ? String(Reflect.get(body, "error")) : `The server answered ${path.split("?")[0]} with ${response.status}.`);
|
|
14
|
+
};
|
|
15
|
+
const withQuery = (path, input) => {
|
|
16
|
+
const query = new URLSearchParams();
|
|
17
|
+
for (const [key, value] of Object.entries(input)) if (value !== void 0) query.set(key, String(value));
|
|
18
|
+
const value = query.toString();
|
|
19
|
+
return value.length === 0 ? path : `${path}?${value}`;
|
|
20
|
+
};
|
|
21
|
+
const eventQuery = ({ beforeReceivedAtMs, sinceMs, cursor, limit }) => ({
|
|
22
|
+
beforeReceivedAtMs,
|
|
23
|
+
sinceMs,
|
|
24
|
+
cursor,
|
|
25
|
+
limit
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* The reads over a self-hosted server's admin routes, which its `insights()`
|
|
29
|
+
* serves, for tooling that reaches it through `standaloneRepository`.
|
|
30
|
+
*/
|
|
31
|
+
const createInsightsAdminReads = (fetchAdmin, { unavailable = () => /* @__PURE__ */ new Error("The server runs without insights(): its admin API serves no Insights routes.") } = {}) => {
|
|
32
|
+
const read = async (path) => {
|
|
33
|
+
const response = await fetchAdmin(path);
|
|
34
|
+
if (response.status === 404) return null;
|
|
35
|
+
if (!response.ok) throw await errorOf(response, path);
|
|
36
|
+
return await response.json();
|
|
37
|
+
};
|
|
38
|
+
const required = async (path) => {
|
|
39
|
+
const value = await read(path);
|
|
40
|
+
if (value === null) throw unavailable();
|
|
41
|
+
return value;
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
getReportingOverview: ({ platform, channel, window, bundleId }) => required(withQuery("/overview", {
|
|
45
|
+
platform,
|
|
46
|
+
channel,
|
|
47
|
+
window,
|
|
48
|
+
bundleId
|
|
49
|
+
})),
|
|
50
|
+
listEvents: ({ bundle, ...input }) => required(withQuery("/events", {
|
|
51
|
+
...eventQuery(input),
|
|
52
|
+
...bundle === void 0 ? {} : {
|
|
53
|
+
platform: bundle.platform,
|
|
54
|
+
channel: bundle.channel,
|
|
55
|
+
bundleId: bundle.bundleId,
|
|
56
|
+
outcome: bundle.outcome
|
|
57
|
+
}
|
|
58
|
+
})),
|
|
59
|
+
listInstallationEvents: ({ installId, ...input }) => required(withQuery(`/installations/${encodeURIComponent(installId)}/events`, eventQuery(input))),
|
|
60
|
+
getInstallation: ({ installId }) => read(`/installations/${encodeURIComponent(installId)}`),
|
|
61
|
+
pageInstallationsByCurrentUserId: ({ userId, cursor, limit }) => required(withQuery("/installations", {
|
|
62
|
+
userId,
|
|
63
|
+
cursor,
|
|
64
|
+
limit
|
|
65
|
+
})),
|
|
66
|
+
getUpdateFailures: ({ platform, channel, releaseId, timeRange }) => required(withQuery("/failures", {
|
|
67
|
+
platform,
|
|
68
|
+
channel,
|
|
69
|
+
releaseId,
|
|
70
|
+
start: timeRange?.start,
|
|
71
|
+
end: timeRange?.end
|
|
72
|
+
})),
|
|
73
|
+
getRetention: () => required("/retention")
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
exports.createInsightsAdminReads = createInsightsAdminReads;
|
|
78
|
+
exports.createInsightsReads = createInsightsReads;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { InsightsRetention } from "./schema.cjs";
|
|
2
|
+
import { InsightsUpdateFailures, InsightsUpdateFailuresInput } from "./reads.cjs";
|
|
3
|
+
import { InsightsProvider } from "./types.cjs";
|
|
4
|
+
import { InsightsApi } from "./index.cjs";
|
|
5
|
+
import { RemoteDatabase } from "@hot-updater/plugin-core";
|
|
6
|
+
//#region src/server/adminReads.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* The Insights reads tooling shows, the Console and the CLI: the routes'
|
|
9
|
+
* reads, update failures, and how long rows are kept.
|
|
10
|
+
*/
|
|
11
|
+
type InsightsReads = Omit<InsightsProvider, "appendBundleEvent"> & {
|
|
12
|
+
getRetention(): Promise<InsightsRetention>;
|
|
13
|
+
getUpdateFailures(input: InsightsUpdateFailuresInput): Promise<InsightsUpdateFailures>;
|
|
14
|
+
};
|
|
15
|
+
/** The reads over the `insights()` API tooling assembled on the server's database. */
|
|
16
|
+
declare const createInsightsReads: (api: InsightsApi) => InsightsReads;
|
|
17
|
+
interface InsightsAdminReadsOptions {
|
|
18
|
+
/**
|
|
19
|
+
* The error for a server that runs without `insights()`, whose admin API
|
|
20
|
+
* answers its routes with 404.
|
|
21
|
+
*/
|
|
22
|
+
readonly unavailable?: () => Error;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The reads over a self-hosted server's admin routes, which its `insights()`
|
|
26
|
+
* serves, for tooling that reaches it through `standaloneRepository`.
|
|
27
|
+
*/
|
|
28
|
+
declare const createInsightsAdminReads: (fetchAdmin: RemoteDatabase["fetchAdmin"], { unavailable }?: InsightsAdminReadsOptions) => InsightsReads;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { InsightsAdminReadsOptions, InsightsReads, createInsightsAdminReads, createInsightsReads };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { InsightsRetention } from "./schema.mjs";
|
|
2
|
+
import { InsightsUpdateFailures, InsightsUpdateFailuresInput } from "./reads.mjs";
|
|
3
|
+
import { InsightsProvider } from "./types.mjs";
|
|
4
|
+
import { InsightsApi } from "./index.mjs";
|
|
5
|
+
import { RemoteDatabase } from "@hot-updater/plugin-core";
|
|
6
|
+
//#region src/server/adminReads.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* The Insights reads tooling shows, the Console and the CLI: the routes'
|
|
9
|
+
* reads, update failures, and how long rows are kept.
|
|
10
|
+
*/
|
|
11
|
+
type InsightsReads = Omit<InsightsProvider, "appendBundleEvent"> & {
|
|
12
|
+
getRetention(): Promise<InsightsRetention>;
|
|
13
|
+
getUpdateFailures(input: InsightsUpdateFailuresInput): Promise<InsightsUpdateFailures>;
|
|
14
|
+
};
|
|
15
|
+
/** The reads over the `insights()` API tooling assembled on the server's database. */
|
|
16
|
+
declare const createInsightsReads: (api: InsightsApi) => InsightsReads;
|
|
17
|
+
interface InsightsAdminReadsOptions {
|
|
18
|
+
/**
|
|
19
|
+
* The error for a server that runs without `insights()`, whose admin API
|
|
20
|
+
* answers its routes with 404.
|
|
21
|
+
*/
|
|
22
|
+
readonly unavailable?: () => Error;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The reads over a self-hosted server's admin routes, which its `insights()`
|
|
26
|
+
* serves, for tooling that reaches it through `standaloneRepository`.
|
|
27
|
+
*/
|
|
28
|
+
declare const createInsightsAdminReads: (fetchAdmin: RemoteDatabase["fetchAdmin"], { unavailable }?: InsightsAdminReadsOptions) => InsightsReads;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { InsightsAdminReadsOptions, InsightsReads, createInsightsAdminReads, createInsightsReads };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createInsightsModel } from "./model.mjs";
|
|
2
|
+
import { createInsightsProvider } from "./provider.mjs";
|
|
3
|
+
//#region src/server/adminReads.ts
|
|
4
|
+
/** The reads over the `insights()` API tooling assembled on the server's database. */
|
|
5
|
+
const createInsightsReads = (api) => ({
|
|
6
|
+
...createInsightsProvider(createInsightsModel(api)),
|
|
7
|
+
getRetention: async () => api.retention,
|
|
8
|
+
getUpdateFailures: api.getUpdateFailures
|
|
9
|
+
});
|
|
10
|
+
/** The `error` a failed admin route answered with, or a message naming its status. */
|
|
11
|
+
const errorOf = async (response, path) => {
|
|
12
|
+
const body = await response.json().catch(() => null);
|
|
13
|
+
return new Error(typeof body === "object" && body !== null && typeof Reflect.get(body, "error") === "string" ? String(Reflect.get(body, "error")) : `The server answered ${path.split("?")[0]} with ${response.status}.`);
|
|
14
|
+
};
|
|
15
|
+
const withQuery = (path, input) => {
|
|
16
|
+
const query = new URLSearchParams();
|
|
17
|
+
for (const [key, value] of Object.entries(input)) if (value !== void 0) query.set(key, String(value));
|
|
18
|
+
const value = query.toString();
|
|
19
|
+
return value.length === 0 ? path : `${path}?${value}`;
|
|
20
|
+
};
|
|
21
|
+
const eventQuery = ({ beforeReceivedAtMs, sinceMs, cursor, limit }) => ({
|
|
22
|
+
beforeReceivedAtMs,
|
|
23
|
+
sinceMs,
|
|
24
|
+
cursor,
|
|
25
|
+
limit
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* The reads over a self-hosted server's admin routes, which its `insights()`
|
|
29
|
+
* serves, for tooling that reaches it through `standaloneRepository`.
|
|
30
|
+
*/
|
|
31
|
+
const createInsightsAdminReads = (fetchAdmin, { unavailable = () => /* @__PURE__ */ new Error("The server runs without insights(): its admin API serves no Insights routes.") } = {}) => {
|
|
32
|
+
const read = async (path) => {
|
|
33
|
+
const response = await fetchAdmin(path);
|
|
34
|
+
if (response.status === 404) return null;
|
|
35
|
+
if (!response.ok) throw await errorOf(response, path);
|
|
36
|
+
return await response.json();
|
|
37
|
+
};
|
|
38
|
+
const required = async (path) => {
|
|
39
|
+
const value = await read(path);
|
|
40
|
+
if (value === null) throw unavailable();
|
|
41
|
+
return value;
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
getReportingOverview: ({ platform, channel, window, bundleId }) => required(withQuery("/overview", {
|
|
45
|
+
platform,
|
|
46
|
+
channel,
|
|
47
|
+
window,
|
|
48
|
+
bundleId
|
|
49
|
+
})),
|
|
50
|
+
listEvents: ({ bundle, ...input }) => required(withQuery("/events", {
|
|
51
|
+
...eventQuery(input),
|
|
52
|
+
...bundle === void 0 ? {} : {
|
|
53
|
+
platform: bundle.platform,
|
|
54
|
+
channel: bundle.channel,
|
|
55
|
+
bundleId: bundle.bundleId,
|
|
56
|
+
outcome: bundle.outcome
|
|
57
|
+
}
|
|
58
|
+
})),
|
|
59
|
+
listInstallationEvents: ({ installId, ...input }) => required(withQuery(`/installations/${encodeURIComponent(installId)}/events`, eventQuery(input))),
|
|
60
|
+
getInstallation: ({ installId }) => read(`/installations/${encodeURIComponent(installId)}`),
|
|
61
|
+
pageInstallationsByCurrentUserId: ({ userId, cursor, limit }) => required(withQuery("/installations", {
|
|
62
|
+
userId,
|
|
63
|
+
cursor,
|
|
64
|
+
limit
|
|
65
|
+
})),
|
|
66
|
+
getUpdateFailures: ({ platform, channel, releaseId, timeRange }) => required(withQuery("/failures", {
|
|
67
|
+
platform,
|
|
68
|
+
channel,
|
|
69
|
+
releaseId,
|
|
70
|
+
start: timeRange?.start,
|
|
71
|
+
end: timeRange?.end
|
|
72
|
+
})),
|
|
73
|
+
getRetention: () => required("/retention")
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
export { createInsightsAdminReads, createInsightsReads };
|
package/dist/server/index.cjs
CHANGED
|
@@ -7,6 +7,7 @@ const require_provider = require("./provider.cjs");
|
|
|
7
7
|
const require_recordEvent = require("./recordEvent.cjs");
|
|
8
8
|
const require_reads = require("./reads.cjs");
|
|
9
9
|
const require_routes = require("./routes.cjs");
|
|
10
|
+
const require_adminReads = require("./adminReads.cjs");
|
|
10
11
|
let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
|
|
11
12
|
//#region src/server/index.ts
|
|
12
13
|
const createInsightsApi = (db, now, retention) => ({
|
|
@@ -122,8 +123,10 @@ const insights = (options = {}) => {
|
|
|
122
123
|
//#endregion
|
|
123
124
|
exports.DEFAULT_INSIGHTS_RETENTION = require_schema.DEFAULT_INSIGHTS_RETENTION;
|
|
124
125
|
exports.InsightsBadRequestError = require_errors.InsightsBadRequestError;
|
|
126
|
+
exports.createInsightsAdminReads = require_adminReads.createInsightsAdminReads;
|
|
125
127
|
exports.createInsightsModel = require_model.createInsightsModel;
|
|
126
128
|
exports.createInsightsProvider = require_provider.createInsightsProvider;
|
|
129
|
+
exports.createInsightsReads = require_adminReads.createInsightsReads;
|
|
127
130
|
exports.createInsightsSchema = require_schema.createInsightsSchema;
|
|
128
131
|
exports.insights = insights;
|
|
129
132
|
exports.insightsIdentity = require_recordEvent.insightsIdentity;
|
package/dist/server/index.d.cts
CHANGED
|
@@ -3,9 +3,10 @@ import { InsightsBundleEventFilter, InsightsCountEventSeriesInput, InsightsCount
|
|
|
3
3
|
import { DEFAULT_INSIGHTS_RETENTION, InsightsRetention, InsightsSchema, createInsightsSchema, insightsSchema } from "./schema.cjs";
|
|
4
4
|
import { InsightsFailureBreakdown, InsightsUpdateFailures, InsightsUpdateFailuresInput } from "./reads.cjs";
|
|
5
5
|
import { ActiveInstallationWindow, BundleEventFailureInput, CreateBundleEventRequest, CreateBundleEventRequestBase, CursorPage, EventCursorPage, EventHistoryChange, EventHistoryRow, InsightsBundleSelection, InsightsCountMeasurement, InsightsHttpResponse, InstallationHistoryRow, InstallationRow, ReportingOverview } from "./domain.cjs";
|
|
6
|
+
import { InsightsEventPageInput, InsightsInstallationEventPageInput, InsightsProvider, InsightsUserInstallationPageInput } from "./types.cjs";
|
|
7
|
+
import { InsightsAdminReadsOptions, InsightsReads, createInsightsAdminReads, createInsightsReads } from "./adminReads.cjs";
|
|
6
8
|
import { InsightsBadRequestError } from "./errors.cjs";
|
|
7
9
|
import { createInsightsModel } from "./model.cjs";
|
|
8
|
-
import { InsightsEventPageInput, InsightsInstallationEventPageInput, InsightsProvider, InsightsUserInstallationPageInput } from "./types.cjs";
|
|
9
10
|
import { createInsightsProvider } from "./provider.cjs";
|
|
10
11
|
import { InsightsIdentityParts, insightsIdentity } from "./recordEvent.cjs";
|
|
11
12
|
import { HotUpdaterDatabase, PluginEndpoint } from "@hot-updater/plugin-core";
|
|
@@ -422,4 +423,4 @@ declare const insights: (options?: InsightsOptions) => import("@hot-updater/plug
|
|
|
422
423
|
endpoints: PluginEndpoint[];
|
|
423
424
|
}, {}>;
|
|
424
425
|
//#endregion
|
|
425
|
-
export { type ActiveInstallationWindow, type BundleEventFailure, type BundleEventFailureInput, type BundleEventFailureReason, type BundleEventFailureStage, type BundleEventRow, type BundleEventRowBase, type CreateBundleEventRequest, type CreateBundleEventRequestBase, type CursorPage, DEFAULT_INSIGHTS_RETENTION, type DatabaseBundleEventMetadata, type EventCursorPage, type EventHistoryChange, type EventHistoryRow, InsightsApi, InsightsBadRequestError, type InsightsBundleEventFilter, type InsightsBundleSelection, type InsightsCountEventSeriesInput, type InsightsCountEventsInput, type InsightsCountLatestEventsInput, type InsightsCountMeasurement, type InsightsCoverage, type InsightsEventCursor, type InsightsEventFilter, type InsightsEventPageInput, type InsightsEventSeriesPoint, type InsightsFailureBreakdown, type InsightsFindLatestEventsInput, type InsightsGetAppUsageInput, type InsightsGetAppUsageResult, type InsightsGetReleaseActivityInput, type InsightsGetReleaseActivityResult, type InsightsHttpResponse, type InsightsIdentityParts, type InsightsInstallationEventPageInput, type InsightsListEventsInput, type InsightsModel, InsightsOptions, type InsightsProvider, type InsightsRecordEventInput, type InsightsRetention, type InsightsSchema, type InsightsScope, type InsightsTimeRange, type InsightsUpdateFailures, type InsightsUpdateFailuresInput, type InsightsUserInstallationPageInput, type InstallationHistoryRow, type InstallationRow, type ReleaseActivityMetrics, type ReleaseReference, type ReportingOverview, createInsightsModel, createInsightsProvider, createInsightsSchema, insights, insightsIdentity, insightsSchema };
|
|
426
|
+
export { type ActiveInstallationWindow, type BundleEventFailure, type BundleEventFailureInput, type BundleEventFailureReason, type BundleEventFailureStage, type BundleEventRow, type BundleEventRowBase, type CreateBundleEventRequest, type CreateBundleEventRequestBase, type CursorPage, DEFAULT_INSIGHTS_RETENTION, type DatabaseBundleEventMetadata, type EventCursorPage, type EventHistoryChange, type EventHistoryRow, type InsightsAdminReadsOptions, InsightsApi, InsightsBadRequestError, type InsightsBundleEventFilter, type InsightsBundleSelection, type InsightsCountEventSeriesInput, type InsightsCountEventsInput, type InsightsCountLatestEventsInput, type InsightsCountMeasurement, type InsightsCoverage, type InsightsEventCursor, type InsightsEventFilter, type InsightsEventPageInput, type InsightsEventSeriesPoint, type InsightsFailureBreakdown, type InsightsFindLatestEventsInput, type InsightsGetAppUsageInput, type InsightsGetAppUsageResult, type InsightsGetReleaseActivityInput, type InsightsGetReleaseActivityResult, type InsightsHttpResponse, type InsightsIdentityParts, type InsightsInstallationEventPageInput, type InsightsListEventsInput, type InsightsModel, InsightsOptions, type InsightsProvider, type InsightsReads, type InsightsRecordEventInput, type InsightsRetention, type InsightsSchema, type InsightsScope, type InsightsTimeRange, type InsightsUpdateFailures, type InsightsUpdateFailuresInput, type InsightsUserInstallationPageInput, type InstallationHistoryRow, type InstallationRow, type ReleaseActivityMetrics, type ReleaseReference, type ReportingOverview, createInsightsAdminReads, createInsightsModel, createInsightsProvider, createInsightsReads, createInsightsSchema, insights, insightsIdentity, insightsSchema };
|
package/dist/server/index.d.mts
CHANGED
|
@@ -3,9 +3,10 @@ import { InsightsBundleEventFilter, InsightsCountEventSeriesInput, InsightsCount
|
|
|
3
3
|
import { DEFAULT_INSIGHTS_RETENTION, InsightsRetention, InsightsSchema, createInsightsSchema, insightsSchema } from "./schema.mjs";
|
|
4
4
|
import { InsightsFailureBreakdown, InsightsUpdateFailures, InsightsUpdateFailuresInput } from "./reads.mjs";
|
|
5
5
|
import { ActiveInstallationWindow, BundleEventFailureInput, CreateBundleEventRequest, CreateBundleEventRequestBase, CursorPage, EventCursorPage, EventHistoryChange, EventHistoryRow, InsightsBundleSelection, InsightsCountMeasurement, InsightsHttpResponse, InstallationHistoryRow, InstallationRow, ReportingOverview } from "./domain.mjs";
|
|
6
|
+
import { InsightsEventPageInput, InsightsInstallationEventPageInput, InsightsProvider, InsightsUserInstallationPageInput } from "./types.mjs";
|
|
7
|
+
import { InsightsAdminReadsOptions, InsightsReads, createInsightsAdminReads, createInsightsReads } from "./adminReads.mjs";
|
|
6
8
|
import { InsightsBadRequestError } from "./errors.mjs";
|
|
7
9
|
import { createInsightsModel } from "./model.mjs";
|
|
8
|
-
import { InsightsEventPageInput, InsightsInstallationEventPageInput, InsightsProvider, InsightsUserInstallationPageInput } from "./types.mjs";
|
|
9
10
|
import { createInsightsProvider } from "./provider.mjs";
|
|
10
11
|
import { InsightsIdentityParts, insightsIdentity } from "./recordEvent.mjs";
|
|
11
12
|
import { HotUpdaterDatabase, PluginEndpoint } from "@hot-updater/plugin-core";
|
|
@@ -422,4 +423,4 @@ declare const insights: (options?: InsightsOptions) => import("@hot-updater/plug
|
|
|
422
423
|
endpoints: PluginEndpoint[];
|
|
423
424
|
}, {}>;
|
|
424
425
|
//#endregion
|
|
425
|
-
export { type ActiveInstallationWindow, type BundleEventFailure, type BundleEventFailureInput, type BundleEventFailureReason, type BundleEventFailureStage, type BundleEventRow, type BundleEventRowBase, type CreateBundleEventRequest, type CreateBundleEventRequestBase, type CursorPage, DEFAULT_INSIGHTS_RETENTION, type DatabaseBundleEventMetadata, type EventCursorPage, type EventHistoryChange, type EventHistoryRow, InsightsApi, InsightsBadRequestError, type InsightsBundleEventFilter, type InsightsBundleSelection, type InsightsCountEventSeriesInput, type InsightsCountEventsInput, type InsightsCountLatestEventsInput, type InsightsCountMeasurement, type InsightsCoverage, type InsightsEventCursor, type InsightsEventFilter, type InsightsEventPageInput, type InsightsEventSeriesPoint, type InsightsFailureBreakdown, type InsightsFindLatestEventsInput, type InsightsGetAppUsageInput, type InsightsGetAppUsageResult, type InsightsGetReleaseActivityInput, type InsightsGetReleaseActivityResult, type InsightsHttpResponse, type InsightsIdentityParts, type InsightsInstallationEventPageInput, type InsightsListEventsInput, type InsightsModel, InsightsOptions, type InsightsProvider, type InsightsRecordEventInput, type InsightsRetention, type InsightsSchema, type InsightsScope, type InsightsTimeRange, type InsightsUpdateFailures, type InsightsUpdateFailuresInput, type InsightsUserInstallationPageInput, type InstallationHistoryRow, type InstallationRow, type ReleaseActivityMetrics, type ReleaseReference, type ReportingOverview, createInsightsModel, createInsightsProvider, createInsightsSchema, insights, insightsIdentity, insightsSchema };
|
|
426
|
+
export { type ActiveInstallationWindow, type BundleEventFailure, type BundleEventFailureInput, type BundleEventFailureReason, type BundleEventFailureStage, type BundleEventRow, type BundleEventRowBase, type CreateBundleEventRequest, type CreateBundleEventRequestBase, type CursorPage, DEFAULT_INSIGHTS_RETENTION, type DatabaseBundleEventMetadata, type EventCursorPage, type EventHistoryChange, type EventHistoryRow, type InsightsAdminReadsOptions, InsightsApi, InsightsBadRequestError, type InsightsBundleEventFilter, type InsightsBundleSelection, type InsightsCountEventSeriesInput, type InsightsCountEventsInput, type InsightsCountLatestEventsInput, type InsightsCountMeasurement, type InsightsCoverage, type InsightsEventCursor, type InsightsEventFilter, type InsightsEventPageInput, type InsightsEventSeriesPoint, type InsightsFailureBreakdown, type InsightsFindLatestEventsInput, type InsightsGetAppUsageInput, type InsightsGetAppUsageResult, type InsightsGetReleaseActivityInput, type InsightsGetReleaseActivityResult, type InsightsHttpResponse, type InsightsIdentityParts, type InsightsInstallationEventPageInput, type InsightsListEventsInput, type InsightsModel, InsightsOptions, type InsightsProvider, type InsightsReads, type InsightsRecordEventInput, type InsightsRetention, type InsightsSchema, type InsightsScope, type InsightsTimeRange, type InsightsUpdateFailures, type InsightsUpdateFailuresInput, type InsightsUserInstallationPageInput, type InstallationHistoryRow, type InstallationRow, type ReleaseActivityMetrics, type ReleaseReference, type ReportingOverview, createInsightsAdminReads, createInsightsModel, createInsightsProvider, createInsightsReads, createInsightsSchema, insights, insightsIdentity, insightsSchema };
|
package/dist/server/index.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { createInsightsProvider } from "./provider.mjs";
|
|
|
6
6
|
import { insightsIdentity, recordEvent } from "./recordEvent.mjs";
|
|
7
7
|
import { countEventSeries, countEvents, countLatestEvents, findLatestEvents, getAppUsage, getReleaseActivity, getUpdateFailures, listEvents } from "./reads.mjs";
|
|
8
8
|
import { INSIGHTS_ROUTES, createInsightsRouteHandlers } from "./routes.mjs";
|
|
9
|
+
import { createInsightsAdminReads, createInsightsReads } from "./adminReads.mjs";
|
|
9
10
|
import { DatabaseAdapterInputError, HotUpdaterConfigError, definePlugin, isDatabaseBusyError } from "@hot-updater/plugin-core";
|
|
10
11
|
//#region src/server/index.ts
|
|
11
12
|
const createInsightsApi = (db, now, retention) => ({
|
|
@@ -119,4 +120,4 @@ const insights = (options = {}) => {
|
|
|
119
120
|
return markOfficial(plugin);
|
|
120
121
|
};
|
|
121
122
|
//#endregion
|
|
122
|
-
export { DEFAULT_INSIGHTS_RETENTION, InsightsBadRequestError, createInsightsModel, createInsightsProvider, createInsightsSchema, insights, insightsIdentity, insightsSchema };
|
|
123
|
+
export { DEFAULT_INSIGHTS_RETENTION, InsightsBadRequestError, createInsightsAdminReads, createInsightsModel, createInsightsProvider, createInsightsReads, createInsightsSchema, insights, insightsIdentity, insightsSchema };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/plugin-insights",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.42",
|
|
5
5
|
"description": "Hot Updater's Insights plugin: launch, download, and update failure events, for the server and the React Native app",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./client": {
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"package.json"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@hot-updater/protocol": "1.0.0-rc.
|
|
36
|
+
"@hot-updater/protocol": "1.0.0-rc.42"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@hot-updater/plugin-core": "^1.0.0-rc.
|
|
39
|
+
"@hot-updater/plugin-core": "^1.0.0-rc.42"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"@hot-updater/plugin-core": {
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/node": "^20",
|
|
48
48
|
"vitest": "4.1.4",
|
|
49
|
-
"@hot-updater/plugin-core": "1.0.0-rc.
|
|
50
|
-
"@hot-updater/test-utils": "1.0.0-rc.
|
|
49
|
+
"@hot-updater/plugin-core": "1.0.0-rc.42",
|
|
50
|
+
"@hot-updater/test-utils": "1.0.0-rc.42"
|
|
51
51
|
},
|
|
52
52
|
"nx": {
|
|
53
53
|
"implicitDependencies": [
|