social components inlay.at
atproto components sdui
86
fork

Configure Feed

Select the types of activity you want to include in your feed.

replace resolveImports with resolve

+32 -21
+9 -1
packages/@inlay/render/README.md
··· 52 52 async fetchRecord(uri) { return records[uri] ?? null; }, 53 53 async xrpc(params) { throw new Error(`No handler for ${params.nsid}`); }, 54 54 async resolveLexicon() { return null; }, 55 + async resolve(dids, collection, rkey) { 56 + for (const did of dids) { 57 + const uri = `at://${did}/${collection}/${rkey}`; 58 + const record = records[uri]; 59 + if (record) return { did, uri, record }; 60 + } 61 + return null; 62 + }, 55 63 }; 56 64 57 65 // Primitives → JSX ··· 160 168 161 169 ### Types 162 170 163 - - **`Resolver`** — `{ fetchRecord, xrpc, resolveLexicon }` 171 + - **`Resolver`** — `{ fetchRecord, xrpc, resolveLexicon, resolve }` 164 172 - **`RenderContext`** — `{ imports, component?, componentUri?, depth?, scope?, stack? }` 165 173 - **`RenderResult`** — `{ node, context, props, cache? }` 166 174 - **`RenderOptions`** — `{ resolver, maxDepth? }`
+1 -5
packages/@inlay/render/src/index.ts
··· 63 63 export type RenderOptions = { 64 64 resolver: Resolver; 65 65 maxDepth?: number; 66 - resolveImports?: (imports: DidString[], nsid: string) => DidString[]; 67 66 }; 68 67 69 68 /** ··· 194 193 throw Error("Component depth limit exceeded"); 195 194 } 196 195 197 - const effectiveImports = options.resolveImports 198 - ? options.resolveImports(ctx.imports, type) 199 - : ctx.imports; 200 196 const { component, componentUri } = await resolveType( 201 197 type, 202 - effectiveImports, 198 + ctx.imports, 203 199 resolver 204 200 ); 205 201 return await renderComponent(
+22 -15
packages/@inlay/render/test/render.test.ts
··· 1029 1029 }); 1030 1030 1031 1031 // ============================================================================ 1032 - // 3b. resolveImports — caller-controlled import filtering 1032 + // 3b. resolve overrides — host-controlled resolution filtering 1033 1033 // ============================================================================ 1034 1034 // 1035 - // The resolveImports option lets the host rewrite the import list before 1036 - // type resolution. It receives the component's imports and the NSID being 1037 - // resolved, and returns the DID list that should actually be searched. 1035 + // The host's resolve() method can filter or reorder DIDs per NSID. 1036 + // These tests verify that a custom resolve implementation can override 1037 + // which DID wins for specific NSIDs. 1038 1038 1039 - describe("resolveImports", () => { 1039 + describe("resolve overrides", () => { 1040 1040 const FANCY_DID = "did:plc:fancy"; 1041 1041 const CASUAL_DID = "did:plc:casual"; 1042 1042 ··· 1059 1059 }; 1060 1060 1061 1061 it("filters imports per NSID", async () => { 1062 - // Root imports both fancy and casual, but resolveImports drops fancy 1062 + // Root imports both fancy and casual, but resolve drops fancy 1063 1063 // for Greeting — so casual wins even though fancy is listed first. 1064 1064 const rootComponent: ComponentRecord = { 1065 1065 $type: "at.inlay.component", ··· 1077 1077 }; 1078 1078 1079 1079 const { options, log } = testResolver(records); 1080 - options.resolveImports = (imports, nsid) => { 1081 - if (nsid === Greeting) { 1082 - return imports.filter((d) => d !== FANCY_DID) as DidString[]; 1080 + const originalResolve = options.resolver.resolve; 1081 + options.resolver.resolve = async (dids, collection, rkey) => { 1082 + if (rkey === Greeting) { 1083 + return originalResolve( 1084 + dids.filter((d) => d !== FANCY_DID) as DidString[], 1085 + collection, 1086 + rkey 1087 + ); 1083 1088 } 1084 - return imports; 1089 + return originalResolve(dids, collection, rkey); 1085 1090 }; 1086 1091 1087 1092 const output = await renderToCompletion( ··· 1103 1108 1104 1109 it("can reroute a nested type without affecting its parent", async () => { 1105 1110 // Root's template renders Greeting, whose template renders Text. 1106 - // resolveImports only redirects Text to a different DID — Greeting 1111 + // resolve only redirects Text to a different DID — Greeting 1107 1112 // still resolves normally through casual, but Text picks up the 1108 1113 // alternate DID's implementation (a bold primitive instead of span). 1109 1114 const ALT_DID = "did:plc:alt"; ··· 1137 1142 }, 1138 1143 }); 1139 1144 1140 - options.resolveImports = (imports, nsid) => { 1145 + const originalResolve = options.resolver.resolve; 1146 + options.resolver.resolve = async (dids, collection, rkey) => { 1141 1147 // Only redirect Text resolution to alt DID 1142 - if (nsid === Text) return [ALT_DID] as DidString[]; 1143 - return imports; 1148 + if (rkey === Text) 1149 + return originalResolve([ALT_DID] as DidString[], collection, rkey); 1150 + return originalResolve(dids, collection, rkey); 1144 1151 }; 1145 1152 1146 1153 const output = await renderToCompletion( ··· 1175 1182 [`at://${CASUAL_DID}/at.inlay.component/${Greeting}`]: casualGreeting, 1176 1183 }); 1177 1184 1178 - // No resolveImports set — default behavior 1185 + // No override — default resolve behavior, first DID wins 1179 1186 const output = await renderToCompletion( 1180 1187 $(Root, {}), 1181 1188 options,