social components inlay-proto.up.railway.app/
atproto components sdui

restructure view to pull prop name out

+397 -289
+49 -33
generated/at/inlay/component.defs.ts
··· 27 27 | l.Unknown$TypedObject; 28 28 29 29 /** 30 - * What data types this component is a view for 30 + * What data this component views and which prop receives it 31 31 */ 32 - view?: ( 33 - | l.$Typed<ViewRecord> 34 - | l.$Typed<ViewPrimitive> 35 - | l.Unknown$TypedObject 36 - )[]; 32 + view?: View; 37 33 38 34 /** 39 35 * Ordered list of pack URIs (import stack). First pack that exports an NSID wins. ··· 70 66 false 71 67 ) 72 68 ), 73 - view: l.optional( 74 - l.array( 75 - l.typedUnion( 76 - [ 77 - l.typedRef<ViewRecord>((() => viewRecord) as any), 78 - l.typedRef<ViewPrimitive>((() => viewPrimitive) as any), 79 - ], 80 - false 81 - ) 82 - ) 83 - ), 69 + view: l.optional(l.ref<View>((() => view) as any)), 84 70 imports: l.optional(l.array(l.string({ format: "at-uri" }))), 85 71 via: l.optional( 86 72 l.typedUnion( ··· 151 137 152 138 export { bodyTemplate }; 153 139 154 - /** Component is a view for individual records of a collection. Omit collection for a generic record view. When rkey is present, the component accepts bare DIDs (expanded to full AT URIs) and appears on identity pages. */ 140 + /** Declares what data this component views and which prop receives it. */ 141 + type View = { 142 + $type?: "at.inlay.component#view"; 143 + 144 + /** 145 + * Which component prop receives the view data. 146 + */ 147 + prop: string; 148 + 149 + /** 150 + * Data types this view accepts. 151 + */ 152 + accepts: ( 153 + | l.$Typed<ViewRecord> 154 + | l.$Typed<ViewPrimitive> 155 + | l.Unknown$TypedObject 156 + )[]; 157 + }; 158 + 159 + export type { View }; 160 + 161 + /** Declares what data this component views and which prop receives it. */ 162 + const view = l.typedObject<View>( 163 + $nsid, 164 + "view", 165 + l.object({ 166 + prop: l.string({ maxLength: 256 }), 167 + accepts: l.array( 168 + l.typedUnion( 169 + [ 170 + l.typedRef<ViewRecord>((() => viewRecord) as any), 171 + l.typedRef<ViewPrimitive>((() => viewPrimitive) as any), 172 + ], 173 + false 174 + ), 175 + { minLength: 1 } 176 + ), 177 + }) 178 + ); 179 + 180 + export { view }; 181 + 182 + /** View accepts individual records of a collection. Omit collection for a generic record view. When rkey is present, the component accepts bare DIDs (expanded to full AT URIs) and appears on identity pages. */ 155 183 type ViewRecord = { 156 184 $type?: "at.inlay.component#viewRecord"; 157 185 ··· 164 192 * The record key, baked from the collection's lexicon at authoring time. Presence enables DID expansion and identity page routing. 165 193 */ 166 194 rkey?: string; 167 - 168 - /** 169 - * Which prop receives the AT URI. 170 - */ 171 - prop: string; 172 195 }; 173 196 174 197 export type { ViewRecord }; 175 198 176 - /** Component is a view for individual records of a collection. Omit collection for a generic record view. When rkey is present, the component accepts bare DIDs (expanded to full AT URIs) and appears on identity pages. */ 199 + /** View accepts individual records of a collection. Omit collection for a generic record view. When rkey is present, the component accepts bare DIDs (expanded to full AT URIs) and appears on identity pages. */ 177 200 const viewRecord = l.typedObject<ViewRecord>( 178 201 $nsid, 179 202 "viewRecord", 180 203 l.object({ 181 204 collection: l.optional(l.string({ format: "nsid" })), 182 205 rkey: l.optional(l.string({ maxLength: 512 })), 183 - prop: l.string({ maxLength: 256 }), 184 206 }) 185 207 ); 186 208 187 209 export { viewRecord }; 188 210 189 - /** Component is a view for a primitive value type. */ 211 + /** View accepts a primitive value type. */ 190 212 type ViewPrimitive = { 191 213 $type?: "at.inlay.component#viewPrimitive"; 192 214 ··· 218 240 | "record-key" 219 241 | "tid" 220 242 | l.UnknownString; 221 - 222 - /** 223 - * Which prop receives the value. 224 - */ 225 - prop: string; 226 243 }; 227 244 228 245 export type { ViewPrimitive }; 229 246 230 - /** Component is a view for a primitive value type. */ 247 + /** View accepts a primitive value type. */ 231 248 const viewPrimitive = l.typedObject<ViewPrimitive>( 232 249 $nsid, 233 250 "viewPrimitive", ··· 261 278 ]; 262 279 }>({ maxLength: 64 }) 263 280 ), 264 - prop: l.string({ maxLength: 256 }), 265 281 }) 266 282 ); 267 283
+27 -20
lexicons/at/inlay/component.json
··· 21 21 "description": "How this component is rendered. Omit for primitives rendered by the host." 22 22 }, 23 23 "view": { 24 - "type": "array", 25 - "items": { 26 - "type": "union", 27 - "refs": ["#viewRecord", "#viewPrimitive"] 28 - }, 29 - "description": "What data types this component is a view for" 24 + "type": "ref", 25 + "ref": "#view", 26 + "description": "What data this component views and which prop receives it" 30 27 }, 31 28 "imports": { 32 29 "type": "array", ··· 81 78 } 82 79 } 83 80 }, 81 + "view": { 82 + "type": "object", 83 + "description": "Declares what data this component views and which prop receives it.", 84 + "required": ["prop", "accepts"], 85 + "properties": { 86 + "prop": { 87 + "type": "string", 88 + "maxLength": 256, 89 + "description": "Which component prop receives the view data." 90 + }, 91 + "accepts": { 92 + "type": "array", 93 + "minLength": 1, 94 + "items": { 95 + "type": "union", 96 + "refs": ["#viewRecord", "#viewPrimitive"] 97 + }, 98 + "description": "Data types this view accepts." 99 + } 100 + } 101 + }, 84 102 "viewRecord": { 85 103 "type": "object", 86 - "description": "Component is a view for individual records of a collection. Omit collection for a generic record view. When rkey is present, the component accepts bare DIDs (expanded to full AT URIs) and appears on identity pages.", 87 - "required": ["prop"], 104 + "description": "View accepts individual records of a collection. Omit collection for a generic record view. When rkey is present, the component accepts bare DIDs (expanded to full AT URIs) and appears on identity pages.", 88 105 "properties": { 89 106 "collection": { 90 107 "type": "string", ··· 95 112 "type": "string", 96 113 "maxLength": 512, 97 114 "description": "The record key, baked from the collection's lexicon at authoring time. Presence enables DID expansion and identity page routing." 98 - }, 99 - "prop": { 100 - "type": "string", 101 - "maxLength": 256, 102 - "description": "Which prop receives the AT URI." 103 115 } 104 116 } 105 117 }, 106 118 "viewPrimitive": { 107 119 "type": "object", 108 - "description": "Component is a view for a primitive value type.", 109 - "required": ["type", "prop"], 120 + "description": "View accepts a primitive value type.", 121 + "required": ["type"], 110 122 "properties": { 111 123 "type": { 112 124 "type": "string", ··· 138 150 "record-key", 139 151 "tid" 140 152 ] 141 - }, 142 - "prop": { 143 - "type": "string", 144 - "maxLength": 256, 145 - "description": "Which prop receives the value." 146 153 } 147 154 } 148 155 }
+64 -43
packages/@inlay/render/src/index.ts
··· 18 18 } from "@atproto/syntax"; 19 19 import { validateProps } from "./validate.js"; 20 20 21 - import type { Main as ComponentRecord } from "../../../../generated/at/inlay/component.defs.js"; 21 + import type { 22 + Main as ComponentRecord, 23 + View, 24 + } from "../../../../generated/at/inlay/component.defs.js"; 22 25 import { viewRecord as viewRecordSchema } from "../../../../generated/at/inlay/component.defs.js"; 23 26 import type { Main as PackRecord } from "../../../../generated/at/inlay/pack.defs.js"; 24 27 import type { CachePolicy } from "../../../../generated/at/inlay/defs.defs.js"; ··· 205 208 export function resolvePath(obj: unknown, path: string[]): unknown { 206 209 let current: unknown = obj; 207 210 for (const seg of path) { 208 - if (current == null) return undefined; 211 + if (current == null) { 212 + return undefined; 213 + } 209 214 if (typeof current === "string") { 210 - if (!current.startsWith("at://")) return undefined; 215 + if (!current.startsWith("at://")) { 216 + return undefined; 217 + } 211 218 try { 212 219 const parsed = new AtUri(current); 213 220 const uriParts: Record<string, string> = { ··· 221 228 } 222 229 continue; 223 230 } 224 - if (typeof current !== "object") return undefined; 225 - if (!Object.hasOwn(current, seg)) return undefined; 231 + if (typeof current !== "object") { 232 + return undefined; 233 + } 234 + if (!Object.hasOwn(current, seg)) { 235 + return undefined; 236 + } 226 237 current = (current as Record<string, unknown>)[seg]; 227 238 } 228 239 return current; ··· 257 268 const type = element.type; 258 269 let resolvedProps = props; 259 270 if (component.view) { 260 - resolvedProps = expandBareDid(props, component); 271 + resolvedProps = expandBareDid(props, component.view); 261 272 } 262 273 263 274 if (validate) { ··· 295 306 296 307 for (let i = 0; i < importStack.length; i++) { 297 308 const pack = (await packPromises[i]) as PackRecord | null; 298 - if (!pack || !pack.exports) continue; 309 + if (!pack || !pack.exports) { 310 + continue; 311 + } 299 312 300 313 const entry = pack.exports.find((e) => e.type === nsid); 301 - if (!entry) continue; 314 + if (!entry) { 315 + continue; 316 + } 302 317 303 318 const component = (await resolver.fetchRecord( 304 319 entry.component 305 320 )) as ComponentRecord | null; 306 - if (!component) continue; 321 + if (!component) { 322 + continue; 323 + } 307 324 308 325 return { 309 326 componentUri: entry.component, ··· 353 370 let cache: CachePolicy | undefined; 354 371 355 372 // Find a matching viewRecord and resolve its AT URI prop 356 - const viewRecords = (component.view ?? []).filter((v) => 357 - viewRecordSchema.isTypeOf(v) 358 - ); 373 + if (component.view) { 374 + const { prop, accepts } = component.view; 375 + const viewRecords = accepts.filter((v) => viewRecordSchema.isTypeOf(v)); 359 376 360 - for (const vr of viewRecords) { 361 - const prop = vr.prop; 362 - const uri = props[prop] as string | undefined; 363 - if (!uri || !uri.startsWith("at://")) { 364 - continue; 377 + for (const vr of viewRecords) { 378 + const uri = props[prop] as string | undefined; 379 + if (!uri || !uri.startsWith("at://")) { 380 + continue; 381 + } 382 + const parsed = new AtUri(uri); 383 + ensureValidNsid(parsed.collection); 384 + if (!parsed.collection || !parsed.rkey) { 385 + continue; 386 + } 387 + if (vr.collection && vr.collection !== parsed.collection) { 388 + continue; 389 + } 390 + const built = await buildRecord( 391 + parsed.host, 392 + parsed.collection, 393 + parsed.rkey, 394 + tree, 395 + resolver 396 + ); 397 + scope = { props: slottedProps, record: built.record }; 398 + cache = built.cache; 399 + break; 365 400 } 366 - const parsed = new AtUri(uri); 367 - ensureValidNsid(parsed.collection); 368 - if (!parsed.collection || !parsed.rkey) { 369 - continue; 370 - } 371 - if (vr.collection && vr.collection !== parsed.collection) { 372 - continue; 373 - } 374 - const built = await buildRecord( 375 - parsed.host, 376 - parsed.collection, 377 - parsed.rkey, 378 - tree, 379 - resolver 380 - ); 381 - scope = { props: slottedProps, record: built.record }; 382 - cache = built.cache; 383 - break; 384 401 } 385 402 386 403 const node = resolveBindings(tree, scopeResolver(scope)); ··· 454 471 const refSlots = new Set<object>(); 455 472 const wireProps = serializeTree(props, (el) => { 456 473 if (el.type === "at.inlay.Slot") { 457 - if (refSlots.has(el)) return el; 474 + if (refSlots.has(el)) { 475 + return el; 476 + } 458 477 throw new Error("Unexpected Slot in props"); 459 478 } 460 479 const id = String(refs.size); ··· 511 530 512 531 function expandBareDid( 513 532 props: Record<string, unknown>, 514 - component: ComponentRecord 533 + view: View 515 534 ): Record<string, unknown> { 516 - const view = component.view!; 535 + const { prop, accepts } = view; 517 536 518 537 // Find the first viewRecord with both collection and rkey — that enables DID expansion 519 - const entry = view 538 + const entry = accepts 520 539 .filter((v) => viewRecordSchema.isTypeOf(v)) 521 540 .find((v) => v.collection && v.rkey); 522 - if (!entry) return props; 523 - 524 - const prop = entry.prop ?? "uri"; 541 + if (!entry) { 542 + return props; 543 + } 525 544 const value = props[prop] as string | undefined; 526 - if (!value || !value.startsWith("did:")) return props; 545 + if (!value || !value.startsWith("did:")) { 546 + return props; 547 + } 527 548 528 549 return { 529 550 ...props,
+43 -42
packages/@inlay/render/src/validate.ts
··· 11 11 12 12 const lexiconCache = new Map<string, Lexicons>(); 13 13 14 - // --- Helpers --- 15 - 16 - function getViewPrimitives(component: ComponentRecord) { 17 - return (component.view ?? []).filter((v) => viewPrimitiveSchema.isTypeOf(v)); 18 - } 19 - 20 - function getViewRecords(component: ComponentRecord) { 21 - return (component.view ?? []).filter((v) => viewRecordSchema.isTypeOf(v)); 22 - } 23 - 24 14 // --- Public API --- 25 15 26 16 export async function validateProps( ··· 37 27 lexiconCache.set(type, lexicons); 38 28 } 39 29 lexicons.assertValidXrpcInput(type, props); 40 - } else { 30 + } else if (component.view) { 41 31 // Synthesize validation from view entries (viewPrimitive + viewRecord) 42 - const primitives = getViewPrimitives(component); 43 - const records = getViewRecords(component); 32 + const { prop: viewProp, accepts } = component.view; 33 + const primitives = accepts.filter((v) => viewPrimitiveSchema.isTypeOf(v)); 34 + const records = accepts.filter((v) => viewRecordSchema.isTypeOf(v)); 44 35 45 36 if (primitives.length > 0 || records.length > 0) { 46 37 const propEntries = new Map< ··· 50 41 51 42 // viewPrimitive entries define typed props 52 43 for (const vp of primitives) { 53 - if (!vp.prop) continue; 54 - const existing = propEntries.get(vp.prop); 44 + const existing = propEntries.get(viewProp); 55 45 if (existing) { 56 46 if (vp.format) existing.formats.add(vp.format); 57 47 } else { 58 48 const formats = new Set<string>(); 59 49 if (vp.format) formats.add(vp.format); 60 - propEntries.set(vp.prop, { type: vp.type, formats }); 50 + propEntries.set(viewProp, { type: vp.type, formats }); 61 51 } 62 52 } 63 53 64 54 // viewRecord entries imply a string prop (at-uri or did format) 65 55 for (const vr of records) { 66 - const prop = vr.prop ?? "uri"; 67 - const existing = propEntries.get(prop); 56 + const existing = propEntries.get(viewProp); 68 57 if (existing) { 69 58 existing.formats.add("at-uri"); 70 59 if (vr.rkey) existing.formats.add("did"); 71 60 } else { 72 61 const formats = new Set<string>(["at-uri"]); 73 62 if (vr.rkey) formats.add("did"); 74 - propEntries.set(prop, { type: "string", formats }); 63 + propEntries.set(viewProp, { type: "string", formats }); 75 64 } 76 65 } 77 66 ··· 103 92 } 104 93 105 94 // Collection constraint checking from viewRecord entries 106 - const records = getViewRecords(component); 107 - if (records.length > 0) { 108 - const allowedCollections = new Map<string, Set<string>>(); 109 - for (const vr of records) { 110 - if (!vr.collection) continue; 111 - const prop = vr.prop ?? "uri"; 112 - let set = allowedCollections.get(prop); 113 - if (!set) { 114 - set = new Set(); 115 - allowedCollections.set(prop, set); 95 + if (component.view) { 96 + const { prop: collectionProp, accepts } = component.view; 97 + const records = accepts.filter((v) => viewRecordSchema.isTypeOf(v)); 98 + if (records.length > 0) { 99 + const allowedCollections = new Map<string, Set<string>>(); 100 + for (const vr of records) { 101 + if (!vr.collection) { 102 + continue; 103 + } 104 + let set = allowedCollections.get(collectionProp); 105 + if (!set) { 106 + set = new Set(); 107 + allowedCollections.set(collectionProp, set); 108 + } 109 + set.add(vr.collection); 116 110 } 117 - set.add(vr.collection); 118 - } 119 - for (const [prop, allowed] of allowedCollections) { 120 - const value = props[prop]; 121 - if (typeof value !== "string" || !value.startsWith("at://")) continue; 122 - const parsed = new AtUri(value); 123 - if (!parsed.collection) continue; 124 - if (!allowed.has(parsed.collection)) { 125 - throw new Error( 126 - `${type}: ${prop} expects ${[...allowed].join(" or ")}, got ${parsed.collection}` 127 - ); 111 + for (const [prop, allowed] of allowedCollections) { 112 + const value = props[prop]; 113 + if (typeof value !== "string" || !value.startsWith("at://")) { 114 + continue; 115 + } 116 + const parsed = new AtUri(value); 117 + if (!parsed.collection) { 118 + continue; 119 + } 120 + if (!allowed.has(parsed.collection)) { 121 + throw new Error( 122 + `${type}: ${prop} expects ${[...allowed].join(" or ")}, got ${parsed.collection}` 123 + ); 124 + } 128 125 } 129 126 } 130 127 } ··· 140 137 141 138 function unionFormats(formats: Set<string>): string | undefined { 142 139 const arr = [...formats]; 143 - if (arr.length <= 1) return arr[0]; 140 + if (arr.length <= 1) { 141 + return arr[0]; 142 + } 144 143 const ancestorSets = arr.map( 145 144 (f) => new Set([f, ...(FORMAT_ANCESTORS[f] ?? [])]) 146 145 ); 147 146 const common = [...ancestorSets[0]].filter((f) => 148 147 ancestorSets.every((s) => s.has(f)) 149 148 ); 150 - if (common.length === 0) return undefined; 149 + if (common.length === 0) { 150 + return undefined; 151 + } 151 152 if (common.length === 1) return common[0]; 152 153 return common.find( 153 154 (f) =>
+214 -151
packages/@inlay/render/test/render.test.ts
··· 758 758 ), 759 759 }, 760 760 imports: [HOST_PACK_URI], 761 - view: [ 762 - { 763 - $type: "at.inlay.component#viewRecord", 764 - prop: "uri", 765 - collection: "app.bsky.feed.post", 766 - }, 767 - ], 761 + view: { 762 + $type: "at.inlay.component#view", 763 + prop: "uri", 764 + accepts: [ 765 + { 766 + $type: "at.inlay.component#viewRecord", 767 + collection: "app.bsky.feed.post", 768 + }, 769 + ], 770 + }, 768 771 }; 769 772 770 773 const { options, log } = world({ ··· 816 819 ), 817 820 }, 818 821 imports: [HOST_PACK_URI], 819 - view: [ 820 - { 821 - $type: "at.inlay.component#viewRecord", 822 - prop: "uri", 823 - collection: "app.bsky.feed.post", 824 - }, 825 - ], 822 + view: { 823 + $type: "at.inlay.component#view", 824 + prop: "uri", 825 + accepts: [ 826 + { 827 + $type: "at.inlay.component#viewRecord", 828 + collection: "app.bsky.feed.post", 829 + }, 830 + ], 831 + }, 826 832 }; 827 833 828 834 const { options, log } = world({ ··· 869 875 ), 870 876 }, 871 877 imports: [HOST_PACK_URI], 872 - view: [ 873 - { 874 - $type: "at.inlay.component#viewRecord", 875 - prop: "uri", 876 - collection: "app.bsky.feed.post", 877 - }, 878 - ], 878 + view: { 879 + $type: "at.inlay.component#view", 880 + prop: "uri", 881 + accepts: [ 882 + { 883 + $type: "at.inlay.component#viewRecord", 884 + collection: "app.bsky.feed.post", 885 + }, 886 + ], 887 + }, 879 888 }; 880 889 881 890 const { options, log } = world({ ··· 1988 1997 ), 1989 1998 }, 1990 1999 imports: ["at://did:plc:test/at.inlay.pack/child"] as AtUriString[], 1991 - view: [ 1992 - { 1993 - $type: "at.inlay.component#viewRecord", 1994 - prop: "uri", 1995 - collection: "app.bsky.feed.post", 1996 - }, 1997 - ], 2000 + view: { 2001 + $type: "at.inlay.component#view", 2002 + prop: "uri", 2003 + accepts: [ 2004 + { 2005 + $type: "at.inlay.component#viewRecord", 2006 + collection: "app.bsky.feed.post", 2007 + }, 2008 + ], 2009 + }, 1998 2010 }; 1999 2011 2000 2012 const { options, log } = testResolver({ ··· 2211 2223 ), 2212 2224 }, 2213 2225 imports: [HOST_PACK_URI], 2214 - view: [ 2215 - { 2216 - $type: "at.inlay.component#viewRecord", 2217 - prop: "uri", 2218 - collection: "app.bsky.feed.post", 2219 - }, 2220 - ], 2226 + view: { 2227 + $type: "at.inlay.component#view", 2228 + prop: "uri", 2229 + accepts: [ 2230 + { 2231 + $type: "at.inlay.component#viewRecord", 2232 + collection: "app.bsky.feed.post", 2233 + }, 2234 + ], 2235 + }, 2221 2236 }; 2222 2237 2223 2238 const postUri = "at://did:plc:alice/app.bsky.feed.post/123"; ··· 2371 2386 ), 2372 2387 }, 2373 2388 imports: [HOST_PACK_URI], 2374 - view: [ 2375 - { 2376 - $type: "at.inlay.component#viewRecord", 2377 - prop: "uri", 2378 - collection: "app.bsky.feed.post", 2379 - }, 2380 - ], 2389 + view: { 2390 + $type: "at.inlay.component#view", 2391 + prop: "uri", 2392 + accepts: [ 2393 + { 2394 + $type: "at.inlay.component#viewRecord", 2395 + collection: "app.bsky.feed.post", 2396 + }, 2397 + ], 2398 + }, 2381 2399 }; 2382 2400 2383 2401 const postUri = "at://did:plc:alice/app.bsky.feed.post/123"; ··· 2520 2538 ), 2521 2539 }, 2522 2540 imports: [HOST_PACK_URI], 2523 - view: [ 2524 - { 2525 - $type: "at.inlay.component#viewRecord", 2526 - prop: "uri", 2527 - collection: "app.bsky.actor.profile", 2528 - rkey: "self", 2529 - }, 2530 - ], 2541 + view: { 2542 + $type: "at.inlay.component#view", 2543 + prop: "uri", 2544 + accepts: [ 2545 + { 2546 + $type: "at.inlay.component#viewRecord", 2547 + collection: "app.bsky.actor.profile", 2548 + rkey: "self", 2549 + }, 2550 + ], 2551 + }, 2531 2552 }; 2532 2553 2533 2554 const { options } = world({ ··· 2557 2578 ), 2558 2579 }, 2559 2580 imports: [HOST_PACK_URI], 2560 - view: [ 2561 - { 2562 - $type: "at.inlay.component#viewRecord", 2563 - prop: "uri", 2564 - collection: "app.bsky.actor.profile", 2565 - rkey: "main", 2566 - }, 2567 - ], 2581 + view: { 2582 + $type: "at.inlay.component#view", 2583 + prop: "uri", 2584 + accepts: [ 2585 + { 2586 + $type: "at.inlay.component#viewRecord", 2587 + collection: "app.bsky.actor.profile", 2588 + rkey: "main", 2589 + }, 2590 + ], 2591 + }, 2568 2592 }; 2569 2593 2570 2594 const { options } = world({ ··· 2594 2618 ), 2595 2619 }, 2596 2620 imports: [HOST_PACK_URI], 2597 - view: [ 2598 - { 2599 - $type: "at.inlay.component#viewRecord", 2600 - prop: "uri", 2601 - collection: "app.bsky.actor.profile", 2602 - rkey: "self", 2603 - }, 2604 - ], 2621 + view: { 2622 + $type: "at.inlay.component#view", 2623 + prop: "uri", 2624 + accepts: [ 2625 + { 2626 + $type: "at.inlay.component#viewRecord", 2627 + collection: "app.bsky.actor.profile", 2628 + rkey: "self", 2629 + }, 2630 + ], 2631 + }, 2605 2632 }; 2606 2633 2607 2634 const { options } = world({ ··· 2635 2662 ), 2636 2663 }, 2637 2664 imports: [HOST_PACK_URI], 2638 - view: [ 2639 - { 2640 - $type: "at.inlay.component#viewRecord", 2641 - prop: "uri", 2642 - collection: "app.bsky.feed.post", 2643 - }, 2644 - ], 2665 + view: { 2666 + $type: "at.inlay.component#view", 2667 + prop: "uri", 2668 + accepts: [ 2669 + { 2670 + $type: "at.inlay.component#viewRecord", 2671 + collection: "app.bsky.feed.post", 2672 + }, 2673 + ], 2674 + }, 2645 2675 }; 2646 2676 2647 2677 const { resolver } = world(); ··· 2729 2759 node: { $: "$", type: Text, props: {} }, 2730 2760 }, 2731 2761 imports: [HOST_PACK_URI], 2732 - view: [ 2733 - { 2734 - $type: "at.inlay.component#viewRecord", 2735 - prop: "uri", 2736 - collection: "app.bsky.feed.post", 2737 - }, 2738 - ], 2762 + view: { 2763 + $type: "at.inlay.component#view", 2764 + prop: "uri", 2765 + accepts: [ 2766 + { 2767 + $type: "at.inlay.component#viewRecord", 2768 + collection: "app.bsky.feed.post", 2769 + }, 2770 + ], 2771 + }, 2739 2772 }; 2740 2773 2741 2774 const { options } = world(); ··· 2765 2798 node: { $: "$", type: Text, props: {} }, 2766 2799 }, 2767 2800 imports: [HOST_PACK_URI], 2768 - view: [ 2769 - { 2770 - $type: "at.inlay.component#viewPrimitive", 2771 - type: "string", 2772 - format: "datetime", 2773 - prop: "value", 2774 - }, 2775 - ], 2801 + view: { 2802 + $type: "at.inlay.component#view", 2803 + prop: "value", 2804 + accepts: [ 2805 + { 2806 + $type: "at.inlay.component#viewPrimitive", 2807 + type: "string", 2808 + format: "datetime", 2809 + }, 2810 + ], 2811 + }, 2776 2812 }; 2777 2813 2778 2814 const { options } = world(); ··· 2802 2838 node: { $: "$", type: Text, props: {} }, 2803 2839 }, 2804 2840 imports: [HOST_PACK_URI], 2805 - view: [ 2806 - { 2807 - $type: "at.inlay.component#viewRecord", 2808 - prop: "uri", 2809 - collection: "app.bsky.feed.post", 2810 - }, 2811 - ], 2841 + view: { 2842 + $type: "at.inlay.component#view", 2843 + prop: "uri", 2844 + accepts: [ 2845 + { 2846 + $type: "at.inlay.component#viewRecord", 2847 + collection: "app.bsky.feed.post", 2848 + }, 2849 + ], 2850 + }, 2812 2851 }; 2813 2852 2814 2853 const { options } = world(); ··· 2898 2937 ), 2899 2938 }, 2900 2939 imports: [HOST_PACK_URI], 2901 - view: [ 2902 - { 2903 - $type: "at.inlay.component#viewRecord", 2904 - prop: "uri", 2905 - collection: "app.bsky.feed.post", 2906 - }, 2907 - ], 2940 + view: { 2941 + $type: "at.inlay.component#view", 2942 + prop: "uri", 2943 + accepts: [ 2944 + { 2945 + $type: "at.inlay.component#viewRecord", 2946 + collection: "app.bsky.feed.post", 2947 + }, 2948 + ], 2949 + }, 2908 2950 }; 2909 2951 2910 2952 const { options } = world({ ··· 2992 3034 ), 2993 3035 }, 2994 3036 imports: [HOST_PACK_URI], 2995 - view: [ 2996 - { 2997 - $type: "at.inlay.component#viewRecord", 2998 - prop: "uri", 2999 - collection: "app.bsky.feed.post", 3000 - }, 3001 - ], 3037 + view: { 3038 + $type: "at.inlay.component#view", 3039 + prop: "uri", 3040 + accepts: [ 3041 + { 3042 + $type: "at.inlay.component#viewRecord", 3043 + collection: "app.bsky.feed.post", 3044 + }, 3045 + ], 3046 + }, 3002 3047 }; 3003 3048 3004 3049 const { options } = world({ ··· 3062 3107 ), 3063 3108 }, 3064 3109 imports: [HOST_PACK_URI], 3065 - view: [ 3066 - { 3067 - $type: "at.inlay.component#viewRecord", 3068 - prop: "uri", 3069 - collection: "app.bsky.feed.post", 3070 - }, 3071 - ], 3110 + view: { 3111 + $type: "at.inlay.component#view", 3112 + prop: "uri", 3113 + accepts: [ 3114 + { 3115 + $type: "at.inlay.component#viewRecord", 3116 + collection: "app.bsky.feed.post", 3117 + }, 3118 + ], 3119 + }, 3072 3120 }; 3073 3121 3074 3122 const { options } = world({ ··· 3146 3194 ), 3147 3195 }, 3148 3196 imports: [HOST_PACK_URI], 3149 - view: [ 3150 - { 3151 - $type: "at.inlay.component#viewRecord", 3152 - prop: "uri", 3153 - collection: "app.bsky.feed.post", 3154 - }, 3155 - ], 3197 + view: { 3198 + $type: "at.inlay.component#view", 3199 + prop: "uri", 3200 + accepts: [ 3201 + { 3202 + $type: "at.inlay.component#viewRecord", 3203 + collection: "app.bsky.feed.post", 3204 + }, 3205 + ], 3206 + }, 3156 3207 }; 3157 3208 3158 3209 const { options } = world({ ··· 3196 3247 HOST_PACK_URI, 3197 3248 "at://did:plc:test/at.inlay.pack/app", 3198 3249 ] as AtUriString[], 3199 - view: [ 3200 - { 3201 - $type: "at.inlay.component#viewRecord", 3202 - prop: "uri", 3203 - collection: "app.bsky.feed.post", 3204 - }, 3205 - ], 3250 + view: { 3251 + $type: "at.inlay.component#view", 3252 + prop: "uri", 3253 + accepts: [ 3254 + { 3255 + $type: "at.inlay.component#viewRecord", 3256 + collection: "app.bsky.feed.post", 3257 + }, 3258 + ], 3259 + }, 3206 3260 }; 3207 3261 3208 3262 const { options } = world({ ··· 3267 3321 HOST_PACK_URI, 3268 3322 "at://did:plc:test/at.inlay.pack/app", 3269 3323 ] as AtUriString[], 3270 - view: [ 3271 - { 3272 - $type: "at.inlay.component#viewRecord", 3273 - prop: "uri", 3274 - collection: "app.bsky.feed.post", 3275 - }, 3276 - ], 3324 + view: { 3325 + $type: "at.inlay.component#view", 3326 + prop: "uri", 3327 + accepts: [ 3328 + { 3329 + $type: "at.inlay.component#viewRecord", 3330 + collection: "app.bsky.feed.post", 3331 + }, 3332 + ], 3333 + }, 3277 3334 }; 3278 3335 3279 3336 const { options } = world({ ··· 3337 3394 HOST_PACK_URI, 3338 3395 "at://did:plc:test/at.inlay.pack/app", 3339 3396 ] as AtUriString[], 3340 - view: [ 3341 - { 3342 - $type: "at.inlay.component#viewRecord", 3343 - prop: "uri", 3344 - collection: "app.bsky.feed.post", 3345 - }, 3346 - ], 3397 + view: { 3398 + $type: "at.inlay.component#view", 3399 + prop: "uri", 3400 + accepts: [ 3401 + { 3402 + $type: "at.inlay.component#viewRecord", 3403 + collection: "app.bsky.feed.post", 3404 + }, 3405 + ], 3406 + }, 3347 3407 }; 3348 3408 3349 3409 const { options } = world({ ··· 3432 3492 HOST_PACK_URI, 3433 3493 "at://did:plc:test/at.inlay.pack/safe", 3434 3494 ] as AtUriString[], 3435 - view: [ 3436 - { 3437 - $type: "at.inlay.component#viewRecord", 3438 - prop: "uri", 3439 - collection: "app.bsky.feed.post", 3440 - }, 3441 - ], 3495 + view: { 3496 + $type: "at.inlay.component#view", 3497 + prop: "uri", 3498 + accepts: [ 3499 + { 3500 + $type: "at.inlay.component#viewRecord", 3501 + collection: "app.bsky.feed.post", 3502 + }, 3503 + ], 3504 + }, 3442 3505 }; 3443 3506 3444 3507 const { options } = world({