@agora-sdk/social-core 0.6.0
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/LICENSE +202 -0
- package/dist/cjs/context/social-context.d.ts +65 -0
- package/dist/cjs/context/social-context.js +125 -0
- package/dist/cjs/context/social-context.js.map +1 -0
- package/dist/cjs/contract/index.d.ts +19 -0
- package/dist/cjs/contract/index.js +57 -0
- package/dist/cjs/contract/index.js.map +1 -0
- package/dist/cjs/hooks/useSocialConstellation.d.ts +29 -0
- package/dist/cjs/hooks/useSocialConstellation.js +70 -0
- package/dist/cjs/hooks/useSocialConstellation.js.map +1 -0
- package/dist/cjs/hooks/useSocialNeighborhood.d.ts +29 -0
- package/dist/cjs/hooks/useSocialNeighborhood.js +90 -0
- package/dist/cjs/hooks/useSocialNeighborhood.js.map +1 -0
- package/dist/cjs/hooks/useSocialTransparency.d.ts +25 -0
- package/dist/cjs/hooks/useSocialTransparency.js +28 -0
- package/dist/cjs/hooks/useSocialTransparency.js.map +1 -0
- package/dist/cjs/hooks/useSocialWeather.d.ts +28 -0
- package/dist/cjs/hooks/useSocialWeather.js +72 -0
- package/dist/cjs/hooks/useSocialWeather.js.map +1 -0
- package/dist/cjs/index.d.ts +14 -0
- package/dist/cjs/index.js +33 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/transport/rest.d.ts +105 -0
- package/dist/cjs/transport/rest.js +177 -0
- package/dist/cjs/transport/rest.js.map +1 -0
- package/dist/esm/context/social-context.d.ts +65 -0
- package/dist/esm/context/social-context.js +120 -0
- package/dist/esm/context/social-context.js.map +1 -0
- package/dist/esm/contract/index.d.ts +19 -0
- package/dist/esm/contract/index.js +54 -0
- package/dist/esm/contract/index.js.map +1 -0
- package/dist/esm/hooks/useSocialConstellation.d.ts +29 -0
- package/dist/esm/hooks/useSocialConstellation.js +67 -0
- package/dist/esm/hooks/useSocialConstellation.js.map +1 -0
- package/dist/esm/hooks/useSocialNeighborhood.d.ts +29 -0
- package/dist/esm/hooks/useSocialNeighborhood.js +87 -0
- package/dist/esm/hooks/useSocialNeighborhood.js.map +1 -0
- package/dist/esm/hooks/useSocialTransparency.d.ts +25 -0
- package/dist/esm/hooks/useSocialTransparency.js +25 -0
- package/dist/esm/hooks/useSocialTransparency.js.map +1 -0
- package/dist/esm/hooks/useSocialWeather.d.ts +28 -0
- package/dist/esm/hooks/useSocialWeather.js +69 -0
- package/dist/esm/hooks/useSocialWeather.js.map +1 -0
- package/dist/esm/index.d.ts +14 -0
- package/dist/esm/index.js +17 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/transport/rest.d.ts +105 -0
- package/dist/esm/transport/rest.js +168 -0
- package/dist/esm/transport/rest.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { SocialRestClient } from "../transport/rest.js";
|
|
3
|
+
import { ResolvedSocialConfig } from "../contract/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* The resolved-config sentinel used when the social graph is unavailable (`503
|
|
6
|
+
* social/graph-unavailable`) — every lens and analytics flag disabled, so hooks/components render
|
|
7
|
+
* nothing rather than erroring. Tier is the safe `"community"` default and numeric tuning fields are
|
|
8
|
+
* zeroed; none of these are read while the lenses are disabled.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ALL_DISABLED_SOCIAL_CONFIG: ResolvedSocialConfig;
|
|
11
|
+
/**
|
|
12
|
+
* The value exposed by {@link useSocial}: the shared REST client, the auto-fetched feature config and
|
|
13
|
+
* its load state, and the active project id.
|
|
14
|
+
*/
|
|
15
|
+
export interface SocialContextValue {
|
|
16
|
+
/** REST client for the social endpoints. */
|
|
17
|
+
rest: SocialRestClient;
|
|
18
|
+
/**
|
|
19
|
+
* The project's resolved social config, or `null` until the transparency fetch resolves. When the
|
|
20
|
+
* graph is unavailable this is the {@link ALL_DISABLED_SOCIAL_CONFIG} sentinel (not `null`).
|
|
21
|
+
*/
|
|
22
|
+
config: ResolvedSocialConfig | null;
|
|
23
|
+
/** True while the initial transparency fetch is in flight. */
|
|
24
|
+
configLoading: boolean;
|
|
25
|
+
/** A non-degradation error from the transparency fetch (the `503` graph-off case is not an error). */
|
|
26
|
+
configError: unknown;
|
|
27
|
+
/** The Agora project id these clients are scoped to. */
|
|
28
|
+
projectId: string;
|
|
29
|
+
}
|
|
30
|
+
/** Props for {@link SocialProvider}. */
|
|
31
|
+
export interface SocialProviderProps {
|
|
32
|
+
/** Agora project id (path-scoped on every endpoint — a privacy boundary). */
|
|
33
|
+
projectId: string;
|
|
34
|
+
/** Current access token. Re-pass on refresh; read lazily per request. */
|
|
35
|
+
accessToken?: string;
|
|
36
|
+
/** Override token resolution (takes precedence over `accessToken`). */
|
|
37
|
+
getAccessToken?: () => string | undefined;
|
|
38
|
+
/** Override the API base URL. Defaults to @agora-sdk/core `getApiBaseUrl()`. */
|
|
39
|
+
baseUrl?: string;
|
|
40
|
+
children: React.ReactNode;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Provides the social REST client + the project's resolved feature config to the `useSocial*` hooks
|
|
44
|
+
* and components. Render inside a `ReplykeProvider`. Auto-fetches `GET /social/transparency` once on
|
|
45
|
+
* mount; treats `503 social/graph-unavailable` as "all lenses disabled" rather than an error.
|
|
46
|
+
*
|
|
47
|
+
* @param props - {@link SocialProviderProps}.
|
|
48
|
+
* @returns A context provider wrapping `children`.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* <SocialProvider projectId={projectId} accessToken={token}>
|
|
53
|
+
* <CommunityWeather />
|
|
54
|
+
* <Constellation />
|
|
55
|
+
* </SocialProvider>
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function SocialProvider({ projectId, accessToken, getAccessToken, baseUrl, children, }: SocialProviderProps): React.JSX.Element;
|
|
59
|
+
/**
|
|
60
|
+
* Access the nearest {@link SocialContextValue}.
|
|
61
|
+
*
|
|
62
|
+
* @returns The shared rest client, resolved feature config + load state, and project id.
|
|
63
|
+
* @throws {Error} When called outside a `<SocialProvider>`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function useSocial(): SocialContextValue;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// SocialProvider — wires the social REST transport and auto-resolves the project's feature config.
|
|
3
|
+
//
|
|
4
|
+
// Sits INSIDE a ReplykeProvider: by default it resolves the API base URL from @agora-sdk/core's
|
|
5
|
+
// runtime singleton (getApiBaseUrl). On mount it fetches `GET /social/transparency` once and stores
|
|
6
|
+
// the resolved config so every hook/component can self-gate on the per-project feature flags WITHOUT
|
|
7
|
+
// each issuing its own probe (SOCIAL.md §7 — "check transparency at app init"). There is no crypto and
|
|
8
|
+
// no persistence here: social data is public/server-side and slow-moving, so the provider holds
|
|
9
|
+
// fetched config in React state only.
|
|
10
|
+
//
|
|
11
|
+
// Graceful degradation: a `503 social/graph-unavailable` is treated as "the whole graph is off" — we
|
|
12
|
+
// store an ALL-DISABLED sentinel rather than an error, so surfaces hide silently instead of throwing
|
|
13
|
+
// at members. Any other failure is surfaced via `configError` for the host app to decide on.
|
|
14
|
+
import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
15
|
+
import { getApiBaseUrl } from "@agora-sdk/core";
|
|
16
|
+
import { SocialRestClient } from "../transport/rest.js";
|
|
17
|
+
import { SocialApiError } from "../transport/rest.js";
|
|
18
|
+
/**
|
|
19
|
+
* The resolved-config sentinel used when the social graph is unavailable (`503
|
|
20
|
+
* social/graph-unavailable`) — every lens and analytics flag disabled, so hooks/components render
|
|
21
|
+
* nothing rather than erroring. Tier is the safe `"community"` default and numeric tuning fields are
|
|
22
|
+
* zeroed; none of these are read while the lenses are disabled.
|
|
23
|
+
*/
|
|
24
|
+
export const ALL_DISABLED_SOCIAL_CONFIG = {
|
|
25
|
+
privacyTier: "community",
|
|
26
|
+
graphEnabled: false,
|
|
27
|
+
weatherEnabled: false,
|
|
28
|
+
constellationEnabled: false,
|
|
29
|
+
constellationKFloor: 0,
|
|
30
|
+
neighborhoodEnabled: false,
|
|
31
|
+
neighborhoodIncludeInteractions: false,
|
|
32
|
+
influenceScoresEnabled: false,
|
|
33
|
+
siloDetectionEnabled: false,
|
|
34
|
+
engagementScoresEnabled: false,
|
|
35
|
+
frictionVisibleToStewards: false,
|
|
36
|
+
frictionAnalyticsEnabled: false,
|
|
37
|
+
readAffinityEnabled: false,
|
|
38
|
+
readReceiptsAllowed: false,
|
|
39
|
+
warmthHalfLifeDays: 0,
|
|
40
|
+
frictionHalfLifeDays: 0,
|
|
41
|
+
};
|
|
42
|
+
const SocialContext = createContext(null);
|
|
43
|
+
/**
|
|
44
|
+
* Provides the social REST client + the project's resolved feature config to the `useSocial*` hooks
|
|
45
|
+
* and components. Render inside a `ReplykeProvider`. Auto-fetches `GET /social/transparency` once on
|
|
46
|
+
* mount; treats `503 social/graph-unavailable` as "all lenses disabled" rather than an error.
|
|
47
|
+
*
|
|
48
|
+
* @param props - {@link SocialProviderProps}.
|
|
49
|
+
* @returns A context provider wrapping `children`.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* <SocialProvider projectId={projectId} accessToken={token}>
|
|
54
|
+
* <CommunityWeather />
|
|
55
|
+
* <Constellation />
|
|
56
|
+
* </SocialProvider>
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function SocialProvider({ projectId, accessToken, getAccessToken, baseUrl, children, }) {
|
|
60
|
+
const tokenRef = useRef(accessToken);
|
|
61
|
+
tokenRef.current = accessToken;
|
|
62
|
+
const resolveToken = useMemo(() => getAccessToken ?? (() => tokenRef.current), [getAccessToken]);
|
|
63
|
+
const rest = useMemo(() => new SocialRestClient({
|
|
64
|
+
projectId,
|
|
65
|
+
getAccessToken: resolveToken,
|
|
66
|
+
getBaseUrl: () => baseUrl ?? getApiBaseUrl(),
|
|
67
|
+
}), [projectId, resolveToken, baseUrl]);
|
|
68
|
+
const [config, setConfig] = useState(null);
|
|
69
|
+
const [configLoading, setConfigLoading] = useState(true);
|
|
70
|
+
const [configError, setConfigError] = useState(null);
|
|
71
|
+
// Auto-resolve the per-project feature config once on mount (and whenever the client identity
|
|
72
|
+
// changes). A `503 social/graph-unavailable` is degradation, not an error: store the all-disabled
|
|
73
|
+
// sentinel so every surface hides silently (SOCIAL.md §7). A stale-guard prevents a slow first fetch
|
|
74
|
+
// from clobbering a newer one after a projectId/token swap.
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
let active = true;
|
|
77
|
+
setConfigLoading(true);
|
|
78
|
+
setConfigError(null);
|
|
79
|
+
rest
|
|
80
|
+
.getTransparency()
|
|
81
|
+
.then((resolved) => {
|
|
82
|
+
if (!active)
|
|
83
|
+
return;
|
|
84
|
+
setConfig(resolved);
|
|
85
|
+
})
|
|
86
|
+
.catch((err) => {
|
|
87
|
+
if (!active)
|
|
88
|
+
return;
|
|
89
|
+
if (err instanceof SocialApiError && err.code === "social/graph-unavailable") {
|
|
90
|
+
setConfig(ALL_DISABLED_SOCIAL_CONFIG);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
setConfigError(err);
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
.finally(() => {
|
|
97
|
+
if (active)
|
|
98
|
+
setConfigLoading(false);
|
|
99
|
+
});
|
|
100
|
+
return () => {
|
|
101
|
+
active = false;
|
|
102
|
+
};
|
|
103
|
+
}, [rest]);
|
|
104
|
+
const value = useMemo(() => ({ rest, config, configLoading, configError, projectId }), [rest, config, configLoading, configError, projectId]);
|
|
105
|
+
return _jsx(SocialContext.Provider, { value: value, children: children });
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Access the nearest {@link SocialContextValue}.
|
|
109
|
+
*
|
|
110
|
+
* @returns The shared rest client, resolved feature config + load state, and project id.
|
|
111
|
+
* @throws {Error} When called outside a `<SocialProvider>`.
|
|
112
|
+
*/
|
|
113
|
+
export function useSocial() {
|
|
114
|
+
const ctx = useContext(SocialContext);
|
|
115
|
+
if (!ctx) {
|
|
116
|
+
throw new Error("useSocial must be used within a <SocialProvider>.");
|
|
117
|
+
}
|
|
118
|
+
return ctx;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=social-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social-context.js","sourceRoot":"","sources":["../../../src/context/social-context.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type { SocialWeather, WeatherBand, SocialConstellation, ConstellationBlob, BlobSizeBucket, SocialNeighborhood, NeighborhoodTie, NeighborhoodTieKind, ResolvedSocialConfig, SocialPrivacyTier, } from "@agora-server/contract";
|
|
2
|
+
import type { WeatherBand, BlobSizeBucket, NeighborhoodTieKind } from "@agora-server/contract";
|
|
3
|
+
/**
|
|
4
|
+
* Runtime list of {@link WeatherBand} values, low → high (for iteration / validation). Mirrors the
|
|
5
|
+
* contract's `WEATHER_BANDS`; re-declared locally so core's CJS build need not `require()` the
|
|
6
|
+
* ESM-only contract. Typed against the contract union, so any drift is a compile error.
|
|
7
|
+
*/
|
|
8
|
+
export declare const WEATHER_BANDS: readonly WeatherBand[];
|
|
9
|
+
/**
|
|
10
|
+
* Runtime list of {@link BlobSizeBucket} values, small → large (for iteration / validation). Mirrors
|
|
11
|
+
* the contract's `BLOB_SIZE_BUCKETS` (en-dash strings); re-declared locally for the CJS-build reason
|
|
12
|
+
* above.
|
|
13
|
+
*/
|
|
14
|
+
export declare const BLOB_SIZE_BUCKETS: readonly BlobSizeBucket[];
|
|
15
|
+
/**
|
|
16
|
+
* Runtime list of {@link NeighborhoodTieKind} values (for iteration / validation). Mirrors the
|
|
17
|
+
* contract's `NEIGHBORHOOD_TIE_KINDS`; re-declared locally for the CJS-build reason above.
|
|
18
|
+
*/
|
|
19
|
+
export declare const NEIGHBORHOOD_TIE_KINDS: readonly NeighborhoodTieKind[];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Social-graph wire types — re-exported from the published `@agora-server/contract` (Apache-2.0).
|
|
2
|
+
//
|
|
3
|
+
// The dependency arrow is **SDK → contract**: agora-server owns the social wire contract, this SDK
|
|
4
|
+
// depends on it. As of `@agora-server/contract@0.12.1` the social surface is published, so this module
|
|
5
|
+
// is a thin **type-only re-export** (one source of truth, zero drift) — it replaces the earlier local
|
|
6
|
+
// byte-faithful stand-in that stood in until the contract shipped these types.
|
|
7
|
+
//
|
|
8
|
+
// Type-only on purpose: `@agora-server/contract` is ESM-only, but `export type` re-exports are erased
|
|
9
|
+
// from the emitted JS, so core's dual ESM/CJS build never `require()`s it at runtime (mirrors
|
|
10
|
+
// `secure-chat-core/src/contract`). For the SAME reason the three runtime const arrays are re-declared
|
|
11
|
+
// **locally** rather than value-re-exported — a value re-export would force the CJS build to
|
|
12
|
+
// `require()` the ESM-only contract. They are typed against the contract's unions, so any drift in the
|
|
13
|
+
// bands/buckets/tie-kinds becomes a compile error here.
|
|
14
|
+
//
|
|
15
|
+
// Scope: only the three member-facing lenses (Weather, Constellation, Neighborhood) + the resolved
|
|
16
|
+
// config the SDK consumes. The contract's corporate-analytics surface (influence / silos / engagement,
|
|
17
|
+
// read-receipts) is intentionally NOT re-exported — it is outside this package's scope.
|
|
18
|
+
//
|
|
19
|
+
// Wire conventions (owned by the contract): timestamps are ISO 8601 strings; `value`/`trend`/
|
|
20
|
+
// `brightness` are JSON numbers; size buckets are en-dash strings ("5–9", U+2013).
|
|
21
|
+
/**
|
|
22
|
+
* Runtime list of {@link WeatherBand} values, low → high (for iteration / validation). Mirrors the
|
|
23
|
+
* contract's `WEATHER_BANDS`; re-declared locally so core's CJS build need not `require()` the
|
|
24
|
+
* ESM-only contract. Typed against the contract union, so any drift is a compile error.
|
|
25
|
+
*/
|
|
26
|
+
export const WEATHER_BANDS = [
|
|
27
|
+
"quiet",
|
|
28
|
+
"stormy",
|
|
29
|
+
"overcast",
|
|
30
|
+
"fine",
|
|
31
|
+
"sunny",
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* Runtime list of {@link BlobSizeBucket} values, small → large (for iteration / validation). Mirrors
|
|
35
|
+
* the contract's `BLOB_SIZE_BUCKETS` (en-dash strings); re-declared locally for the CJS-build reason
|
|
36
|
+
* above.
|
|
37
|
+
*/
|
|
38
|
+
export const BLOB_SIZE_BUCKETS = [
|
|
39
|
+
"5–9",
|
|
40
|
+
"10–19",
|
|
41
|
+
"20–49",
|
|
42
|
+
"50–99",
|
|
43
|
+
"100+",
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Runtime list of {@link NeighborhoodTieKind} values (for iteration / validation). Mirrors the
|
|
47
|
+
* contract's `NEIGHBORHOOD_TIE_KINDS`; re-declared locally for the CJS-build reason above.
|
|
48
|
+
*/
|
|
49
|
+
export const NEIGHBORHOOD_TIE_KINDS = [
|
|
50
|
+
"follow",
|
|
51
|
+
"connection",
|
|
52
|
+
"interaction",
|
|
53
|
+
];
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/contract/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,EAAE;AACF,mGAAmG;AACnG,uGAAuG;AACvG,sGAAsG;AACtG,+EAA+E;AAC/E,EAAE;AACF,sGAAsG;AACtG,8FAA8F;AAC9F,uGAAuG;AACvG,6FAA6F;AAC7F,uGAAuG;AACvG,wDAAwD;AACxD,EAAE;AACF,mGAAmG;AACnG,uGAAuG;AACvG,wFAAwF;AACxF,EAAE;AACF,8FAA8F;AAC9F,mFAAmF;AAiBnF;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,OAAO;IACP,QAAQ;IACR,UAAU;IACV,MAAM;IACN,OAAO;CACR,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA8B;IAC1D,KAAK;IACL,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;CACP,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAmC;IACpE,QAAQ;IACR,YAAY;IACZ,aAAa;CACd,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SocialConstellation } from "../contract/index.js";
|
|
2
|
+
/** The state and actions returned by {@link useSocialConstellation}. */
|
|
3
|
+
export interface UseSocialConstellationValues {
|
|
4
|
+
/** The current snapshot, or `null` while loading, when disabled, or on error. `asOf: null` = still forming. */
|
|
5
|
+
constellation: SocialConstellation | null;
|
|
6
|
+
/** True while a fetch is in flight (always `false` when the lens is disabled). */
|
|
7
|
+
loading: boolean;
|
|
8
|
+
/** The last error thrown by the fetch, or `null`. */
|
|
9
|
+
error: unknown;
|
|
10
|
+
/** Re-fetch the snapshot. No-op when the lens is disabled. */
|
|
11
|
+
refresh: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Load the Constellation snapshot (anonymous cluster blobs) for the current project.
|
|
15
|
+
*
|
|
16
|
+
* Waits for the provider's transparency config, then fetches `GET /social/constellation` only when
|
|
17
|
+
* `constellationEnabled` is true. A snapshot with `asOf === null` is the valid "still forming" state,
|
|
18
|
+
* not an error — render a nebula.
|
|
19
|
+
*
|
|
20
|
+
* @returns {@link UseSocialConstellationValues} — the snapshot, load state, and a `refresh` action.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* const { constellation } = useSocialConstellation();
|
|
25
|
+
* if (!constellation) return null; // disabled or loading
|
|
26
|
+
* if (constellation.asOf === null) return <Nebula />; // still forming
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function useSocialConstellation(): UseSocialConstellationValues;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// useSocialConstellation — load the anonymous Constellation snapshot, gated on the feature config.
|
|
2
|
+
//
|
|
3
|
+
// Self-gates on `config.constellationEnabled`. The Constellation is a slow seasonal snapshot
|
|
4
|
+
// (materialized ~every 6 weeks), so one fetch on enable is plenty; `refresh()` is exposed only for
|
|
5
|
+
// completeness. The returned `blobs` carry no stable identity — re-randomizing their LAYOUT on every
|
|
6
|
+
// render is the rendering layer's job (SOCIAL.md §6), not this hook's.
|
|
7
|
+
import { useCallback, useEffect, useState } from "react";
|
|
8
|
+
import { isSocialDegradation } from "../transport/rest.js";
|
|
9
|
+
import { useSocial } from "../context/social-context.js";
|
|
10
|
+
/**
|
|
11
|
+
* Load the Constellation snapshot (anonymous cluster blobs) for the current project.
|
|
12
|
+
*
|
|
13
|
+
* Waits for the provider's transparency config, then fetches `GET /social/constellation` only when
|
|
14
|
+
* `constellationEnabled` is true. A snapshot with `asOf === null` is the valid "still forming" state,
|
|
15
|
+
* not an error — render a nebula.
|
|
16
|
+
*
|
|
17
|
+
* @returns {@link UseSocialConstellationValues} — the snapshot, load state, and a `refresh` action.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const { constellation } = useSocialConstellation();
|
|
22
|
+
* if (!constellation) return null; // disabled or loading
|
|
23
|
+
* if (constellation.asOf === null) return <Nebula />; // still forming
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function useSocialConstellation() {
|
|
27
|
+
const { rest, config, configLoading } = useSocial();
|
|
28
|
+
const enabled = config?.constellationEnabled ?? false;
|
|
29
|
+
const [constellation, setConstellation] = useState(null);
|
|
30
|
+
const [loading, setLoading] = useState(false);
|
|
31
|
+
const [error, setError] = useState(null);
|
|
32
|
+
const refresh = useCallback(async () => {
|
|
33
|
+
if (!enabled)
|
|
34
|
+
return;
|
|
35
|
+
setLoading(true);
|
|
36
|
+
setError(null);
|
|
37
|
+
try {
|
|
38
|
+
setConstellation(await rest.getConstellation());
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
// Fail soft on degradation (graph off, or the lens disabled mid-session): hide the surface —
|
|
42
|
+
// clear the snapshot and swallow the error rather than surface it to members (SOCIAL.md §7). Real
|
|
43
|
+
// errors still propagate via `error`.
|
|
44
|
+
if (isSocialDegradation(err)) {
|
|
45
|
+
setConstellation(null);
|
|
46
|
+
setError(null);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
setError(err);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
setLoading(false);
|
|
54
|
+
}
|
|
55
|
+
}, [enabled, rest]);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (configLoading)
|
|
58
|
+
return;
|
|
59
|
+
if (!enabled) {
|
|
60
|
+
setConstellation(null);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
void refresh();
|
|
64
|
+
}, [configLoading, enabled, refresh]);
|
|
65
|
+
return { constellation, loading, error, refresh };
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=useSocialConstellation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSocialConstellation.js","sourceRoot":"","sources":["../../../src/hooks/useSocialConstellation.tsx"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,EAAE;AACF,6FAA6F;AAC7F,mGAAmG;AACnG,qGAAqG;AACrG,uEAAuE;AAEvE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAczD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,EAAE,oBAAoB,IAAI,KAAK,CAAC;IAEtD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAA6B,IAAI,CAAC,CAAC;IACrF,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAU,IAAI,CAAC,CAAC;IAElD,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACrC,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,IAAI,CAAC;YACH,gBAAgB,CAAC,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,6FAA6F;YAC7F,kGAAkG;YAClG,sCAAsC;YACtC,IAAI,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7B,gBAAgB,CAAC,IAAI,CAAC,CAAC;gBACvB,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAEpB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,aAAa;YAAE,OAAO;QAC1B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QACD,KAAK,OAAO,EAAE,CAAC;IACjB,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAEtC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SocialNeighborhood } from "../contract/index.js";
|
|
2
|
+
/** The state and actions returned by {@link useSocialNeighborhood}. */
|
|
3
|
+
export interface UseSocialNeighborhoodValues {
|
|
4
|
+
/** The caller's ties (brightest-first), or `null` while loading, when disabled, or on error. */
|
|
5
|
+
neighborhood: SocialNeighborhood | null;
|
|
6
|
+
/** True while a fetch is in flight (always `false` when the lens is disabled). */
|
|
7
|
+
loading: boolean;
|
|
8
|
+
/** The last error thrown by the fetch, or `null`. */
|
|
9
|
+
error: unknown;
|
|
10
|
+
/** The effective `includeInteractions` value currently in effect. */
|
|
11
|
+
includeInteractions: boolean;
|
|
12
|
+
/** Flip whether interaction-only ties are included; triggers a re-fetch. */
|
|
13
|
+
setIncludeInteractions: (value: boolean) => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Load the caller's Neighborhood — their own named ties with dyadic brightness. Self-view only.
|
|
17
|
+
*
|
|
18
|
+
* Waits for the provider's transparency config, seeds the `includeInteractions` toggle from the
|
|
19
|
+
* project default, then fetches `GET /social/neighborhood` only when `neighborhoodEnabled` is true.
|
|
20
|
+
* Flipping the toggle re-fetches; the hook syncs to the server's echoed effective value.
|
|
21
|
+
*
|
|
22
|
+
* @returns {@link UseSocialNeighborhoodValues} — the ties, load state, and the interactions toggle.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* const { neighborhood, includeInteractions, setIncludeInteractions } = useSocialNeighborhood();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function useSocialNeighborhood(): UseSocialNeighborhoodValues;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// useSocialNeighborhood — load the caller's own named ties (self-view), gated on the feature config.
|
|
2
|
+
//
|
|
3
|
+
// Self-gates on `config.neighborhoodEnabled`. Owns the `includeInteractions` toggle: it seeds from the
|
|
4
|
+
// project default (`config.neighborhoodIncludeInteractions`) once config resolves, then re-fetches
|
|
5
|
+
// whenever the caller flips it. The server always echoes the EFFECTIVE value, so we sync local state to
|
|
6
|
+
// the response (`includesInteractions`) rather than trusting the request optimistically.
|
|
7
|
+
//
|
|
8
|
+
// Privacy (SOCIAL.md §6): the Neighborhood is self-view only and must not persist across sign-outs or
|
|
9
|
+
// user switches. This hook keeps ties in component state only (no cache) and clears them when the lens
|
|
10
|
+
// disables or the provider's client identity changes — so a project/token swap cannot leak a prior
|
|
11
|
+
// user's ties.
|
|
12
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
13
|
+
import { isSocialDegradation } from "../transport/rest.js";
|
|
14
|
+
import { useSocial } from "../context/social-context.js";
|
|
15
|
+
/**
|
|
16
|
+
* Load the caller's Neighborhood — their own named ties with dyadic brightness. Self-view only.
|
|
17
|
+
*
|
|
18
|
+
* Waits for the provider's transparency config, seeds the `includeInteractions` toggle from the
|
|
19
|
+
* project default, then fetches `GET /social/neighborhood` only when `neighborhoodEnabled` is true.
|
|
20
|
+
* Flipping the toggle re-fetches; the hook syncs to the server's echoed effective value.
|
|
21
|
+
*
|
|
22
|
+
* @returns {@link UseSocialNeighborhoodValues} — the ties, load state, and the interactions toggle.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* const { neighborhood, includeInteractions, setIncludeInteractions } = useSocialNeighborhood();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function useSocialNeighborhood() {
|
|
30
|
+
const { rest, config, configLoading } = useSocial();
|
|
31
|
+
const enabled = config?.neighborhoodEnabled ?? false;
|
|
32
|
+
const projectDefault = config?.neighborhoodIncludeInteractions ?? false;
|
|
33
|
+
const [neighborhood, setNeighborhood] = useState(null);
|
|
34
|
+
const [loading, setLoading] = useState(false);
|
|
35
|
+
const [error, setError] = useState(null);
|
|
36
|
+
const [includeInteractions, setIncludeInteractions] = useState(false);
|
|
37
|
+
// Seed the toggle from the project default exactly once, when config first resolves. After that the
|
|
38
|
+
// caller owns it. A ref guards against re-seeding (which would clobber a user's choice on re-render).
|
|
39
|
+
const seeded = useRef(false);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (configLoading || seeded.current)
|
|
42
|
+
return;
|
|
43
|
+
setIncludeInteractions(projectDefault);
|
|
44
|
+
seeded.current = true;
|
|
45
|
+
}, [configLoading, projectDefault]);
|
|
46
|
+
const fetchFor = useCallback(async (include) => {
|
|
47
|
+
if (!enabled)
|
|
48
|
+
return;
|
|
49
|
+
setLoading(true);
|
|
50
|
+
setError(null);
|
|
51
|
+
try {
|
|
52
|
+
const result = await rest.getNeighborhood({ includeInteractions: include });
|
|
53
|
+
setNeighborhood(result);
|
|
54
|
+
// Sync to the server's effective value (it may override the request, e.g. project policy).
|
|
55
|
+
setIncludeInteractions(result.includesInteractions);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
// Fail soft on degradation (graph off, or the lens disabled mid-session): hide the surface —
|
|
59
|
+
// clear ties and swallow the error rather than surface it to members (SOCIAL.md §7). Real
|
|
60
|
+
// errors still propagate via `error`.
|
|
61
|
+
if (isSocialDegradation(err)) {
|
|
62
|
+
setNeighborhood(null);
|
|
63
|
+
setError(null);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
setError(err);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
setLoading(false);
|
|
71
|
+
}
|
|
72
|
+
}, [enabled, rest]);
|
|
73
|
+
// Fetch on enable and whenever the toggle changes. Clear ties when disabled or before re-fetch under
|
|
74
|
+
// a new identity — the self-view must never linger across a user switch (SOCIAL.md §6).
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (configLoading || !seeded.current)
|
|
77
|
+
return;
|
|
78
|
+
if (!enabled) {
|
|
79
|
+
setNeighborhood(null);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
void fetchFor(includeInteractions);
|
|
83
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
84
|
+
}, [configLoading, enabled, includeInteractions, fetchFor]);
|
|
85
|
+
return { neighborhood, loading, error, includeInteractions, setIncludeInteractions };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=useSocialNeighborhood.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSocialNeighborhood.js","sourceRoot":"","sources":["../../../src/hooks/useSocialNeighborhood.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ResolvedSocialConfig } from "../contract/index.js";
|
|
2
|
+
/** The state returned by {@link useSocialTransparency}. */
|
|
3
|
+
export interface UseSocialTransparencyValues {
|
|
4
|
+
/** The resolved config, or `null` until the provider's transparency fetch resolves. */
|
|
5
|
+
config: ResolvedSocialConfig | null;
|
|
6
|
+
/** True while the provider's initial transparency fetch is in flight. */
|
|
7
|
+
loading: boolean;
|
|
8
|
+
/** A non-degradation error from the transparency fetch, or `null`. */
|
|
9
|
+
error: unknown;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Read the project's resolved social config (which lenses are enabled, decay half-lives, k-floor).
|
|
13
|
+
*
|
|
14
|
+
* Reads straight from the provider — no extra request. Returns `config: null` until the provider's
|
|
15
|
+
* mount-time transparency fetch resolves.
|
|
16
|
+
*
|
|
17
|
+
* @returns {@link UseSocialTransparencyValues} — the resolved config and its load state.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const { config } = useSocialTransparency();
|
|
22
|
+
* if (config?.weatherEnabled) renderWeatherNavEntry();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function useSocialTransparency(): UseSocialTransparencyValues;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// useSocialTransparency — read the project's resolved social config from the provider.
|
|
2
|
+
//
|
|
3
|
+
// The provider already fetches `GET /social/transparency` once on mount, so this hook issues no
|
|
4
|
+
// request of its own — it just surfaces the cached config + load state. Use it to render a how-it-works
|
|
5
|
+
// panel (which lenses are on, decay half-lives, k-floor) or to drive nav-entry visibility.
|
|
6
|
+
import { useSocial } from "../context/social-context.js";
|
|
7
|
+
/**
|
|
8
|
+
* Read the project's resolved social config (which lenses are enabled, decay half-lives, k-floor).
|
|
9
|
+
*
|
|
10
|
+
* Reads straight from the provider — no extra request. Returns `config: null` until the provider's
|
|
11
|
+
* mount-time transparency fetch resolves.
|
|
12
|
+
*
|
|
13
|
+
* @returns {@link UseSocialTransparencyValues} — the resolved config and its load state.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const { config } = useSocialTransparency();
|
|
18
|
+
* if (config?.weatherEnabled) renderWeatherNavEntry();
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function useSocialTransparency() {
|
|
22
|
+
const { config, configLoading, configError } = useSocial();
|
|
23
|
+
return { config, loading: configLoading, error: configError };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=useSocialTransparency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSocialTransparency.js","sourceRoot":"","sources":["../../../src/hooks/useSocialTransparency.tsx"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,EAAE;AACF,gGAAgG;AAChG,wGAAwG;AACxG,2FAA2F;AAG3F,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAYzD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,SAAS,EAAE,CAAC;IAC3D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SocialWeather } from "../contract/index.js";
|
|
2
|
+
/** The state and actions returned by {@link useSocialWeather}. */
|
|
3
|
+
export interface UseSocialWeatherValues {
|
|
4
|
+
/** The current Weather reading, or `null` while loading, when disabled, or on error. */
|
|
5
|
+
weather: SocialWeather | null;
|
|
6
|
+
/** True while a fetch is in flight (always `false` when the lens is disabled). */
|
|
7
|
+
loading: boolean;
|
|
8
|
+
/** The last error thrown by the fetch, or `null`. */
|
|
9
|
+
error: unknown;
|
|
10
|
+
/** Re-fetch the Weather reading. No-op when the lens is disabled. */
|
|
11
|
+
refresh: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Load the Community Weather scalar for the current project.
|
|
15
|
+
*
|
|
16
|
+
* Waits for the provider's transparency config, then fetches `GET /social/weather` only when
|
|
17
|
+
* `weatherEnabled` is true. When the lens is disabled it returns `{ weather: null, loading: false }`
|
|
18
|
+
* and issues no request.
|
|
19
|
+
*
|
|
20
|
+
* @returns {@link UseSocialWeatherValues} — the reading, load state, and a `refresh` action.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* const { weather, loading } = useSocialWeather();
|
|
25
|
+
* if (!weather) return null; // disabled or still loading
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function useSocialWeather(): UseSocialWeatherValues;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// useSocialWeather — load the Community Weather scalar, gated on the project's feature config.
|
|
2
|
+
//
|
|
3
|
+
// Self-gates on `config.weatherEnabled` from the provider: when the lens is disabled (or the graph is
|
|
4
|
+
// unavailable) the hook returns `weather: null` and never issues a request, so a host app can render
|
|
5
|
+
// `<CommunityWeather />` unconditionally and have it disappear when off (SOCIAL.md §7). Weather is a
|
|
6
|
+
// ~1h server-cached aggregate, so a single fetch on enable is enough; `refresh()` is exposed for
|
|
7
|
+
// manual refetch (e.g. pull-to-refresh).
|
|
8
|
+
import { useCallback, useEffect, useState } from "react";
|
|
9
|
+
import { isSocialDegradation } from "../transport/rest.js";
|
|
10
|
+
import { useSocial } from "../context/social-context.js";
|
|
11
|
+
/**
|
|
12
|
+
* Load the Community Weather scalar for the current project.
|
|
13
|
+
*
|
|
14
|
+
* Waits for the provider's transparency config, then fetches `GET /social/weather` only when
|
|
15
|
+
* `weatherEnabled` is true. When the lens is disabled it returns `{ weather: null, loading: false }`
|
|
16
|
+
* and issues no request.
|
|
17
|
+
*
|
|
18
|
+
* @returns {@link UseSocialWeatherValues} — the reading, load state, and a `refresh` action.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* const { weather, loading } = useSocialWeather();
|
|
23
|
+
* if (!weather) return null; // disabled or still loading
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function useSocialWeather() {
|
|
27
|
+
const { rest, config, configLoading } = useSocial();
|
|
28
|
+
const enabled = config?.weatherEnabled ?? false;
|
|
29
|
+
const [weather, setWeather] = useState(null);
|
|
30
|
+
const [loading, setLoading] = useState(false);
|
|
31
|
+
const [error, setError] = useState(null);
|
|
32
|
+
const refresh = useCallback(async () => {
|
|
33
|
+
if (!enabled)
|
|
34
|
+
return;
|
|
35
|
+
setLoading(true);
|
|
36
|
+
setError(null);
|
|
37
|
+
try {
|
|
38
|
+
setWeather(await rest.getWeather());
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
// Fail soft on degradation (graph off, or the lens disabled mid-session): hide the surface —
|
|
42
|
+
// clear the reading and swallow the error rather than surface it to members (SOCIAL.md §7). Real
|
|
43
|
+
// errors still propagate via `error`.
|
|
44
|
+
if (isSocialDegradation(err)) {
|
|
45
|
+
setWeather(null);
|
|
46
|
+
setError(null);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
setError(err);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
setLoading(false);
|
|
54
|
+
}
|
|
55
|
+
}, [enabled, rest]);
|
|
56
|
+
// Fetch once the config has resolved and the lens is enabled. When disabled, clear any stale reading
|
|
57
|
+
// so a config flip to off (or a project switch) doesn't leave the previous community's weather on screen.
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (configLoading)
|
|
60
|
+
return;
|
|
61
|
+
if (!enabled) {
|
|
62
|
+
setWeather(null);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
void refresh();
|
|
66
|
+
}, [configLoading, enabled, refresh]);
|
|
67
|
+
return { weather, loading, error, refresh };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=useSocialWeather.js.map
|