@singi-labs/sifa-sdk 0.19.109 → 0.19.110

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/index.cjs CHANGED
@@ -7928,7 +7928,7 @@ function describeSifaRecord(collection, value) {
7928
7928
  }
7929
7929
 
7930
7930
  // src/index.ts
7931
- var SIFA_SDK_VERSION = "0.19.109";
7931
+ var SIFA_SDK_VERSION = "0.19.110";
7932
7932
 
7933
7933
  exports.ACTIVITY_TIERS = ACTIVITY_TIERS;
7934
7934
  exports.ACTIVITY_VERBS = ACTIVITY_VERBS;
package/dist/index.js CHANGED
@@ -393,7 +393,7 @@ import {
393
393
  roadmapIssueUrl
394
394
  } from "./roadmap/index.js";
395
395
  import { SIFA_REPO_GROUPS, describeSifaRecord, repoGroupForCollection } from "./repo/index.js";
396
- var SIFA_SDK_VERSION = "0.19.109";
396
+ var SIFA_SDK_VERSION = "0.19.110";
397
397
  export {
398
398
  ACTIVITY_TIERS,
399
399
  ACTIVITY_VERBS,
@@ -40,11 +40,16 @@ type GermMessageLink = {
40
40
  interface FetchGermMessageLinkOptions extends ApiFetchOptions {
41
41
  /** Raw `Cookie` header for RSC calls, so the API sees the viewer's session. */
42
42
  cookieHeader?: string;
43
+ /**
44
+ * The visitor's User-Agent, for RSC calls. The API uses it for the platform
45
+ * hint, the iPhone/iPad-only mode and bot-free show counts.
46
+ */
47
+ viewerUserAgent?: string;
43
48
  }
44
49
  /**
45
50
  * Germ DM state for a profile (see {@link GermMessageLink}). Pass the viewer's
46
- * `cookieHeader` from server components; without it the result is the
47
- * logged-out view and may be cached. Returns `null` on any error.
51
+ * `cookieHeader` and `viewerUserAgent` from server components; without a
52
+ * cookie the result is the logged-out view. Returns `null` on any error.
48
53
  */
49
54
  declare function fetchGermMessageLink(config: SifaApiConfig, did: string, options?: FetchGermMessageLinkOptions): Promise<GermMessageLink | null>;
50
55
  /**
@@ -40,11 +40,16 @@ type GermMessageLink = {
40
40
  interface FetchGermMessageLinkOptions extends ApiFetchOptions {
41
41
  /** Raw `Cookie` header for RSC calls, so the API sees the viewer's session. */
42
42
  cookieHeader?: string;
43
+ /**
44
+ * The visitor's User-Agent, for RSC calls. The API uses it for the platform
45
+ * hint, the iPhone/iPad-only mode and bot-free show counts.
46
+ */
47
+ viewerUserAgent?: string;
43
48
  }
44
49
  /**
45
50
  * Germ DM state for a profile (see {@link GermMessageLink}). Pass the viewer's
46
- * `cookieHeader` from server components; without it the result is the
47
- * logged-out view and may be cached. Returns `null` on any error.
51
+ * `cookieHeader` and `viewerUserAgent` from server components; without a
52
+ * cookie the result is the logged-out view. Returns `null` on any error.
48
53
  */
49
54
  declare function fetchGermMessageLink(config: SifaApiConfig, did: string, options?: FetchGermMessageLinkOptions): Promise<GermMessageLink | null>;
50
55
  /**
@@ -4,7 +4,6 @@ import {
4
4
  } from "../../schemas/germ-declaration.js";
5
5
  import { apiFetch, encodeIdentifier } from "../client.js";
6
6
  var GERM_LINK_TIMEOUT_MS = 1500;
7
- var LOGGED_OUT_REVALIDATE_S = 900;
8
7
  function isShowButtonTo(value) {
9
8
  return GERM_SHOW_BUTTON_TO_VALUES.includes(value);
10
9
  }
@@ -21,10 +20,11 @@ function parseGermMessageLink(data) {
21
20
  return null;
22
21
  }
23
22
  async function fetchGermMessageLink(config, did, options = {}) {
24
- const { cookieHeader, ...rest } = options;
23
+ const { cookieHeader, viewerUserAgent, ...rest } = options;
25
24
  const headers = { ...rest.headers ?? {} };
26
25
  if (cookieHeader) headers.cookie = cookieHeader;
27
- const caching = cookieHeader ? { cache: "no-store", next: void 0 } : { next: { revalidate: LOGGED_OUT_REVALIDATE_S } };
26
+ if (viewerUserAgent) headers["x-viewer-user-agent"] = viewerUserAgent;
27
+ const caching = { cache: "no-store", next: void 0 };
28
28
  try {
29
29
  const data = await apiFetch(
30
30
  config,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/query/fetchers/germ.ts"],"sourcesContent":["import {\n GERM_SHOW_BUTTON_TO_VALUES,\n type GermShowButtonTo,\n} from '../../schemas/germ-declaration.js';\nimport { apiFetch, encodeIdentifier, type ApiFetchOptions, type SifaApiConfig } from '../client.js';\n\n/**\n * Germ DM state of a profile, as seen by the current viewer.\n *\n * - `eligible`: render the \"Message on Germ\" button. Its `href` is\n * {@link germRedirectPath}, which counts the click and forwards to Germ.\n * - `owner`: the viewer looks at their own profile. `showButtonTo` is the\n * owner's Germ setting, for a status note; `null` when the record has no\n * `messageMe` or the value is not one Sifa knows.\n *\n * `null` means no button and no note.\n */\nexport type GermMessageLink =\n { status: 'eligible' } | { status: 'owner'; showButtonTo: GermShowButtonTo | null };\n\nexport interface FetchGermMessageLinkOptions extends ApiFetchOptions {\n /** Raw `Cookie` header for RSC calls, so the API sees the viewer's session. */\n cookieHeader?: string;\n}\n\n// Below the profile page's patience: a slow lookup drops the button, not the page.\nconst GERM_LINK_TIMEOUT_MS = 1500;\n// Logged-out results depend only on the owner, so they can be shared.\nconst LOGGED_OUT_REVALIDATE_S = 900;\n\nfunction isShowButtonTo(value: unknown): value is GermShowButtonTo {\n return (GERM_SHOW_BUTTON_TO_VALUES as readonly unknown[]).includes(value);\n}\n\nfunction parseGermMessageLink(data: unknown): GermMessageLink | null {\n if (typeof data !== 'object' || data === null) return null;\n const { status, showButtonTo } = data as { status?: unknown; showButtonTo?: unknown };\n if (status === 'eligible') return { status: 'eligible' };\n if (status === 'owner') {\n if (showButtonTo === undefined || showButtonTo === null) {\n return { status: 'owner', showButtonTo: null };\n }\n if (isShowButtonTo(showButtonTo)) return { status: 'owner', showButtonTo };\n }\n return null;\n}\n\n/**\n * Germ DM state for a profile (see {@link GermMessageLink}). Pass the viewer's\n * `cookieHeader` from server components; without it the result is the\n * logged-out view and may be cached. Returns `null` on any error.\n */\nexport async function fetchGermMessageLink(\n config: SifaApiConfig,\n did: string,\n options: FetchGermMessageLinkOptions = {},\n): Promise<GermMessageLink | null> {\n const { cookieHeader, ...rest } = options;\n const headers: Record<string, string> = { ...(rest.headers ?? {}) };\n if (cookieHeader) headers.cookie = cookieHeader;\n // Applied last: a viewer-specific answer must never land in a shared cache.\n const caching: ApiFetchOptions = cookieHeader\n ? { cache: 'no-store', next: undefined }\n : { next: { revalidate: LOGGED_OUT_REVALIDATE_S } };\n try {\n const data = await apiFetch<unknown>(\n config,\n `/api/profiles/${encodeIdentifier(did)}/germ-message-link`,\n { timeoutMs: GERM_LINK_TIMEOUT_MS, credentials: 'include', ...rest, ...caching, headers },\n );\n return parseGermMessageLink(data);\n } catch {\n return null;\n }\n}\n\n/**\n * Path of the click route the button links to. The route re-checks the\n * viewer, counts the click and redirects to Germ, so clicks are counted\n * without client-side JavaScript. Prefix it with the API origin.\n */\nexport function germRedirectPath(did: string): string {\n return `/api/profiles/${encodeIdentifier(did)}/germ-redirect`;\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,OAEK;AACP,SAAS,UAAU,wBAAkE;AAsBrF,IAAM,uBAAuB;AAE7B,IAAM,0BAA0B;AAEhC,SAAS,eAAe,OAA2C;AACjE,SAAQ,2BAAkD,SAAS,KAAK;AAC1E;AAEA,SAAS,qBAAqB,MAAuC;AACnE,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,QAAM,EAAE,QAAQ,aAAa,IAAI;AACjC,MAAI,WAAW,WAAY,QAAO,EAAE,QAAQ,WAAW;AACvD,MAAI,WAAW,SAAS;AACtB,QAAI,iBAAiB,UAAa,iBAAiB,MAAM;AACvD,aAAO,EAAE,QAAQ,SAAS,cAAc,KAAK;AAAA,IAC/C;AACA,QAAI,eAAe,YAAY,EAAG,QAAO,EAAE,QAAQ,SAAS,aAAa;AAAA,EAC3E;AACA,SAAO;AACT;AAOA,eAAsB,qBACpB,QACA,KACA,UAAuC,CAAC,GACP;AACjC,QAAM,EAAE,cAAc,GAAG,KAAK,IAAI;AAClC,QAAM,UAAkC,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG;AAClE,MAAI,aAAc,SAAQ,SAAS;AAEnC,QAAM,UAA2B,eAC7B,EAAE,OAAO,YAAY,MAAM,OAAU,IACrC,EAAE,MAAM,EAAE,YAAY,wBAAwB,EAAE;AACpD,MAAI;AACF,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA,iBAAiB,iBAAiB,GAAG,CAAC;AAAA,MACtC,EAAE,WAAW,sBAAsB,aAAa,WAAW,GAAG,MAAM,GAAG,SAAS,QAAQ;AAAA,IAC1F;AACA,WAAO,qBAAqB,IAAI;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,iBAAiB,KAAqB;AACpD,SAAO,iBAAiB,iBAAiB,GAAG,CAAC;AAC/C;","names":[]}
1
+ {"version":3,"sources":["../../../src/query/fetchers/germ.ts"],"sourcesContent":["import {\n GERM_SHOW_BUTTON_TO_VALUES,\n type GermShowButtonTo,\n} from '../../schemas/germ-declaration.js';\nimport { apiFetch, encodeIdentifier, type ApiFetchOptions, type SifaApiConfig } from '../client.js';\n\n/**\n * Germ DM state of a profile, as seen by the current viewer.\n *\n * - `eligible`: render the \"Message on Germ\" button. Its `href` is\n * {@link germRedirectPath}, which counts the click and forwards to Germ.\n * - `owner`: the viewer looks at their own profile. `showButtonTo` is the\n * owner's Germ setting, for a status note; `null` when the record has no\n * `messageMe` or the value is not one Sifa knows.\n *\n * `null` means no button and no note.\n */\nexport type GermMessageLink =\n { status: 'eligible' } | { status: 'owner'; showButtonTo: GermShowButtonTo | null };\n\nexport interface FetchGermMessageLinkOptions extends ApiFetchOptions {\n /** Raw `Cookie` header for RSC calls, so the API sees the viewer's session. */\n cookieHeader?: string;\n /**\n * The visitor's User-Agent, for RSC calls. The API uses it for the platform\n * hint, the iPhone/iPad-only mode and bot-free show counts.\n */\n viewerUserAgent?: string;\n}\n\n// Below the profile page's patience: a slow lookup drops the button, not the page.\nconst GERM_LINK_TIMEOUT_MS = 1500;\n\nfunction isShowButtonTo(value: unknown): value is GermShowButtonTo {\n return (GERM_SHOW_BUTTON_TO_VALUES as readonly unknown[]).includes(value);\n}\n\nfunction parseGermMessageLink(data: unknown): GermMessageLink | null {\n if (typeof data !== 'object' || data === null) return null;\n const { status, showButtonTo } = data as { status?: unknown; showButtonTo?: unknown };\n if (status === 'eligible') return { status: 'eligible' };\n if (status === 'owner') {\n if (showButtonTo === undefined || showButtonTo === null) {\n return { status: 'owner', showButtonTo: null };\n }\n if (isShowButtonTo(showButtonTo)) return { status: 'owner', showButtonTo };\n }\n return null;\n}\n\n/**\n * Germ DM state for a profile (see {@link GermMessageLink}). Pass the viewer's\n * `cookieHeader` and `viewerUserAgent` from server components; without a\n * cookie the result is the logged-out view. Returns `null` on any error.\n */\nexport async function fetchGermMessageLink(\n config: SifaApiConfig,\n did: string,\n options: FetchGermMessageLinkOptions = {},\n): Promise<GermMessageLink | null> {\n const { cookieHeader, viewerUserAgent, ...rest } = options;\n const headers: Record<string, string> = { ...(rest.headers ?? {}) };\n if (cookieHeader) headers.cookie = cookieHeader;\n if (viewerUserAgent) headers['x-viewer-user-agent'] = viewerUserAgent;\n // Applied last, never cached: the answer depends on the viewer and device,\n // and each call counts as a shown button. The API caches the lookups.\n const caching: ApiFetchOptions = { cache: 'no-store', next: undefined };\n try {\n const data = await apiFetch<unknown>(\n config,\n `/api/profiles/${encodeIdentifier(did)}/germ-message-link`,\n { timeoutMs: GERM_LINK_TIMEOUT_MS, credentials: 'include', ...rest, ...caching, headers },\n );\n return parseGermMessageLink(data);\n } catch {\n return null;\n }\n}\n\n/**\n * Path of the click route the button links to. The route re-checks the\n * viewer, counts the click and redirects to Germ, so clicks are counted\n * without client-side JavaScript. Prefix it with the API origin.\n */\nexport function germRedirectPath(did: string): string {\n return `/api/profiles/${encodeIdentifier(did)}/germ-redirect`;\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,OAEK;AACP,SAAS,UAAU,wBAAkE;AA2BrF,IAAM,uBAAuB;AAE7B,SAAS,eAAe,OAA2C;AACjE,SAAQ,2BAAkD,SAAS,KAAK;AAC1E;AAEA,SAAS,qBAAqB,MAAuC;AACnE,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,QAAM,EAAE,QAAQ,aAAa,IAAI;AACjC,MAAI,WAAW,WAAY,QAAO,EAAE,QAAQ,WAAW;AACvD,MAAI,WAAW,SAAS;AACtB,QAAI,iBAAiB,UAAa,iBAAiB,MAAM;AACvD,aAAO,EAAE,QAAQ,SAAS,cAAc,KAAK;AAAA,IAC/C;AACA,QAAI,eAAe,YAAY,EAAG,QAAO,EAAE,QAAQ,SAAS,aAAa;AAAA,EAC3E;AACA,SAAO;AACT;AAOA,eAAsB,qBACpB,QACA,KACA,UAAuC,CAAC,GACP;AACjC,QAAM,EAAE,cAAc,iBAAiB,GAAG,KAAK,IAAI;AACnD,QAAM,UAAkC,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG;AAClE,MAAI,aAAc,SAAQ,SAAS;AACnC,MAAI,gBAAiB,SAAQ,qBAAqB,IAAI;AAGtD,QAAM,UAA2B,EAAE,OAAO,YAAY,MAAM,OAAU;AACtE,MAAI;AACF,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA,iBAAiB,iBAAiB,GAAG,CAAC;AAAA,MACtC,EAAE,WAAW,sBAAsB,aAAa,WAAW,GAAG,MAAM,GAAG,SAAS,QAAQ;AAAA,IAC1F;AACA,WAAO,qBAAqB,IAAI;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,iBAAiB,KAAqB;AACpD,SAAO,iBAAiB,iBAAiB,GAAG,CAAC;AAC/C;","names":[]}
@@ -167,7 +167,6 @@ zod.z.object({
167
167
 
168
168
  // src/query/fetchers/germ.ts
169
169
  var GERM_LINK_TIMEOUT_MS = 1500;
170
- var LOGGED_OUT_REVALIDATE_S = 900;
171
170
  function isShowButtonTo(value) {
172
171
  return GERM_SHOW_BUTTON_TO_VALUES.includes(value);
173
172
  }
@@ -184,10 +183,11 @@ function parseGermMessageLink(data) {
184
183
  return null;
185
184
  }
186
185
  async function fetchGermMessageLink(config, did, options = {}) {
187
- const { cookieHeader, ...rest } = options;
186
+ const { cookieHeader, viewerUserAgent, ...rest } = options;
188
187
  const headers = { ...rest.headers ?? {} };
189
188
  if (cookieHeader) headers.cookie = cookieHeader;
190
- const caching = cookieHeader ? { cache: "no-store", next: void 0 } : { next: { revalidate: LOGGED_OUT_REVALIDATE_S } };
189
+ if (viewerUserAgent) headers["x-viewer-user-agent"] = viewerUserAgent;
190
+ const caching = { cache: "no-store", next: void 0 };
191
191
  try {
192
192
  const data = await apiFetch(
193
193
  config,