@aturi.to/waypoints 0.1.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 +21 -0
- package/README.md +86 -0
- package/dist/index.cjs +1351 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +262 -0
- package/dist/index.d.ts +262 -0
- package/dist/index.js +1327 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
type WaypointType = 'post' | 'profile' | 'list' | 'record' | 'unknown';
|
|
2
|
+
/**
|
|
3
|
+
* Keys identifying which "data family" a waypoint belongs to for auto-redirect
|
|
4
|
+
* purposes. Two waypoints can only be the endpoints of an auto-redirect when
|
|
5
|
+
* they share at least one family key (i.e. they render the same underlying
|
|
6
|
+
* atproto collections). Display groupings live in `WAYPOINT_CATEGORIES_DATA`
|
|
7
|
+
* and are independent of this.
|
|
8
|
+
*/
|
|
9
|
+
type RedirectCompatFamily = 'bluesky-social' | 'standard-site' | 'tangled' | 'margin' | 'grain' | 'pinksky' | 'semble' | 'streamplace' | 'popfeed' | 'sifa' | 'blento';
|
|
10
|
+
type WaypointData = {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
description: string | ((collection?: string, type?: WaypointType) => string);
|
|
14
|
+
getUrl: (handle: string, collection?: string, rkey?: string, did?: string) => string | null;
|
|
15
|
+
supportedTypes: WaypointType[];
|
|
16
|
+
category: string;
|
|
17
|
+
/**
|
|
18
|
+
* Data families this waypoint participates in. Auto-redirect rules are only
|
|
19
|
+
* emitted between waypoints that share at least one family. An empty array
|
|
20
|
+
* means the waypoint can never be an auto-redirect source *or* destination
|
|
21
|
+
* (dev tools / generic record viewers land here by design).
|
|
22
|
+
*/
|
|
23
|
+
redirectCompat: RedirectCompatFamily[];
|
|
24
|
+
/**
|
|
25
|
+
* NSID prefixes that signal this waypoint is meaningfully usable for the
|
|
26
|
+
* target repo. When set, the extension can call describeRepo on the target
|
|
27
|
+
* DID and check whether any of the user's collections start with one of
|
|
28
|
+
* these prefixes — if none do, the waypoint is flagged as "no records
|
|
29
|
+
* found" in the popup and demoted in smart recommendations.
|
|
30
|
+
*
|
|
31
|
+
* Use trailing-dot prefixes for whole namespaces (e.g. `'sh.tangled.'`)
|
|
32
|
+
* or full NSIDs for single-collection apps. Atmosphere apps typically
|
|
33
|
+
* declare a reversed-domain prefix (`semble.so` → `so.semble.`) so the
|
|
34
|
+
* popup can flag accounts that haven't published any of that app's
|
|
35
|
+
* records. Omit the field entirely for generic explorers (PDSls,
|
|
36
|
+
* atp.tools, Aturi) — those stay in the "unknown" / no-opinion state.
|
|
37
|
+
*/
|
|
38
|
+
expectedCollections?: string[];
|
|
39
|
+
};
|
|
40
|
+
type CompatFamilyMeta = {
|
|
41
|
+
id: RedirectCompatFamily;
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Registry of compat families. `description` is shown in the options UI so the
|
|
47
|
+
* user understands what each "Favorite for X" controls.
|
|
48
|
+
*/
|
|
49
|
+
declare const COMPAT_FAMILIES: Record<RedirectCompatFamily, CompatFamilyMeta>;
|
|
50
|
+
declare const COMPAT_FAMILY_ORDER: RedirectCompatFamily[];
|
|
51
|
+
type WaypointCategoryData = {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
defaultWaypointId: string;
|
|
56
|
+
subcategories?: WaypointCategoryData[];
|
|
57
|
+
};
|
|
58
|
+
type CategorizedWaypointsData = {
|
|
59
|
+
category: WaypointCategoryData;
|
|
60
|
+
waypoints: WaypointData[];
|
|
61
|
+
};
|
|
62
|
+
declare const WAYPOINT_DESTINATIONS_DATA: Record<string, WaypointData>;
|
|
63
|
+
declare const WAYPOINT_ORDER: string[];
|
|
64
|
+
declare function getWaypointDataForType(type: WaypointType): WaypointData[];
|
|
65
|
+
declare function getWaypointCountData(): number;
|
|
66
|
+
declare const WAYPOINT_CATEGORIES_DATA: Record<string, WaypointCategoryData>;
|
|
67
|
+
declare const CATEGORY_ORDER: string[];
|
|
68
|
+
declare function getCategorizedWaypointsData(type: WaypointType): CategorizedWaypointsData[];
|
|
69
|
+
declare function getRecommendedWaypointsData(type: WaypointType, collection?: string): {
|
|
70
|
+
waypoints: WaypointData[];
|
|
71
|
+
label: string;
|
|
72
|
+
};
|
|
73
|
+
declare function getFeaturedWaypointData(type: WaypointType, collection?: string): WaypointData | null;
|
|
74
|
+
/**
|
|
75
|
+
* Result of comparing a waypoint's `expectedCollections` against the set of
|
|
76
|
+
* NSIDs found in the target repo.
|
|
77
|
+
*
|
|
78
|
+
* - 'present' — the user has at least one record under a matching prefix.
|
|
79
|
+
* - 'absent' — the waypoint declared collections but none are in the repo.
|
|
80
|
+
* - 'unknown' — the waypoint didn't declare any expectations, or we
|
|
81
|
+
* haven't scanned the repo yet (e.g. scan disabled, no DID).
|
|
82
|
+
*/
|
|
83
|
+
type WaypointActivity = 'present' | 'absent' | 'unknown';
|
|
84
|
+
/**
|
|
85
|
+
* Classify a waypoint against the set of collection NSIDs known to exist on
|
|
86
|
+
* the target repo. Prefix-matches each entry in `expectedCollections` against
|
|
87
|
+
* `repoCollections`. Returns 'unknown' when the waypoint has no declared
|
|
88
|
+
* expectations or the caller passed `null` for `repoCollections` (i.e. scan
|
|
89
|
+
* disabled or still in flight).
|
|
90
|
+
*/
|
|
91
|
+
declare function waypointActivity(waypoint: Pick<WaypointData, 'expectedCollections'>, repoCollections: ReadonlySet<string> | null): WaypointActivity;
|
|
92
|
+
|
|
93
|
+
type ParsedURI = {
|
|
94
|
+
type: 'post' | 'profile' | 'list' | 'record' | 'unknown';
|
|
95
|
+
uri: string;
|
|
96
|
+
handle: string;
|
|
97
|
+
did?: string;
|
|
98
|
+
collection?: string;
|
|
99
|
+
rkey?: string;
|
|
100
|
+
error?: string;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Parse URL path segments into structured AT URI data
|
|
104
|
+
* Examples:
|
|
105
|
+
* - /alice.bsky.social -> profile
|
|
106
|
+
* - /alice.bsky.social/app.bsky.feed.post/3k7qw... -> post
|
|
107
|
+
* - /did:plc:xxx/app.bsky.graph.list/abc -> list
|
|
108
|
+
*/
|
|
109
|
+
declare function parseURI(handle: string, collection?: string, rkey?: string): ParsedURI;
|
|
110
|
+
/**
|
|
111
|
+
* Resolve a handle to a DID using the Bluesky API
|
|
112
|
+
*/
|
|
113
|
+
declare function resolveHandle(handle: string): Promise<string | null>;
|
|
114
|
+
/**
|
|
115
|
+
* Get display name from handle or DID
|
|
116
|
+
*/
|
|
117
|
+
declare function getDisplayName(handle: string, did?: string): string;
|
|
118
|
+
|
|
119
|
+
type SourceApp = 'bluesky' | 'bluepy' | 'blacksky' | 'reddwarf' | 'witchsky' | 'catsky' | 'deer' | 'anisota' | 'pinksky' | 'leaflet' | 'tangled' | 'margin' | 'pdsls' | 'atptools' | 'semble' | 'streamplace' | 'grain' | 'popfeed' | 'sifa' | 'blento' | 'offprint' | 'pckt' | 'headDetected';
|
|
120
|
+
type ReverseMatch = {
|
|
121
|
+
source: SourceApp;
|
|
122
|
+
parsed: ParsedURI;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Reverse-match any supported Aturi waypoint site URL back into a structured
|
|
126
|
+
* ParsedURI (handle/collection/rkey). Returns `null` if the URL isn't on a
|
|
127
|
+
* supported site or isn't a shape we recognize.
|
|
128
|
+
*/
|
|
129
|
+
declare function matchSupportedUrl(url: URL): ReverseMatch | null;
|
|
130
|
+
/**
|
|
131
|
+
* Parse an AT URI string (e.g. "at://did:plc:abc123/collection/rkey") into
|
|
132
|
+
* its components. Used by head-based detection when an AT URI is found in
|
|
133
|
+
* a <link> tag's href attribute.
|
|
134
|
+
*/
|
|
135
|
+
declare function parseAtUri(uri: string): ReverseMatch | null;
|
|
136
|
+
/**
|
|
137
|
+
* All host names we know how to reverse-parse. Used by the popup + background
|
|
138
|
+
* worker to decide if a tab is "relevant" before doing more expensive work.
|
|
139
|
+
*/
|
|
140
|
+
declare const SUPPORTED_HOSTS: string[];
|
|
141
|
+
|
|
142
|
+
type ResolvedWaypoint = {
|
|
143
|
+
id: string;
|
|
144
|
+
name: string;
|
|
145
|
+
category: string;
|
|
146
|
+
url: string;
|
|
147
|
+
};
|
|
148
|
+
type ResolvedRecommendation = {
|
|
149
|
+
ids: string[];
|
|
150
|
+
label: string;
|
|
151
|
+
};
|
|
152
|
+
type ResolveResult = {
|
|
153
|
+
parsed: ParsedURI;
|
|
154
|
+
source: SourceApp;
|
|
155
|
+
did: string | null;
|
|
156
|
+
didResolved: boolean;
|
|
157
|
+
waypoints: ResolvedWaypoint[];
|
|
158
|
+
recommended: ResolvedRecommendation;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Waypoints whose `getUrl` only produces a useful destination when a DID is
|
|
162
|
+
* available. These are filtered out unless a DID is known. Mirrors the hosted
|
|
163
|
+
* aturi.to/api/resolve route exactly.
|
|
164
|
+
*/
|
|
165
|
+
declare const DID_REQUIRED_WAYPOINTS: ReadonlySet<string>;
|
|
166
|
+
type BuildWaypointsOptions = {
|
|
167
|
+
/** DID to pass to each waypoint's getUrl. Falls back to `parsed.did`. */
|
|
168
|
+
did?: string;
|
|
169
|
+
/** Waypoint id to omit (e.g. the source app the user is already on). */
|
|
170
|
+
excludeSourceId?: string;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Turn a parsed AT URI into the list of waypoints that can render it plus the
|
|
174
|
+
* recommended set, applying the DID-required filter and dropping waypoints
|
|
175
|
+
* whose getUrl returns null. This is the framework-agnostic core of the
|
|
176
|
+
* hosted resolve endpoint.
|
|
177
|
+
*/
|
|
178
|
+
declare function buildWaypointsForParsed(parsed: ParsedURI, options?: BuildWaypointsOptions): {
|
|
179
|
+
waypoints: ResolvedWaypoint[];
|
|
180
|
+
recommended: ResolvedRecommendation;
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Resolve an AT URI string (e.g. "at://did:plc:abc/app.bsky.feed.post/rkey")
|
|
184
|
+
* directly into its waypoints. Returns null if the string isn't a valid AT URI.
|
|
185
|
+
*/
|
|
186
|
+
declare function resolveAtUri(uri: string): ResolveResult | null;
|
|
187
|
+
type ResolveUrlOptions = {
|
|
188
|
+
/**
|
|
189
|
+
* When the URL pattern isn't recognized, fetch the page and look for a
|
|
190
|
+
* `<link href="at://…">` in <head>. Off by default to keep the resolver
|
|
191
|
+
* isomorphic (no network unless explicitly requested).
|
|
192
|
+
*/
|
|
193
|
+
fetchHead?: boolean;
|
|
194
|
+
/** Timeout for the optional head probe. Defaults to 4000ms. */
|
|
195
|
+
fetchHeadTimeoutMs?: number;
|
|
196
|
+
/**
|
|
197
|
+
* Resolve a handle to a DID so DID-only waypoints (pdsls, atptools, margin,
|
|
198
|
+
* grain, popfeed) are included. Pass `resolveHandle` from this package, or
|
|
199
|
+
* your own implementation.
|
|
200
|
+
*/
|
|
201
|
+
resolveHandle?: (handle: string) => Promise<string | null>;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Resolve a pasted/shared page URL back into the AT URI it represents and the
|
|
205
|
+
* waypoints that can render it. Uses local URL-pattern matching by default;
|
|
206
|
+
* optionally falls back to a `<head>` link probe and/or handle→DID resolution.
|
|
207
|
+
*
|
|
208
|
+
* The source app's own waypoint is omitted from the result (you're already
|
|
209
|
+
* there), mirroring the extension popup and hosted endpoint.
|
|
210
|
+
*/
|
|
211
|
+
declare function resolveUrl(url: string | URL, options?: ResolveUrlOptions): Promise<ResolveResult | null>;
|
|
212
|
+
type ResolveApiInput = {
|
|
213
|
+
url?: string;
|
|
214
|
+
atUri?: string;
|
|
215
|
+
/** Set false to skip the server-side <head> probe. */
|
|
216
|
+
headDetect?: boolean;
|
|
217
|
+
};
|
|
218
|
+
type ResolveApiParsed = {
|
|
219
|
+
type: WaypointType;
|
|
220
|
+
uri: string;
|
|
221
|
+
handle: string;
|
|
222
|
+
did: string | null;
|
|
223
|
+
collection: string | null;
|
|
224
|
+
rkey: string | null;
|
|
225
|
+
};
|
|
226
|
+
type ResolveApiSuccess = {
|
|
227
|
+
ok: true;
|
|
228
|
+
inputKind: 'atUri' | 'url';
|
|
229
|
+
detectedVia: 'atUri' | 'urlPattern' | 'headLink' | null;
|
|
230
|
+
source: SourceApp;
|
|
231
|
+
isKnownHost: boolean;
|
|
232
|
+
parsed: ResolveApiParsed;
|
|
233
|
+
didResolved: boolean;
|
|
234
|
+
recommended: ResolvedRecommendation;
|
|
235
|
+
waypoints: ResolvedWaypoint[];
|
|
236
|
+
};
|
|
237
|
+
type ResolveApiFailure = {
|
|
238
|
+
ok: false;
|
|
239
|
+
input?: string | null;
|
|
240
|
+
inputKind?: 'atUri' | 'url';
|
|
241
|
+
isKnownHost?: boolean;
|
|
242
|
+
reason?: string;
|
|
243
|
+
message?: string;
|
|
244
|
+
error?: string;
|
|
245
|
+
};
|
|
246
|
+
type ResolveApiResponse = ResolveApiSuccess | ResolveApiFailure;
|
|
247
|
+
type ResolveViaApiOptions = {
|
|
248
|
+
/** Defaults to the hosted endpoint, https://aturi.to/api/resolve. */
|
|
249
|
+
endpoint?: string;
|
|
250
|
+
/** Custom fetch implementation (e.g. a polyfill or instrumented client). */
|
|
251
|
+
fetch?: typeof fetch;
|
|
252
|
+
signal?: AbortSignal;
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* Typed client for the hosted resolve endpoint. Use this when you want the
|
|
256
|
+
* server to do the work — notably the <head> link probe, which needs to fetch
|
|
257
|
+
* the target page (something you may not want to do from the browser for CORS
|
|
258
|
+
* reasons). Returns the same response shape the route emits.
|
|
259
|
+
*/
|
|
260
|
+
declare function resolveViaApi(input: ResolveApiInput, options?: ResolveViaApiOptions): Promise<ResolveApiResponse>;
|
|
261
|
+
|
|
262
|
+
export { type BuildWaypointsOptions, CATEGORY_ORDER, COMPAT_FAMILIES, COMPAT_FAMILY_ORDER, type CategorizedWaypointsData, type CompatFamilyMeta, DID_REQUIRED_WAYPOINTS, type ParsedURI, type RedirectCompatFamily, type ResolveApiFailure, type ResolveApiInput, type ResolveApiParsed, type ResolveApiResponse, type ResolveApiSuccess, type ResolveResult, type ResolveUrlOptions, type ResolveViaApiOptions, type ResolvedRecommendation, type ResolvedWaypoint, type ReverseMatch, SUPPORTED_HOSTS, type SourceApp, WAYPOINT_CATEGORIES_DATA, WAYPOINT_DESTINATIONS_DATA, WAYPOINT_ORDER, type WaypointActivity, type WaypointCategoryData, type WaypointData, type WaypointType, buildWaypointsForParsed, getCategorizedWaypointsData, getDisplayName, getFeaturedWaypointData, getRecommendedWaypointsData, getWaypointCountData, getWaypointDataForType, matchSupportedUrl, parseAtUri, parseURI, resolveAtUri, resolveHandle, resolveUrl, resolveViaApi, waypointActivity };
|