@mohasinac/appkit 3.2.10 → 3.2.11
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/_internal/server/features/auth/firebase-identity.d.ts +2 -1
- package/dist/_internal/server/jobs/core/cleanupRtdbEvents.js +4 -1
- package/dist/_internal/shared/listing-types/action-tracker.js +2 -1
- package/dist/features/blog/api/[slug]/route.js +2 -1
- package/dist/features/homepage/lib/live-stats.js +7 -5
- package/dist/features/scams/actions/scam-actions.js +2 -1
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JsonObject } from "../../../../schemas/types";
|
|
1
2
|
type IdentityOperation = "signInWithPassword" | "signInWithCustomToken";
|
|
2
3
|
/**
|
|
3
4
|
* Calls the Firebase Identity Toolkit REST API with one retry for transient
|
|
@@ -8,5 +9,5 @@ type IdentityOperation = "signInWithPassword" | "signInWithCustomToken";
|
|
|
8
9
|
* into a session cookie. Centralised here so the URL, Content-Type, and retry
|
|
9
10
|
* config are in one place.
|
|
10
11
|
*/
|
|
11
|
-
export declare function callFirebaseIdentityToolkit<T extends
|
|
12
|
+
export declare function callFirebaseIdentityToolkit<T extends JsonObject>(operation: IdentityOperation, body: JsonObject, apiKey: string): Promise<T>;
|
|
12
13
|
export {};
|
|
@@ -17,7 +17,10 @@ export async function runCleanupRtdbEvents(ctx) {
|
|
|
17
17
|
if (staleAuthIds.length > 0) {
|
|
18
18
|
await Promise.all(staleAuthIds.flatMap((id) => [
|
|
19
19
|
rtdb.ref(`auth_events/${id}`).remove(),
|
|
20
|
-
auth.deleteUser(`auth_event_${id}`).catch(
|
|
20
|
+
auth.deleteUser(`auth_event_${id}`).catch((err) => {
|
|
21
|
+
void normalizeError(err);
|
|
22
|
+
ctx.logger.warn("cleanupRtdbEvents: deleteUser skipped — may already be absent", { userId: `auth_event_${id}`, error: err instanceof Error ? err.message : String(err) });
|
|
23
|
+
}),
|
|
21
24
|
]));
|
|
22
25
|
ctx.logger.info("Auth events removed", { count: staleAuthIds.length });
|
|
23
26
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeError } from "../../../errors/normalize";
|
|
1
2
|
function defaultSink(event) {
|
|
2
3
|
if (typeof window === "undefined") {
|
|
3
4
|
// SSR / Node — best-effort console log; production servers can swap
|
|
@@ -32,7 +33,7 @@ export const actionTracker = {
|
|
|
32
33
|
const result = currentSink(event);
|
|
33
34
|
// Swallow promise rejections so the caller path is never affected.
|
|
34
35
|
if (result && typeof result.catch === "function") {
|
|
35
|
-
result.catch(
|
|
36
|
+
result.catch((err) => { void normalizeError(err); });
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
catch {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { NextResponse } from "next/server.js";
|
|
12
12
|
import { blogRepository } from "../../repository/blog.repository";
|
|
13
13
|
import { normalizeError } from "../../../../errors/normalize";
|
|
14
|
+
import { safeFireAndForget } from "../../../../utils/safe-fire-forget";
|
|
14
15
|
function toBlogPost(doc) {
|
|
15
16
|
return {
|
|
16
17
|
...doc,
|
|
@@ -28,7 +29,7 @@ export async function GET(_request, context) {
|
|
|
28
29
|
return NextResponse.json({ success: false, error: "Blog post not found" }, { status: 404 });
|
|
29
30
|
}
|
|
30
31
|
// Increment view count fire-and-forget — must not block response
|
|
31
|
-
blogRepository.incrementViews(post.id)
|
|
32
|
+
safeFireAndForget(blogRepository.incrementViews(post.id), "blog: incrementViews");
|
|
32
33
|
// Related posts: same category, latest 3, excluding current
|
|
33
34
|
const related = (await blogRepository.findRelated(post.category, post.id, 3)).map(toBlogPost);
|
|
34
35
|
const body = { post: toBlogPost(post), related };
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import { ALLOWED_LIVE_COLLECTIONS } from "../schemas/firestore";
|
|
9
9
|
import { productRepository, storeRepository, userRepository, reviewRepository, orderRepository, } from "../../../repositories";
|
|
10
10
|
import { getAdminDb, getFirestoreCount } from "../../../providers/db-firebase";
|
|
11
|
+
import { normalizeError } from "../../../errors/normalize";
|
|
12
|
+
import { serverLogger } from "../../../monitoring/server-logger";
|
|
11
13
|
/**
|
|
12
14
|
* Fetch live stats for all requested metrics.
|
|
13
15
|
* Preset metrics are deduped so each Firestore query runs at most once.
|
|
@@ -27,22 +29,22 @@ export async function fetchLiveStats(requests) {
|
|
|
27
29
|
if (neededPresets.has("total_listings")) {
|
|
28
30
|
tasks.push(productRepository.count()
|
|
29
31
|
.then((n) => { resolvedPresets.total_listings = String(n); })
|
|
30
|
-
.catch(
|
|
32
|
+
.catch((err) => { void normalizeError(err); serverLogger.warn("live-stats: total_listings query failed — stat omitted", { error: err instanceof Error ? err.message : String(err) }); }));
|
|
31
33
|
}
|
|
32
34
|
if (neededPresets.has("verified_sellers")) {
|
|
33
35
|
tasks.push(storeRepository.count()
|
|
34
36
|
.then((n) => { resolvedPresets.verified_sellers = String(n); })
|
|
35
|
-
.catch(
|
|
37
|
+
.catch((err) => { void normalizeError(err); serverLogger.warn("live-stats: verified_sellers query failed — stat omitted", { error: err instanceof Error ? err.message : String(err) }); }));
|
|
36
38
|
}
|
|
37
39
|
if (neededPresets.has("total_buyers")) {
|
|
38
40
|
tasks.push(userRepository.countByRole("user")
|
|
39
41
|
.then((n) => { resolvedPresets.total_buyers = String(n); })
|
|
40
|
-
.catch(
|
|
42
|
+
.catch((err) => { void normalizeError(err); serverLogger.warn("live-stats: total_buyers query failed — stat omitted", { error: err instanceof Error ? err.message : String(err) }); }));
|
|
41
43
|
}
|
|
42
44
|
if (neededPresets.has("total_orders")) {
|
|
43
45
|
tasks.push(orderRepository.count()
|
|
44
46
|
.then((n) => { resolvedPresets.total_orders = String(n); })
|
|
45
|
-
.catch(
|
|
47
|
+
.catch((err) => { void normalizeError(err); serverLogger.warn("live-stats: total_orders query failed — stat omitted", { error: err instanceof Error ? err.message : String(err) }); }));
|
|
46
48
|
}
|
|
47
49
|
if (neededPresets.has("total_reviews") || neededPresets.has("platform_rating")) {
|
|
48
50
|
tasks.push(reviewRepository.findAll()
|
|
@@ -57,7 +59,7 @@ export async function fetchLiveStats(requests) {
|
|
|
57
59
|
resolvedPresets.platform_rating = avg.toFixed(1) + "★";
|
|
58
60
|
}
|
|
59
61
|
})
|
|
60
|
-
.catch(
|
|
62
|
+
.catch((err) => { void normalizeError(err); serverLogger.warn("live-stats: reviews/rating query failed — stat omitted", { error: err instanceof Error ? err.message : String(err) }); }));
|
|
61
63
|
}
|
|
62
64
|
// --- Collection-query metrics ------------------------------------------------
|
|
63
65
|
const queryRequests = requests.filter((r) => r.source === "live-collection" && r.collectionQuery !== undefined);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit";
|
|
3
3
|
import { scammerRepository } from "../repository/scammer.repository";
|
|
4
|
+
import { safeFireAndForget } from "../../../utils/safe-fire-forget";
|
|
4
5
|
/**
|
|
5
6
|
* List verified scammer profiles for the public registry page.
|
|
6
7
|
* Accepts sieve-style searchParams from Next.js page props.
|
|
@@ -43,7 +44,7 @@ export async function getPublicScammerById(id) {
|
|
|
43
44
|
if (!doc || doc.status !== "verified")
|
|
44
45
|
return null;
|
|
45
46
|
// Increment views — non-blocking.
|
|
46
|
-
scammerRepository.incrementViews(doc.id)
|
|
47
|
+
safeFireAndForget(scammerRepository.incrementViews(doc.id), "scam: incrementViews");
|
|
47
48
|
return doc;
|
|
48
49
|
}
|
|
49
50
|
/**
|