@singi-labs/sifa-sdk 0.9.12 → 0.9.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +40 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +39 -2
- package/dist/index.js.map +1 -1
- package/dist/publishing/index.cjs +155 -0
- package/dist/publishing/index.cjs.map +1 -0
- package/dist/publishing/index.d.cts +253 -0
- package/dist/publishing/index.d.ts +253 -0
- package/dist/publishing/index.js +138 -0
- package/dist/publishing/index.js.map +1 -0
- package/dist/query/index.d.cts +20 -20
- package/dist/query/index.d.ts +20 -20
- package/package.json +13 -3
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zod schemas mirroring the canonical Standard.site lexicons that Sifa
|
|
5
|
+
* consumes when rendering publication embeds.
|
|
6
|
+
*
|
|
7
|
+
* Canonical lexicons live at:
|
|
8
|
+
* DID: did:plc:re3ebnp5v7ffagz6rb6xfei4
|
|
9
|
+
* PDS: https://auriporia.us-west.host.bsky.network
|
|
10
|
+
* Collection: com.atproto.lexicon.schema
|
|
11
|
+
*
|
|
12
|
+
* Sifa does NOT own these lexicons; we vendor the validation shapes so
|
|
13
|
+
* clients can parse augmented embeds and (in Phase 4) write subscription
|
|
14
|
+
* records to viewers' PDSes. Re-check against the canonical PDS on each
|
|
15
|
+
* SDK release to detect schema drift.
|
|
16
|
+
*/
|
|
17
|
+
declare const rgbColorSchema: z.ZodObject<{
|
|
18
|
+
r: z.ZodNumber;
|
|
19
|
+
g: z.ZodNumber;
|
|
20
|
+
b: z.ZodNumber;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
type RgbColor = z.infer<typeof rgbColorSchema>;
|
|
23
|
+
/** site.standard.theme.basic */
|
|
24
|
+
declare const BasicThemeSchema: z.ZodObject<{
|
|
25
|
+
background: z.ZodObject<{
|
|
26
|
+
r: z.ZodNumber;
|
|
27
|
+
g: z.ZodNumber;
|
|
28
|
+
b: z.ZodNumber;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
foreground: z.ZodObject<{
|
|
31
|
+
r: z.ZodNumber;
|
|
32
|
+
g: z.ZodNumber;
|
|
33
|
+
b: z.ZodNumber;
|
|
34
|
+
}, z.core.$strip>;
|
|
35
|
+
accent: z.ZodObject<{
|
|
36
|
+
r: z.ZodNumber;
|
|
37
|
+
g: z.ZodNumber;
|
|
38
|
+
b: z.ZodNumber;
|
|
39
|
+
}, z.core.$strip>;
|
|
40
|
+
accentForeground: z.ZodObject<{
|
|
41
|
+
r: z.ZodNumber;
|
|
42
|
+
g: z.ZodNumber;
|
|
43
|
+
b: z.ZodNumber;
|
|
44
|
+
}, z.core.$strip>;
|
|
45
|
+
}, z.core.$strip>;
|
|
46
|
+
type BasicTheme = z.infer<typeof BasicThemeSchema>;
|
|
47
|
+
/** site.standard.publication */
|
|
48
|
+
declare const StandardSitePublicationRecordSchema: z.ZodObject<{
|
|
49
|
+
url: z.ZodString;
|
|
50
|
+
name: z.ZodString;
|
|
51
|
+
description: z.ZodOptional<z.ZodString>;
|
|
52
|
+
icon: z.ZodOptional<z.ZodObject<{
|
|
53
|
+
$type: z.ZodOptional<z.ZodString>;
|
|
54
|
+
ref: z.ZodUnknown;
|
|
55
|
+
mimeType: z.ZodOptional<z.ZodString>;
|
|
56
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
}, z.core.$loose>>;
|
|
58
|
+
basicTheme: z.ZodOptional<z.ZodObject<{
|
|
59
|
+
background: z.ZodObject<{
|
|
60
|
+
r: z.ZodNumber;
|
|
61
|
+
g: z.ZodNumber;
|
|
62
|
+
b: z.ZodNumber;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
foreground: z.ZodObject<{
|
|
65
|
+
r: z.ZodNumber;
|
|
66
|
+
g: z.ZodNumber;
|
|
67
|
+
b: z.ZodNumber;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
accent: z.ZodObject<{
|
|
70
|
+
r: z.ZodNumber;
|
|
71
|
+
g: z.ZodNumber;
|
|
72
|
+
b: z.ZodNumber;
|
|
73
|
+
}, z.core.$strip>;
|
|
74
|
+
accentForeground: z.ZodObject<{
|
|
75
|
+
r: z.ZodNumber;
|
|
76
|
+
g: z.ZodNumber;
|
|
77
|
+
b: z.ZodNumber;
|
|
78
|
+
}, z.core.$strip>;
|
|
79
|
+
}, z.core.$strip>>;
|
|
80
|
+
labels: z.ZodOptional<z.ZodObject<{
|
|
81
|
+
$type: z.ZodOptional<z.ZodLiteral<"com.atproto.label.defs#selfLabels">>;
|
|
82
|
+
values: z.ZodArray<z.ZodObject<{
|
|
83
|
+
val: z.ZodString;
|
|
84
|
+
}, z.core.$strip>>;
|
|
85
|
+
}, z.core.$strip>>;
|
|
86
|
+
preferences: z.ZodOptional<z.ZodObject<{
|
|
87
|
+
showInDiscover: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
88
|
+
}, z.core.$strip>>;
|
|
89
|
+
}, z.core.$loose>;
|
|
90
|
+
type StandardSitePublicationRecord = z.infer<typeof StandardSitePublicationRecordSchema>;
|
|
91
|
+
/** site.standard.document */
|
|
92
|
+
declare const StandardSiteDocumentRecordSchema: z.ZodObject<{
|
|
93
|
+
site: z.ZodString;
|
|
94
|
+
title: z.ZodString;
|
|
95
|
+
path: z.ZodOptional<z.ZodString>;
|
|
96
|
+
publishedAt: z.ZodString;
|
|
97
|
+
updatedAt: z.ZodOptional<z.ZodString>;
|
|
98
|
+
description: z.ZodOptional<z.ZodString>;
|
|
99
|
+
textContent: z.ZodOptional<z.ZodString>;
|
|
100
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
101
|
+
coverImage: z.ZodOptional<z.ZodObject<{
|
|
102
|
+
$type: z.ZodOptional<z.ZodString>;
|
|
103
|
+
ref: z.ZodUnknown;
|
|
104
|
+
mimeType: z.ZodOptional<z.ZodString>;
|
|
105
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
106
|
+
}, z.core.$loose>>;
|
|
107
|
+
contributors: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
108
|
+
did: z.ZodString;
|
|
109
|
+
role: z.ZodOptional<z.ZodString>;
|
|
110
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
111
|
+
}, z.core.$loose>>>;
|
|
112
|
+
bskyPostRef: z.ZodOptional<z.ZodObject<{
|
|
113
|
+
uri: z.ZodString;
|
|
114
|
+
cid: z.ZodString;
|
|
115
|
+
}, z.core.$strip>>;
|
|
116
|
+
labels: z.ZodOptional<z.ZodObject<{
|
|
117
|
+
$type: z.ZodOptional<z.ZodLiteral<"com.atproto.label.defs#selfLabels">>;
|
|
118
|
+
values: z.ZodArray<z.ZodObject<{
|
|
119
|
+
val: z.ZodString;
|
|
120
|
+
}, z.core.$strip>>;
|
|
121
|
+
}, z.core.$strip>>;
|
|
122
|
+
}, z.core.$loose>;
|
|
123
|
+
type StandardSiteDocumentRecord = z.infer<typeof StandardSiteDocumentRecordSchema>;
|
|
124
|
+
/**
|
|
125
|
+
* site.standard.graph.subscription
|
|
126
|
+
*
|
|
127
|
+
* Authored by a viewer to declare a subscription to a publication. Used
|
|
128
|
+
* by Phase 4 inline-subscribe path. Record key is a TID; the AT-URI
|
|
129
|
+
* shape is `at://<viewer-did>/site.standard.graph.subscription/<rkey>`.
|
|
130
|
+
*/
|
|
131
|
+
declare const StandardSiteSubscriptionRecordSchema: z.ZodObject<{
|
|
132
|
+
publication: z.ZodString;
|
|
133
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
134
|
+
}, z.core.$strip>;
|
|
135
|
+
type StandardSiteSubscriptionRecord = z.infer<typeof StandardSiteSubscriptionRecordSchema>;
|
|
136
|
+
/**
|
|
137
|
+
* site.standard.graph.recommend
|
|
138
|
+
*
|
|
139
|
+
* Document-level "like" record. Same scope as subscription via the
|
|
140
|
+
* site.standard.authSocial OAuth permission-set, so Phase 4 unlocks
|
|
141
|
+
* inline likes alongside inline subscribes.
|
|
142
|
+
*/
|
|
143
|
+
declare const StandardSiteRecommendRecordSchema: z.ZodObject<{
|
|
144
|
+
document: z.ZodString;
|
|
145
|
+
createdAt: z.ZodString;
|
|
146
|
+
}, z.core.$strip>;
|
|
147
|
+
type StandardSiteRecommendRecord = z.infer<typeof StandardSiteRecommendRecordSchema>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Publisher allowlist for the Standard.site rich embed.
|
|
151
|
+
*
|
|
152
|
+
* Mirrors `bluesky-social/social-app`
|
|
153
|
+
* `src/components/Post/Embed/StandardSiteEmbed/publishers.ts`. The only
|
|
154
|
+
* gate this provides is which publishers get the highlighted
|
|
155
|
+
* "Subscribe on {Publisher}" CTA with a publisher icon vs the plain
|
|
156
|
+
* "View publication" fallback — any Standard.site embed renders
|
|
157
|
+
* regardless of allowlist membership.
|
|
158
|
+
*
|
|
159
|
+
* Sync policy: review additions against the upstream bsky list weekly;
|
|
160
|
+
* Singi Labs reviews before merge.
|
|
161
|
+
*/
|
|
162
|
+
interface Publisher {
|
|
163
|
+
/** Lowercase host. Subdomains are matched via `hostMatches`. */
|
|
164
|
+
host: string;
|
|
165
|
+
/** Human-facing publisher name shown in CTA copy. */
|
|
166
|
+
name: string;
|
|
167
|
+
/**
|
|
168
|
+
* Stable identifier used by clients to look up brand icons. The SDK
|
|
169
|
+
* does not ship icon assets — sifa-web maintains them keyed by this
|
|
170
|
+
* id so React Native vs web rendering can diverge.
|
|
171
|
+
*/
|
|
172
|
+
iconKey: 'leaflet' | 'pckt' | 'offprint';
|
|
173
|
+
}
|
|
174
|
+
declare const STANDARD_SITE_PUBLISHERS: readonly Publisher[];
|
|
175
|
+
/**
|
|
176
|
+
* Returns true when `host` exactly matches `target` or is a subdomain of
|
|
177
|
+
* it. Hosts are expected to be lowercase already.
|
|
178
|
+
*/
|
|
179
|
+
declare function hostMatches(host: string, target: string): boolean;
|
|
180
|
+
/**
|
|
181
|
+
* Match a publisher by host. Returns the publisher when `host` is on the
|
|
182
|
+
* allowlist (exact or subdomain match), null otherwise. Host should be
|
|
183
|
+
* lowercase.
|
|
184
|
+
*/
|
|
185
|
+
declare function matchPublisherByHost(host: string | null | undefined): Publisher | null;
|
|
186
|
+
/**
|
|
187
|
+
* Match a publisher by URI. Convenience wrapper around
|
|
188
|
+
* `matchPublisherByHost` for callers that have a publication URL handy.
|
|
189
|
+
*/
|
|
190
|
+
declare function matchPublisherByUri(uri: string | undefined | null): Publisher | null;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Publication metadata embedded in the augmented activity view by
|
|
194
|
+
* sifa-api when an external link card matches an indexed publication.
|
|
195
|
+
*
|
|
196
|
+
* `uri` is the publication's AT-URI (e.g.
|
|
197
|
+
* `at://did:plc:abc/site.standard.publication/xyz`). `theme` carries
|
|
198
|
+
* the publication's own colors when supplied — clients should apply a
|
|
199
|
+
* WCAG min-contrast fallback before honoring them.
|
|
200
|
+
*
|
|
201
|
+
* `icon` is left as `unknown` here because its representation depends
|
|
202
|
+
* on the surface: blob ref on the wire, CDN URL after resolution.
|
|
203
|
+
*/
|
|
204
|
+
interface PublicationSource {
|
|
205
|
+
uri: string;
|
|
206
|
+
title: string;
|
|
207
|
+
icon?: unknown;
|
|
208
|
+
theme?: BasicTheme;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Shape attached to activity items whose external link card URL matches
|
|
212
|
+
* a Standard.site record. Mirrors the relevant fields of bsky's
|
|
213
|
+
* `StandardSiteEmbed` view so a sifa-web renderer can be near-1:1.
|
|
214
|
+
*
|
|
215
|
+
* `associatedRefs` carries AT-URIs the client may use in Phase 4 to
|
|
216
|
+
* query subscription state for the viewer.
|
|
217
|
+
*/
|
|
218
|
+
interface StandardSiteEmbedView {
|
|
219
|
+
uri: string;
|
|
220
|
+
source: PublicationSource;
|
|
221
|
+
associatedRefs: {
|
|
222
|
+
uri: string;
|
|
223
|
+
}[];
|
|
224
|
+
createdAt?: string;
|
|
225
|
+
readingTime?: number;
|
|
226
|
+
}
|
|
227
|
+
declare const STANDARD_SITE_PUBLICATION_NSID: "site.standard.publication";
|
|
228
|
+
declare const STANDARD_SITE_DOCUMENT_NSID: "site.standard.document";
|
|
229
|
+
declare const STANDARD_SITE_SUBSCRIPTION_NSID: "site.standard.graph.subscription";
|
|
230
|
+
declare const STANDARD_SITE_RECOMMEND_NSID: "site.standard.graph.recommend";
|
|
231
|
+
/**
|
|
232
|
+
* Pre-defined OAuth permission-set the consumer apps request to write
|
|
233
|
+
* subscription + recommend records on behalf of the viewer. The actual
|
|
234
|
+
* permission-set is published under
|
|
235
|
+
* `at://did:plc:re3ebnp5v7ffagz6rb6xfei4/com.atproto.lexicon.schema/site.standard.authSocial`.
|
|
236
|
+
*/
|
|
237
|
+
declare const STANDARD_SITE_AUTH_SOCIAL_NSID: "site.standard.authSocial";
|
|
238
|
+
/**
|
|
239
|
+
* True when the AT-URI's collection segment is a Standard.site
|
|
240
|
+
* collection. Useful for detecting Standard.site embed augmentation on
|
|
241
|
+
* arbitrary activity items.
|
|
242
|
+
*/
|
|
243
|
+
declare function isStandardSiteAtUri(uri: string): boolean;
|
|
244
|
+
/**
|
|
245
|
+
* True when any `associatedRefs[].uri` is a Standard.site collection
|
|
246
|
+
* AT-URI. The bsky client uses the same check to gate the
|
|
247
|
+
* `StandardSiteEmbed` renderer.
|
|
248
|
+
*/
|
|
249
|
+
declare function hasStandardSiteAssociatedRef(refs: {
|
|
250
|
+
uri: string;
|
|
251
|
+
}[] | undefined): boolean;
|
|
252
|
+
|
|
253
|
+
export { type BasicTheme, BasicThemeSchema, type PublicationSource, type Publisher, type RgbColor, STANDARD_SITE_AUTH_SOCIAL_NSID, STANDARD_SITE_DOCUMENT_NSID, STANDARD_SITE_PUBLICATION_NSID, STANDARD_SITE_PUBLISHERS, STANDARD_SITE_RECOMMEND_NSID, STANDARD_SITE_SUBSCRIPTION_NSID, type StandardSiteDocumentRecord, StandardSiteDocumentRecordSchema, type StandardSiteEmbedView, type StandardSitePublicationRecord, StandardSitePublicationRecordSchema, type StandardSiteRecommendRecord, StandardSiteRecommendRecordSchema, type StandardSiteSubscriptionRecord, StandardSiteSubscriptionRecordSchema, hasStandardSiteAssociatedRef, hostMatches, isStandardSiteAtUri, matchPublisherByHost, matchPublisherByUri };
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// src/publishing/schemas.ts
|
|
4
|
+
function maxGraphemes(max) {
|
|
5
|
+
return (value) => {
|
|
6
|
+
const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
7
|
+
let count = 0;
|
|
8
|
+
for (const _ of segmenter.segment(value)) {
|
|
9
|
+
count++;
|
|
10
|
+
if (count > max) return false;
|
|
11
|
+
}
|
|
12
|
+
return true;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
var didSchema = z.string().regex(/^did:[a-z]+:[a-zA-Z0-9._:%-]+$/, "Invalid DID");
|
|
16
|
+
var datetimeSchema = z.string().datetime({ offset: true });
|
|
17
|
+
var atUriSchema = z.string().regex(/^at:\/\/[^\s]+$/, "Invalid AT-URI");
|
|
18
|
+
var cidSchema = z.string().regex(/^(Qm[1-9A-HJ-NP-Za-km-z]{44}|b[A-Za-z0-9+/=]+)$/, "Invalid CID");
|
|
19
|
+
z.string().regex(/^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/, "Invalid BCP 47 language tag");
|
|
20
|
+
var uriSchema = z.string().url();
|
|
21
|
+
var strongRefSchema = z.object({
|
|
22
|
+
uri: atUriSchema,
|
|
23
|
+
cid: cidSchema
|
|
24
|
+
});
|
|
25
|
+
var selfLabelsSchema = z.object({
|
|
26
|
+
$type: z.literal("com.atproto.label.defs#selfLabels").optional(),
|
|
27
|
+
values: z.array(z.object({ val: z.string() }))
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// src/publishing/schemas.ts
|
|
31
|
+
var rgbColorSchema = z.object({
|
|
32
|
+
r: z.number().int().min(0).max(255),
|
|
33
|
+
g: z.number().int().min(0).max(255),
|
|
34
|
+
b: z.number().int().min(0).max(255)
|
|
35
|
+
});
|
|
36
|
+
var BasicThemeSchema = z.object({
|
|
37
|
+
background: rgbColorSchema,
|
|
38
|
+
foreground: rgbColorSchema,
|
|
39
|
+
accent: rgbColorSchema,
|
|
40
|
+
accentForeground: rgbColorSchema
|
|
41
|
+
});
|
|
42
|
+
var blobRefSchema = z.object({
|
|
43
|
+
$type: z.string().optional(),
|
|
44
|
+
ref: z.unknown(),
|
|
45
|
+
mimeType: z.string().optional(),
|
|
46
|
+
size: z.number().optional()
|
|
47
|
+
}).passthrough();
|
|
48
|
+
var StandardSitePublicationRecordSchema = z.object({
|
|
49
|
+
url: uriSchema,
|
|
50
|
+
name: z.string().min(1).refine(maxGraphemes(500)).max(5e3),
|
|
51
|
+
description: z.string().refine(maxGraphemes(3e3)).max(3e4).optional(),
|
|
52
|
+
icon: blobRefSchema.optional(),
|
|
53
|
+
basicTheme: BasicThemeSchema.optional(),
|
|
54
|
+
labels: selfLabelsSchema.optional(),
|
|
55
|
+
preferences: z.object({
|
|
56
|
+
showInDiscover: z.boolean().optional()
|
|
57
|
+
}).partial().optional()
|
|
58
|
+
}).passthrough();
|
|
59
|
+
var contributorSchema = z.object({
|
|
60
|
+
did: didSchema,
|
|
61
|
+
role: z.string().refine(maxGraphemes(100)).max(1e3).optional(),
|
|
62
|
+
displayName: z.string().refine(maxGraphemes(100)).max(1e3).optional()
|
|
63
|
+
}).passthrough();
|
|
64
|
+
var StandardSiteDocumentRecordSchema = z.object({
|
|
65
|
+
site: z.string().min(1),
|
|
66
|
+
title: z.string().min(1).refine(maxGraphemes(500)).max(5e3),
|
|
67
|
+
path: z.string().optional(),
|
|
68
|
+
publishedAt: datetimeSchema,
|
|
69
|
+
updatedAt: datetimeSchema.optional(),
|
|
70
|
+
description: z.string().refine(maxGraphemes(3e3)).max(3e4).optional(),
|
|
71
|
+
textContent: z.string().optional(),
|
|
72
|
+
tags: z.array(z.string().refine(maxGraphemes(128)).max(1280)).optional(),
|
|
73
|
+
coverImage: blobRefSchema.optional(),
|
|
74
|
+
contributors: z.array(contributorSchema).optional(),
|
|
75
|
+
bskyPostRef: strongRefSchema.optional(),
|
|
76
|
+
labels: selfLabelsSchema.optional()
|
|
77
|
+
}).passthrough();
|
|
78
|
+
var StandardSiteSubscriptionRecordSchema = z.object({
|
|
79
|
+
publication: atUriSchema,
|
|
80
|
+
createdAt: datetimeSchema.optional()
|
|
81
|
+
});
|
|
82
|
+
var StandardSiteRecommendRecordSchema = z.object({
|
|
83
|
+
document: atUriSchema,
|
|
84
|
+
createdAt: datetimeSchema
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// src/publishing/registry.ts
|
|
88
|
+
var STANDARD_SITE_PUBLISHERS = Object.freeze([
|
|
89
|
+
{ host: "leaflet.pub", name: "Leaflet", iconKey: "leaflet" },
|
|
90
|
+
{ host: "pckt.blog", name: "pckt", iconKey: "pckt" },
|
|
91
|
+
{ host: "offprint.app", name: "Offprint", iconKey: "offprint" }
|
|
92
|
+
]);
|
|
93
|
+
function hostMatches(host, target) {
|
|
94
|
+
return host === target || host.endsWith("." + target);
|
|
95
|
+
}
|
|
96
|
+
function hostFromUri(uri) {
|
|
97
|
+
if (!uri) return null;
|
|
98
|
+
try {
|
|
99
|
+
return new URL(uri).host.toLowerCase();
|
|
100
|
+
} catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function matchPublisherByHost(host) {
|
|
105
|
+
if (!host) return null;
|
|
106
|
+
const lower = host.toLowerCase();
|
|
107
|
+
return STANDARD_SITE_PUBLISHERS.find((p) => hostMatches(lower, p.host)) ?? null;
|
|
108
|
+
}
|
|
109
|
+
function matchPublisherByUri(uri) {
|
|
110
|
+
return matchPublisherByHost(hostFromUri(uri));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/publishing/types.ts
|
|
114
|
+
var STANDARD_SITE_PUBLICATION_NSID = "site.standard.publication";
|
|
115
|
+
var STANDARD_SITE_DOCUMENT_NSID = "site.standard.document";
|
|
116
|
+
var STANDARD_SITE_SUBSCRIPTION_NSID = "site.standard.graph.subscription";
|
|
117
|
+
var STANDARD_SITE_RECOMMEND_NSID = "site.standard.graph.recommend";
|
|
118
|
+
var STANDARD_SITE_AUTH_SOCIAL_NSID = "site.standard.authSocial";
|
|
119
|
+
var COLLECTION_SET = /* @__PURE__ */ new Set([
|
|
120
|
+
STANDARD_SITE_PUBLICATION_NSID,
|
|
121
|
+
STANDARD_SITE_DOCUMENT_NSID,
|
|
122
|
+
STANDARD_SITE_SUBSCRIPTION_NSID,
|
|
123
|
+
STANDARD_SITE_RECOMMEND_NSID
|
|
124
|
+
]);
|
|
125
|
+
function isStandardSiteAtUri(uri) {
|
|
126
|
+
if (!uri.startsWith("at://")) return false;
|
|
127
|
+
const segments = uri.slice("at://".length).split("/");
|
|
128
|
+
const collection = segments[1];
|
|
129
|
+
return collection !== void 0 && COLLECTION_SET.has(collection);
|
|
130
|
+
}
|
|
131
|
+
function hasStandardSiteAssociatedRef(refs) {
|
|
132
|
+
if (!refs) return false;
|
|
133
|
+
return refs.some((r) => isStandardSiteAtUri(r.uri));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export { BasicThemeSchema, STANDARD_SITE_AUTH_SOCIAL_NSID, STANDARD_SITE_DOCUMENT_NSID, STANDARD_SITE_PUBLICATION_NSID, STANDARD_SITE_PUBLISHERS, STANDARD_SITE_RECOMMEND_NSID, STANDARD_SITE_SUBSCRIPTION_NSID, StandardSiteDocumentRecordSchema, StandardSitePublicationRecordSchema, StandardSiteRecommendRecordSchema, StandardSiteSubscriptionRecordSchema, hasStandardSiteAssociatedRef, hostMatches, isStandardSiteAtUri, matchPublisherByHost, matchPublisherByUri };
|
|
137
|
+
//# sourceMappingURL=index.js.map
|
|
138
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/schemas/shared.ts","../../src/publishing/schemas.ts","../../src/publishing/registry.ts","../../src/publishing/types.ts"],"names":["z"],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\n\n/**\n * Grapheme-aware refinement matching the AT Protocol lexicon `maxGraphemes`\n * constraint. JS strings are sequences of UTF-16 code units, but lexicon\n * `maxGraphemes` counts user-perceived characters (grapheme clusters), so\n * emoji sequences, regional indicators, ZWJ joins, and combining marks all\n * count as one unit each. We use `Intl.Segmenter` to enforce this correctly.\n */\nexport function maxGraphemes(max: number) {\n return (value: string): boolean => {\n const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });\n let count = 0;\n for (const _ of segmenter.segment(value)) {\n count++;\n if (count > max) return false;\n }\n return true;\n };\n}\n\n/** Decentralized identifier, AT Protocol `format: did`. */\nexport const didSchema = z.string().regex(/^did:[a-z]+:[a-zA-Z0-9._:%-]+$/, 'Invalid DID');\n\n/** RFC 3339 datetime with timezone offset, AT Protocol `format: datetime`. */\nexport const datetimeSchema = z.string().datetime({ offset: true });\n\n/** Generic AT-URI, AT Protocol `format: at-uri`. */\nexport const atUriSchema = z.string().regex(/^at:\\/\\/[^\\s]+$/, 'Invalid AT-URI');\n\n/** Content identifier, AT Protocol `format: cid`. Loose validation -- accepts CIDv0 and CIDv1. */\nexport const cidSchema = z\n .string()\n .regex(/^(Qm[1-9A-HJ-NP-Za-km-z]{44}|b[A-Za-z0-9+/=]+)$/, 'Invalid CID');\n\n/** BCP 47 language tag, AT Protocol `format: language`. */\nexport const languageTagSchema = z\n .string()\n .regex(/^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/, 'Invalid BCP 47 language tag');\n\n/** Generic URI, AT Protocol `format: uri`. */\nexport const uriSchema = z.string().url();\n\n/**\n * StrongRef shape from `com.atproto.repo.strongRef` -- pins a record by both\n * AT-URI (identity) and CID (version).\n */\nexport const strongRefSchema = z.object({\n uri: atUriSchema,\n cid: cidSchema,\n});\n\n/**\n * Self-labels shape from `com.atproto.label.defs#selfLabels`. Modelled\n * permissively because clients rarely construct this directly; the AppView\n * handles label validation.\n */\nexport const selfLabelsSchema = z.object({\n $type: z.literal('com.atproto.label.defs#selfLabels').optional(),\n values: z.array(z.object({ val: z.string() })),\n});\n","import { z } from 'zod';\n\nimport {\n atUriSchema,\n datetimeSchema,\n didSchema,\n maxGraphemes,\n selfLabelsSchema,\n strongRefSchema,\n uriSchema,\n} from '../schemas/shared.js';\n\n/**\n * Zod schemas mirroring the canonical Standard.site lexicons that Sifa\n * consumes when rendering publication embeds.\n *\n * Canonical lexicons live at:\n * DID: did:plc:re3ebnp5v7ffagz6rb6xfei4\n * PDS: https://auriporia.us-west.host.bsky.network\n * Collection: com.atproto.lexicon.schema\n *\n * Sifa does NOT own these lexicons; we vendor the validation shapes so\n * clients can parse augmented embeds and (in Phase 4) write subscription\n * records to viewers' PDSes. Re-check against the canonical PDS on each\n * SDK release to detect schema drift.\n */\n\nconst rgbColorSchema = z.object({\n r: z.number().int().min(0).max(255),\n g: z.number().int().min(0).max(255),\n b: z.number().int().min(0).max(255),\n});\n\nexport type RgbColor = z.infer<typeof rgbColorSchema>;\n\n/** site.standard.theme.basic */\nexport const BasicThemeSchema = z.object({\n background: rgbColorSchema,\n foreground: rgbColorSchema,\n accent: rgbColorSchema,\n accentForeground: rgbColorSchema,\n});\n\nexport type BasicTheme = z.infer<typeof BasicThemeSchema>;\n\nconst blobRefSchema = z\n .object({\n $type: z.string().optional(),\n ref: z.unknown(),\n mimeType: z.string().optional(),\n size: z.number().optional(),\n })\n .passthrough();\n\n/** site.standard.publication */\nexport const StandardSitePublicationRecordSchema = z\n .object({\n url: uriSchema,\n name: z.string().min(1).refine(maxGraphemes(500)).max(5000),\n description: z.string().refine(maxGraphemes(3000)).max(30000).optional(),\n icon: blobRefSchema.optional(),\n basicTheme: BasicThemeSchema.optional(),\n labels: selfLabelsSchema.optional(),\n preferences: z\n .object({\n showInDiscover: z.boolean().optional(),\n })\n .partial()\n .optional(),\n })\n .passthrough();\n\nexport type StandardSitePublicationRecord = z.infer<typeof StandardSitePublicationRecordSchema>;\n\nconst contributorSchema = z\n .object({\n did: didSchema,\n role: z.string().refine(maxGraphemes(100)).max(1000).optional(),\n displayName: z.string().refine(maxGraphemes(100)).max(1000).optional(),\n })\n .passthrough();\n\n/** site.standard.document */\nexport const StandardSiteDocumentRecordSchema = z\n .object({\n site: z.string().min(1),\n title: z.string().min(1).refine(maxGraphemes(500)).max(5000),\n path: z.string().optional(),\n publishedAt: datetimeSchema,\n updatedAt: datetimeSchema.optional(),\n description: z.string().refine(maxGraphemes(3000)).max(30000).optional(),\n textContent: z.string().optional(),\n tags: z.array(z.string().refine(maxGraphemes(128)).max(1280)).optional(),\n coverImage: blobRefSchema.optional(),\n contributors: z.array(contributorSchema).optional(),\n bskyPostRef: strongRefSchema.optional(),\n labels: selfLabelsSchema.optional(),\n })\n .passthrough();\n\nexport type StandardSiteDocumentRecord = z.infer<typeof StandardSiteDocumentRecordSchema>;\n\n/**\n * site.standard.graph.subscription\n *\n * Authored by a viewer to declare a subscription to a publication. Used\n * by Phase 4 inline-subscribe path. Record key is a TID; the AT-URI\n * shape is `at://<viewer-did>/site.standard.graph.subscription/<rkey>`.\n */\nexport const StandardSiteSubscriptionRecordSchema = z.object({\n publication: atUriSchema,\n createdAt: datetimeSchema.optional(),\n});\n\nexport type StandardSiteSubscriptionRecord = z.infer<typeof StandardSiteSubscriptionRecordSchema>;\n\n/**\n * site.standard.graph.recommend\n *\n * Document-level \"like\" record. Same scope as subscription via the\n * site.standard.authSocial OAuth permission-set, so Phase 4 unlocks\n * inline likes alongside inline subscribes.\n */\nexport const StandardSiteRecommendRecordSchema = z.object({\n document: atUriSchema,\n createdAt: datetimeSchema,\n});\n\nexport type StandardSiteRecommendRecord = z.infer<typeof StandardSiteRecommendRecordSchema>;\n","/**\n * Publisher allowlist for the Standard.site rich embed.\n *\n * Mirrors `bluesky-social/social-app`\n * `src/components/Post/Embed/StandardSiteEmbed/publishers.ts`. The only\n * gate this provides is which publishers get the highlighted\n * \"Subscribe on {Publisher}\" CTA with a publisher icon vs the plain\n * \"View publication\" fallback — any Standard.site embed renders\n * regardless of allowlist membership.\n *\n * Sync policy: review additions against the upstream bsky list weekly;\n * Singi Labs reviews before merge.\n */\n\nexport interface Publisher {\n /** Lowercase host. Subdomains are matched via `hostMatches`. */\n host: string;\n /** Human-facing publisher name shown in CTA copy. */\n name: string;\n /**\n * Stable identifier used by clients to look up brand icons. The SDK\n * does not ship icon assets — sifa-web maintains them keyed by this\n * id so React Native vs web rendering can diverge.\n */\n iconKey: 'leaflet' | 'pckt' | 'offprint';\n}\n\nexport const STANDARD_SITE_PUBLISHERS: readonly Publisher[] = Object.freeze([\n { host: 'leaflet.pub', name: 'Leaflet', iconKey: 'leaflet' },\n { host: 'pckt.blog', name: 'pckt', iconKey: 'pckt' },\n { host: 'offprint.app', name: 'Offprint', iconKey: 'offprint' },\n]);\n\n/**\n * Returns true when `host` exactly matches `target` or is a subdomain of\n * it. Hosts are expected to be lowercase already.\n */\nexport function hostMatches(host: string, target: string): boolean {\n return host === target || host.endsWith('.' + target);\n}\n\nfunction hostFromUri(uri: string | undefined | null): string | null {\n if (!uri) return null;\n try {\n return new URL(uri).host.toLowerCase();\n } catch {\n return null;\n }\n}\n\n/**\n * Match a publisher by host. Returns the publisher when `host` is on the\n * allowlist (exact or subdomain match), null otherwise. Host should be\n * lowercase.\n */\nexport function matchPublisherByHost(host: string | null | undefined): Publisher | null {\n if (!host) return null;\n const lower = host.toLowerCase();\n return STANDARD_SITE_PUBLISHERS.find((p) => hostMatches(lower, p.host)) ?? null;\n}\n\n/**\n * Match a publisher by URI. Convenience wrapper around\n * `matchPublisherByHost` for callers that have a publication URL handy.\n */\nexport function matchPublisherByUri(uri: string | undefined | null): Publisher | null {\n return matchPublisherByHost(hostFromUri(uri));\n}\n","import type { BasicTheme } from './schemas.js';\n\n/**\n * Publication metadata embedded in the augmented activity view by\n * sifa-api when an external link card matches an indexed publication.\n *\n * `uri` is the publication's AT-URI (e.g.\n * `at://did:plc:abc/site.standard.publication/xyz`). `theme` carries\n * the publication's own colors when supplied — clients should apply a\n * WCAG min-contrast fallback before honoring them.\n *\n * `icon` is left as `unknown` here because its representation depends\n * on the surface: blob ref on the wire, CDN URL after resolution.\n */\nexport interface PublicationSource {\n uri: string;\n title: string;\n icon?: unknown;\n theme?: BasicTheme;\n}\n\n/**\n * Shape attached to activity items whose external link card URL matches\n * a Standard.site record. Mirrors the relevant fields of bsky's\n * `StandardSiteEmbed` view so a sifa-web renderer can be near-1:1.\n *\n * `associatedRefs` carries AT-URIs the client may use in Phase 4 to\n * query subscription state for the viewer.\n */\nexport interface StandardSiteEmbedView {\n uri: string;\n source: PublicationSource;\n associatedRefs: { uri: string }[];\n createdAt?: string;\n readingTime?: number;\n}\n\nexport const STANDARD_SITE_PUBLICATION_NSID = 'site.standard.publication' as const;\nexport const STANDARD_SITE_DOCUMENT_NSID = 'site.standard.document' as const;\nexport const STANDARD_SITE_SUBSCRIPTION_NSID = 'site.standard.graph.subscription' as const;\nexport const STANDARD_SITE_RECOMMEND_NSID = 'site.standard.graph.recommend' as const;\n\n/**\n * Pre-defined OAuth permission-set the consumer apps request to write\n * subscription + recommend records on behalf of the viewer. The actual\n * permission-set is published under\n * `at://did:plc:re3ebnp5v7ffagz6rb6xfei4/com.atproto.lexicon.schema/site.standard.authSocial`.\n */\nexport const STANDARD_SITE_AUTH_SOCIAL_NSID = 'site.standard.authSocial' as const;\n\nconst COLLECTION_SET = new Set<string>([\n STANDARD_SITE_PUBLICATION_NSID,\n STANDARD_SITE_DOCUMENT_NSID,\n STANDARD_SITE_SUBSCRIPTION_NSID,\n STANDARD_SITE_RECOMMEND_NSID,\n]);\n\n/**\n * True when the AT-URI's collection segment is a Standard.site\n * collection. Useful for detecting Standard.site embed augmentation on\n * arbitrary activity items.\n */\nexport function isStandardSiteAtUri(uri: string): boolean {\n if (!uri.startsWith('at://')) return false;\n const segments = uri.slice('at://'.length).split('/');\n const collection = segments[1];\n return collection !== undefined && COLLECTION_SET.has(collection);\n}\n\n/**\n * True when any `associatedRefs[].uri` is a Standard.site collection\n * AT-URI. The bsky client uses the same check to gate the\n * `StandardSiteEmbed` renderer.\n */\nexport function hasStandardSiteAssociatedRef(refs: { uri: string }[] | undefined): boolean {\n if (!refs) return false;\n return refs.some((r) => isStandardSiteAtUri(r.uri));\n}\n"]}
|
package/dist/query/index.d.cts
CHANGED
|
@@ -37,7 +37,7 @@ declare function useSifaConfig(): SifaApiConfig;
|
|
|
37
37
|
* Pass `{ enabled: false }` (or an empty `handleOrDid`) to defer the
|
|
38
38
|
* fetch.
|
|
39
39
|
*/
|
|
40
|
-
declare function useProfile(handleOrDid: string | undefined | null, options?: Omit<UseQueryOptions<Profile | null, Error, Profile | null, ReturnType<typeof sifaQueryKeys.profile.byHandle>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<Profile | null
|
|
40
|
+
declare function useProfile(handleOrDid: string | undefined | null, options?: Omit<UseQueryOptions<Profile | null, Error, Profile | null, ReturnType<typeof sifaQueryKeys.profile.byHandle>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<Profile | null>, Error>;
|
|
41
41
|
/**
|
|
42
42
|
* React hook for a profile's AT Fund link. Returns `null` data on error
|
|
43
43
|
* or when the profile has no link configured.
|
|
@@ -162,7 +162,7 @@ declare function useUpdateProfileLocation(ownerHandleOrDid: string, options?: Om
|
|
|
162
162
|
declare function useDeleteProfileLocation(ownerHandleOrDid: string, options?: Omit<UseMutationOptions<WriteResult, Error, string>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<WriteResult, Error, string, unknown>;
|
|
163
163
|
|
|
164
164
|
/** React hook for reading the external-accounts list. Returns `[]` data on error. */
|
|
165
|
-
declare function useExternalAccounts(handleOrDid: string | undefined | null, options?: Omit<UseQueryOptions<ExternalAccount[], Error, ExternalAccount[], ReturnType<typeof sifaQueryKeys.profile.externalAccounts>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<ExternalAccount[]
|
|
165
|
+
declare function useExternalAccounts(handleOrDid: string | undefined | null, options?: Omit<UseQueryOptions<ExternalAccount[], Error, ExternalAccount[], ReturnType<typeof sifaQueryKeys.profile.externalAccounts>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<ExternalAccount[]>, Error>;
|
|
166
166
|
/** React hook for creating an external account. */
|
|
167
167
|
declare function useCreateExternalAccount(ownerHandleOrDid: string, options?: Omit<UseMutationOptions<CreateExternalAccountResult, Error, ExternalAccountInput>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<CreateExternalAccountResult, Error, ExternalAccountInput, unknown>;
|
|
168
168
|
/** Variables for {@link useUpdateExternalAccount}. */
|
|
@@ -230,43 +230,43 @@ declare const useBulkUnhideProfileItems: (ownerHandleOrDid: string, options?: Om
|
|
|
230
230
|
/**
|
|
231
231
|
* React hook for the public homepage stats. Returns `null` data on error.
|
|
232
232
|
*/
|
|
233
|
-
declare function useStats(options?: Omit<UseQueryOptions<StatsResponse | null, Error, StatsResponse | null, ReturnType<typeof sifaQueryKeys.stats.homepage>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<StatsResponse | null
|
|
233
|
+
declare function useStats(options?: Omit<UseQueryOptions<StatsResponse | null, Error, StatsResponse | null, ReturnType<typeof sifaQueryKeys.stats.homepage>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<StatsResponse | null>, Error>;
|
|
234
234
|
|
|
235
235
|
/** React hook for the public app registry. */
|
|
236
|
-
declare function useAppsRegistry(options?: Omit<UseQueryOptions<AppRegistryEntry[], Error, AppRegistryEntry[], ReturnType<typeof sifaQueryKeys.apps.registry>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<AppRegistryEntry[]
|
|
236
|
+
declare function useAppsRegistry(options?: Omit<UseQueryOptions<AppRegistryEntry[], Error, AppRegistryEntry[], ReturnType<typeof sifaQueryKeys.apps.registry>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<AppRegistryEntry[]>, Error>;
|
|
237
237
|
/**
|
|
238
238
|
* React hook for the authenticated user's hidden-apps list. Requires a
|
|
239
239
|
* client-side session (relies on `credentials: 'include'`).
|
|
240
240
|
*/
|
|
241
|
-
declare function useHiddenApps(options?: Omit<UseQueryOptions<HiddenApp[], Error, HiddenApp[], ReturnType<typeof sifaQueryKeys.apps.hidden>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<HiddenApp[]
|
|
241
|
+
declare function useHiddenApps(options?: Omit<UseQueryOptions<HiddenApp[], Error, HiddenApp[], ReturnType<typeof sifaQueryKeys.apps.hidden>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<HiddenApp[]>, Error>;
|
|
242
242
|
|
|
243
|
-
declare function useSearchProfiles(filters: SearchFilters, options?: Omit<UseQueryOptions<SearchResponse, Error, SearchResponse, ReturnType<typeof sifaQueryKeys.search.profiles>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<SearchResponse
|
|
244
|
-
declare function useSkillSuggestions(query: string, options?: Omit<UseQueryOptions<SkillSearchResult[], Error, SkillSearchResult[], ReturnType<typeof sifaQueryKeys.search.skills>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<SkillSearchResult[]
|
|
243
|
+
declare function useSearchProfiles(filters: SearchFilters, options?: Omit<UseQueryOptions<SearchResponse, Error, SearchResponse, ReturnType<typeof sifaQueryKeys.search.profiles>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<SearchResponse>, Error>;
|
|
244
|
+
declare function useSkillSuggestions(query: string, options?: Omit<UseQueryOptions<SkillSearchResult[], Error, SkillSearchResult[], ReturnType<typeof sifaQueryKeys.search.skills>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<SkillSearchResult[]>, Error>;
|
|
245
245
|
/**
|
|
246
246
|
* Canonical-skill search hook. Hits `/api/skills/search` (the
|
|
247
247
|
* canonical-skills DB lookup, distinct from {@link useSkillSuggestions}'s
|
|
248
248
|
* `/api/search/skills` profile-skill typeahead). Skips the network call
|
|
249
249
|
* when the query is empty.
|
|
250
250
|
*/
|
|
251
|
-
declare function useCanonicalSkillSearch(query: string, limit?: number, options?: Omit<UseQueryOptions<SkillSuggestion[], Error, SkillSuggestion[], ReturnType<typeof sifaQueryKeys.search.canonicalSkills>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<SkillSuggestion[]
|
|
252
|
-
declare function useSearchFilters(options?: Omit<UseQueryOptions<FilterOptions, Error, FilterOptions, ReturnType<typeof sifaQueryKeys.search.filters>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<FilterOptions
|
|
251
|
+
declare function useCanonicalSkillSearch(query: string, limit?: number, options?: Omit<UseQueryOptions<SkillSuggestion[], Error, SkillSuggestion[], ReturnType<typeof sifaQueryKeys.search.canonicalSkills>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<SkillSuggestion[]>, Error>;
|
|
252
|
+
declare function useSearchFilters(options?: Omit<UseQueryOptions<FilterOptions, Error, FilterOptions, ReturnType<typeof sifaQueryKeys.search.filters>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<FilterOptions>, Error>;
|
|
253
253
|
|
|
254
254
|
declare function useSimilarProfiles(did: string | undefined | null, opts?: {
|
|
255
255
|
limit?: number;
|
|
256
|
-
}, options?: Omit<UseQueryOptions<SimilarProfile[], Error, SimilarProfile[], ReturnType<typeof sifaQueryKeys.discovery.similar>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<SimilarProfile[]
|
|
257
|
-
declare function useSuggestions(opts?: Omit<FetchSuggestionsOptions, keyof Omit<FetchSuggestionsOptions, 'source' | 'includeDismissed' | 'cursor' | 'limit'>>, options?: Omit<UseQueryOptions<SuggestionsResponse, Error, SuggestionsResponse, ReturnType<typeof sifaQueryKeys.discovery.suggestions>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<SuggestionsResponse
|
|
256
|
+
}, options?: Omit<UseQueryOptions<SimilarProfile[], Error, SimilarProfile[], ReturnType<typeof sifaQueryKeys.discovery.similar>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<SimilarProfile[]>, Error>;
|
|
257
|
+
declare function useSuggestions(opts?: Omit<FetchSuggestionsOptions, keyof Omit<FetchSuggestionsOptions, 'source' | 'includeDismissed' | 'cursor' | 'limit'>>, options?: Omit<UseQueryOptions<SuggestionsResponse, Error, SuggestionsResponse, ReturnType<typeof sifaQueryKeys.discovery.suggestions>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<SuggestionsResponse>, Error>;
|
|
258
258
|
declare function useSuggestionCount(since?: string, options?: Omit<UseQueryOptions<number, Error, number, ReturnType<typeof sifaQueryKeys.discovery.suggestionCount>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<number, Error>;
|
|
259
|
-
declare function useFeaturedProfile(options?: Omit<UseQueryOptions<FeaturedProfile | null, Error, FeaturedProfile | null, ReturnType<typeof sifaQueryKeys.discovery.featured>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<FeaturedProfile | null
|
|
259
|
+
declare function useFeaturedProfile(options?: Omit<UseQueryOptions<FeaturedProfile | null, Error, FeaturedProfile | null, ReturnType<typeof sifaQueryKeys.discovery.featured>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<FeaturedProfile | null>, Error>;
|
|
260
260
|
|
|
261
261
|
declare function useFollowing(opts?: {
|
|
262
262
|
source?: string;
|
|
263
263
|
cursor?: string;
|
|
264
264
|
limit?: number;
|
|
265
|
-
}, options?: Omit<UseQueryOptions<FollowingResponse, Error, FollowingResponse, ReturnType<typeof sifaQueryKeys.follow.following>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<FollowingResponse
|
|
265
|
+
}, options?: Omit<UseQueryOptions<FollowingResponse, Error, FollowingResponse, ReturnType<typeof sifaQueryKeys.follow.following>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<FollowingResponse>, Error>;
|
|
266
266
|
|
|
267
|
-
declare function useHeatmapData(handleOrDid: string | undefined | null, days: number, options?: Omit<UseQueryOptions<HeatmapResponse | null, Error, HeatmapResponse | null, ReturnType<typeof sifaQueryKeys.activity.heatmap>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<HeatmapResponse | null
|
|
268
|
-
declare function useActivityTeaser(handleOrDid: string | undefined | null, options?: Omit<UseQueryOptions<ActivityTeaserResponse | null, Error, ActivityTeaserResponse | null, ReturnType<typeof sifaQueryKeys.activity.teaser>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<ActivityTeaserResponse | null
|
|
269
|
-
declare function useActivityFeed(handleOrDid: string | undefined | null, opts?: Pick<FetchActivityFeedOptions, 'category' | 'limit' | 'cursor'>, options?: Omit<UseQueryOptions<ActivityFeedResponse | null, Error, ActivityFeedResponse | null, ReturnType<typeof sifaQueryKeys.activity.feed>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<ActivityFeedResponse | null
|
|
267
|
+
declare function useHeatmapData(handleOrDid: string | undefined | null, days: number, options?: Omit<UseQueryOptions<HeatmapResponse | null, Error, HeatmapResponse | null, ReturnType<typeof sifaQueryKeys.activity.heatmap>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<HeatmapResponse | null>, Error>;
|
|
268
|
+
declare function useActivityTeaser(handleOrDid: string | undefined | null, options?: Omit<UseQueryOptions<ActivityTeaserResponse | null, Error, ActivityTeaserResponse | null, ReturnType<typeof sifaQueryKeys.activity.teaser>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<ActivityTeaserResponse | null>, Error>;
|
|
269
|
+
declare function useActivityFeed(handleOrDid: string | undefined | null, opts?: Pick<FetchActivityFeedOptions, 'category' | 'limit' | 'cursor'>, options?: Omit<UseQueryOptions<ActivityFeedResponse | null, Error, ActivityFeedResponse | null, ReturnType<typeof sifaQueryKeys.activity.feed>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<ActivityFeedResponse | null>, Error>;
|
|
270
270
|
|
|
271
271
|
/** Count of confirmed endorsements for a DID. Returns 0 on error. */
|
|
272
272
|
declare function useEndorsementCount(did: string | undefined | null, options?: Omit<UseQueryOptions<number, Error, number, ReturnType<typeof sifaQueryKeys.endorsement.count>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<number, Error>;
|
|
@@ -281,9 +281,9 @@ declare function useNetworkStreamCount(did: string | undefined | null, options?:
|
|
|
281
281
|
* Batch-look up reaction status for multiple URIs. Skips the network call
|
|
282
282
|
* when `uris` is empty.
|
|
283
283
|
*/
|
|
284
|
-
declare function useReactionStatus(uris: string[], options?: Omit<UseQueryOptions<Record<string, ReactionStatus> | null, Error, Record<string, ReactionStatus> | null, ReturnType<typeof sifaQueryKeys.reactions.status>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<Record<string, ReactionStatus> | null
|
|
284
|
+
declare function useReactionStatus(uris: string[], options?: Omit<UseQueryOptions<Record<string, ReactionStatus> | null, Error, Record<string, ReactionStatus> | null, ReturnType<typeof sifaQueryKeys.reactions.status>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<Record<string, ReactionStatus> | null>, Error>;
|
|
285
285
|
/** Check whether the authenticated viewer has an account on the given app. */
|
|
286
|
-
declare function useAppAccountCheck(appId: string | undefined | null, options?: Omit<UseQueryOptions<AccountCheckResult | null, Error, AccountCheckResult | null, ReturnType<typeof sifaQueryKeys.reactions.accountCheck>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<AccountCheckResult | null
|
|
286
|
+
declare function useAppAccountCheck(appId: string | undefined | null, options?: Omit<UseQueryOptions<AccountCheckResult | null, Error, AccountCheckResult | null, ReturnType<typeof sifaQueryKeys.reactions.accountCheck>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<AccountCheckResult | null>, Error>;
|
|
287
287
|
|
|
288
288
|
/** Variables for {@link useCreateReaction}. */
|
|
289
289
|
interface CreateReactionVariables {
|
|
@@ -323,9 +323,9 @@ interface DeleteReactionVariables {
|
|
|
323
323
|
declare function useDeleteReaction(options?: Omit<UseMutationOptions<WriteResult, Error, DeleteReactionVariables>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<WriteResult, Error, DeleteReactionVariables, unknown>;
|
|
324
324
|
|
|
325
325
|
/** Public roadmap vote tallies. Returns `{}` data on error. */
|
|
326
|
-
declare function useRoadmapVotes(options?: Omit<UseQueryOptions<RoadmapVotesResponse, Error, RoadmapVotesResponse, ReturnType<typeof sifaQueryKeys.roadmap.votes>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<RoadmapVotesResponse
|
|
326
|
+
declare function useRoadmapVotes(options?: Omit<UseQueryOptions<RoadmapVotesResponse, Error, RoadmapVotesResponse, ReturnType<typeof sifaQueryKeys.roadmap.votes>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<RoadmapVotesResponse>, Error>;
|
|
327
327
|
/** Roadmap items the authenticated viewer has voted on. Returns `[]` data on error. */
|
|
328
|
-
declare function useMyRoadmapVotes(options?: Omit<UseQueryOptions<string[], Error, string[], ReturnType<typeof sifaQueryKeys.roadmap.myVotes>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<string[]
|
|
328
|
+
declare function useMyRoadmapVotes(options?: Omit<UseQueryOptions<string[], Error, string[], ReturnType<typeof sifaQueryKeys.roadmap.myVotes>>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<string[]>, Error>;
|
|
329
329
|
|
|
330
330
|
/** React hook for casting a roadmap vote. Variable: the item key. */
|
|
331
331
|
declare function useCastRoadmapVote(options?: Omit<UseMutationOptions<WriteResult, Error, string>, 'mutationFn'>): _tanstack_react_query.UseMutationResult<WriteResult, Error, string, unknown>;
|