custom element for embedding Bluesky posts and feeds mary-ext.github.io/bluesky-embed
typescript npm bluesky atcute
7
fork

Configure Feed

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

docs: svelte-powered site

Mary 427bdd05 6d924089

+1556 -21
+24
packages/svelte-site/.gitignore
··· 1 + # Logs 2 + logs 3 + *.log 4 + npm-debug.log* 5 + yarn-debug.log* 6 + yarn-error.log* 7 + pnpm-debug.log* 8 + lerna-debug.log* 9 + 10 + node_modules 11 + dist 12 + dist-ssr 13 + *.local 14 + 15 + # Editor directories and files 16 + .vscode/* 17 + !.vscode/extensions.json 18 + .idea 19 + .DS_Store 20 + *.suo 21 + *.ntvs* 22 + *.njsproj 23 + *.sln 24 + *.sw?
+66
packages/svelte-site/README.md
··· 1 + # Svelte + TS + Vite 2 + 3 + This template should help get you started developing with Svelte and TypeScript in Vite. 4 + 5 + ## Recommended IDE Setup 6 + 7 + [VS Code](https://code.visualstudio.com/) + 8 + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). 9 + 10 + ## Need an official Svelte framework? 11 + 12 + Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy 13 + anywhere with its serverless-first approach and adapt to various platforms, with out of the box 14 + support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, 15 + Tailwind CSS, and more. 16 + 17 + ## Technical considerations 18 + 19 + **Why use this over SvelteKit?** 20 + 21 + - It brings its own routing solution which might not be preferable for some users. 22 + - It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. 23 + 24 + This template contains as little as possible to get started with Vite + TypeScript + Svelte, while 25 + taking into account the developer experience with regards to HMR and intellisense. It demonstrates 26 + capabilities on par with the other `create-vite` templates and is a good starting point for 27 + beginners dipping their toes into a Vite + Svelte project. 28 + 29 + Should you later need the extended capabilities and extensibility provided by SvelteKit, the 30 + template has been structured similarly to SvelteKit so that it is easy to migrate. 31 + 32 + **Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** 33 + 34 + Setting `compilerOptions.types` shuts out all other types not explicitly listed in the 35 + configuration. Using triple-slash references keeps the default TypeScript setting of accepting type 36 + information from the entire workspace, while also adding `svelte` and `vite/client` type 37 + information. 38 + 39 + **Why include `.vscode/extensions.json`?** 40 + 41 + Other templates indirectly recommend extensions via the README, but this file allows VS Code to 42 + prompt the user to install the recommended extension upon opening the project. 43 + 44 + **Why enable `allowJs` in the TS template?** 45 + 46 + While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not 47 + prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force 48 + `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase 49 + is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there 50 + are valid use cases in which a mixed codebase may be relevant. 51 + 52 + **Why is HMR not preserving my local component state?** 53 + 54 + HMR state preservation comes with a number of gotchas! It has been disabled by default in both 55 + `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read 56 + the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). 57 + 58 + If you have state that's important to retain within a component, consider creating an external store 59 + which would not be replaced by HMR. 60 + 61 + ```ts 62 + // store.ts 63 + // An extremely simple external store 64 + import { writable } from 'svelte/store'; 65 + export default writable(0); 66 + ```
+13
packages/svelte-site/index.html
··· 1 + <!doctype html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8" /> 5 + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 6 + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 + <title>Vite + Svelte + TS</title> 8 + </head> 9 + <body> 10 + <div id="app"></div> 11 + <script type="module" src="/src/main.ts"></script> 12 + </body> 13 + </html>
+30
packages/svelte-site/package.json
··· 1 + { 2 + "name": "svelte-site", 3 + "private": true, 4 + "version": "0.0.0", 5 + "type": "module", 6 + "scripts": { 7 + "dev": "vite", 8 + "build": "vite build", 9 + "preview": "vite preview", 10 + "check": "svelte-check --tsconfig ./tsconfig.json && tsc -p tsconfig.node.json", 11 + "publish": "pnpm run build && ./scripts/publish.sh" 12 + }, 13 + "dependencies": { 14 + "@atcute/bluesky": "^1.0.9", 15 + "@atcute/client": "^2.0.6", 16 + "bluesky-post-embed": "workspace:^", 17 + "bluesky-profile-card-embed": "workspace:^", 18 + "bluesky-profile-feed-embed": "workspace:^", 19 + "internal": "workspace:^" 20 + }, 21 + "devDependencies": { 22 + "@sveltejs/vite-plugin-svelte": "^5.0.1", 23 + "@tsconfig/svelte": "^5.0.4", 24 + "svelte": "^5.11.2", 25 + "svelte-check": "^4.1.1", 26 + "terser": "^5.37.0", 27 + "tslib": "^2.8.1", 28 + "vite": "^6.0.3" 29 + } 30 + }
+18
packages/svelte-site/scripts/publish.sh
··· 1 + #!/usr/bin/env bash 2 + 3 + set -euo pipefail 4 + 5 + if [[ -n $(git status --porcelain) ]]; then 6 + echo 'Working directory is not clean' 7 + git status --short 8 + exit 1 9 + fi 10 + 11 + GIT_COMMIT=$(git rev-parse HEAD) 12 + 13 + rsync -aHAX --delete --exclude=.git --exclude=.nojekyll dist/ pages/ 14 + touch pages/.nojekyll 15 + 16 + git -C pages/ add . 17 + git -C pages/ commit -m "deploy: ${GIT_COMMIT}" 18 + git -C pages/ push
+159
packages/svelte-site/src/App.svelte
··· 1 + <script lang="ts" module> 2 + const PostDisplay = () => import('./components/display/PostDisplay.svelte'); 3 + const ProfileCardDisplay = () => import('./components/display/ProfileCardDisplay.svelte'); 4 + const ProfileFeedDisplay = () => import('./components/display/ProfileFeedDisplay.svelte'); 5 + </script> 6 + 7 + <script lang="ts"> 8 + import { extract_url } from './lib/matcher'; 9 + 10 + import Banner from './components/Banner.svelte'; 11 + import CircularSpinner from './components/CircularSpinner.svelte'; 12 + import Field from './components/Field.svelte'; 13 + import Lazy from './components/Lazy.svelte'; 14 + import TextInput from './components/TextInput.svelte'; 15 + 16 + const DEFAULT_URL = 'https://bsky.app/profile/did:plc:ragtjsm2j2vknwkz3zp4oxrd/post/3kj2umze7zj2n'; 17 + // const DEFAULT_URL = 'https://bsky.app/profile/did:plc:ragtjsm2j2vknwkz3zp4oxrd'; 18 + 19 + let url = $state(''); 20 + let profile_type = $state<'card' | 'feed'>('feed'); 21 + 22 + const matched = $derived(extract_url(url || DEFAULT_URL)); 23 + </script> 24 + 25 + <div class="app"> 26 + <h1 class="header"> 27 + <code>&lt;bluesky-embed&gt;</code> 28 + </h1> 29 + 30 + <Field label="Bluesky post or profile URL"> 31 + <TextInput type="url" bind:value={url} placeholder={DEFAULT_URL} /> 32 + </Field> 33 + 34 + {#if matched && matched.type === 'profile'} 35 + <fieldset class="choices"> 36 + <label class="choice"> 37 + <input type="radio" name="profile-type" value="feed" bind:group={profile_type} /> 38 + <span>Profile feed</span> 39 + </label> 40 + 41 + <label class="choice"> 42 + <input type="radio" name="profile-type" value="card" bind:group={profile_type} /> 43 + <span>Profile card</span> 44 + </label> 45 + </fieldset> 46 + {/if} 47 + 48 + <main class="main"> 49 + {#if !matched} 50 + <Banner type="alert">Invalid URL, did you type it correctly?</Banner> 51 + {:else if matched.type === 'post'} 52 + <Lazy loader={PostDisplay} fallback={LazyFallback} boundary={LazyBoundary}> 53 + {#snippet children(Component)} 54 + <Component {matched} /> 55 + {/snippet} 56 + </Lazy> 57 + {:else if matched.type === 'profile'} 58 + <Lazy 59 + loader={profile_type === 'card' ? ProfileCardDisplay : ProfileFeedDisplay} 60 + fallback={LazyFallback} 61 + boundary={LazyBoundary} 62 + > 63 + {#snippet children(Component)} 64 + <Component {matched} /> 65 + {/snippet} 66 + </Lazy> 67 + {/if} 68 + </main> 69 + 70 + <footer class="footer"> 71 + <span> 72 + made with ❤️ by <a href="https://bsky.app/profile/did:plc:ia76kvnndjutgedggx2ibrem">@mary.my.id</a> 73 + </span> 74 + <span aria-hidden="true"> · </span> 75 + <span> 76 + <a href="https://github.com/mary-ext/bluesky-embed">source code</a> 77 + </span> 78 + <span aria-hidden="true"> · </span> 79 + <span>MIT License</span> 80 + </footer> 81 + </div> 82 + 83 + {#snippet LazyFallback()} 84 + <CircularSpinner /> 85 + {/snippet} 86 + 87 + {#snippet LazyBoundary(err: unknown)} 88 + <Banner type="alert"> 89 + {'' + err} 90 + </Banner> 91 + {/snippet} 92 + 93 + <style> 94 + .app { 95 + margin: 0 auto; 96 + padding: 36px 16px; 97 + width: 100%; 98 + max-width: calc(550px + (16 * 2px)); 99 + } 100 + 101 + .header { 102 + margin: 24px 0; 103 + } 104 + 105 + .main { 106 + margin: 36px 0; 107 + } 108 + 109 + .choices { 110 + display: flex; 111 + flex-direction: column; 112 + gap: 8px; 113 + margin: 16px 0 36px 0; 114 + border: 0; 115 + padding: 0; 116 + } 117 + .choice { 118 + display: flex; 119 + align-items: center; 120 + gap: 8px; 121 + font-size: 0.875rem; 122 + line-height: 1.25rem; 123 + 124 + input { 125 + appearance: none; 126 + outline: 2px none #2563eb; 127 + outline-offset: 2px; 128 + border: 1px solid #9ca3af; 129 + border-radius: 8px; 130 + width: 16px; 131 + height: 16px; 132 + 133 + &:checked { 134 + border: 0; 135 + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); 136 + background-color: #2563eb; 137 + } 138 + &:focus { 139 + outline-style: solid; 140 + } 141 + } 142 + } 143 + 144 + .footer { 145 + display: flex; 146 + flex-wrap: wrap; 147 + gap: 0.5rem; 148 + margin: 36px 0 0 0; 149 + border-top: 1px solid #d1d5db; 150 + padding: 36px 0 0 0; 151 + color: #4b5563; 152 + font-size: 0.875rem; 153 + line-height: 1.25rem; 154 + 155 + a { 156 + color: #2563eb; 157 + } 158 + } 159 + </style>
+42
packages/svelte-site/src/components/Banner.svelte
··· 1 + <script lang="ts"> 2 + import type { Snippet } from 'svelte'; 3 + 4 + interface Props { 5 + type: 'alert' | 'inform'; 6 + children: Snippet<[]>; 7 + } 8 + 9 + let { type, children }: Props = $props(); 10 + </script> 11 + 12 + <div class="banner" class:type-alert={type === 'alert'} class:type-inform={type === 'inform'}> 13 + {@render children()} 14 + </div> 15 + 16 + <style> 17 + .banner { 18 + border: 1px solid; 19 + border-radius: 4px; 20 + padding: 10px 12px; 21 + font-weight: 500; 22 + font-size: 0.875rem; 23 + line-height: 1.25rem; 24 + 25 + :global(a) { 26 + color: inherit; 27 + font-weight: 600; 28 + } 29 + } 30 + 31 + .type-alert { 32 + border-color: #fca5a5; 33 + background: #fee2e2; 34 + color: #991b1b; 35 + } 36 + 37 + .type-inform { 38 + border-color: #bfdbfe; 39 + background: #dbeafe; 40 + color: #1e40af; 41 + } 42 + </style>
+42
packages/svelte-site/src/components/CircularSpinner.svelte
··· 1 + <script lang="ts"> 2 + interface Props {} 3 + 4 + let {}: Props = $props(); 5 + </script> 6 + 7 + <svg viewBox="0 0 32 32" class="circular-spinner"> 8 + <circle cx="16" cy="16" fill="none" r="14" stroke-width="4" class="background" /> 9 + <circle 10 + cx="16" 11 + cy="16" 12 + fill="none" 13 + r="14" 14 + stroke-width="4" 15 + stroke-dasharray="80px" 16 + stroke-dashoffset="60px" 17 + class="accented" 18 + /> 19 + </svg> 20 + 21 + <style> 22 + .circular-spinner { 23 + display: block; 24 + animation: spin 1s linear infinite; 25 + margin: 0 auto; 26 + width: 24px; 27 + height: 24px; 28 + } 29 + @keyframes spin { 30 + to { 31 + transform: rotate(360deg); 32 + } 33 + } 34 + 35 + .accented { 36 + stroke: #2563eb; 37 + } 38 + .background { 39 + stroke: #2563eb; 40 + opacity: 20%; 41 + } 42 + </style>
+100
packages/svelte-site/src/components/CodeBlock.svelte
··· 1 + <script lang="ts"> 2 + interface Props { 3 + code: string; 4 + } 5 + 6 + let { code }: Props = $props(); 7 + </script> 8 + 9 + <div class="code-block"> 10 + <pre><code>{code}</code></pre> 11 + 12 + <div class="actions"> 13 + <button 14 + title="Copy" 15 + aria-label="Copy" 16 + class="action-button" 17 + onclick={() => { 18 + navigator.clipboard.writeText(code).catch(() => alert(`Failed to copy to clipboard`)); 19 + }} 20 + > 21 + <svg class="icon" fill="none" viewBox="0 0 24 24"> 22 + <path 23 + stroke="currentColor" 24 + stroke-linecap="square" 25 + stroke-width="2" 26 + d="M15 5h4v16H5V5h4m0-2h6v4H9V3Z" 27 + /> 28 + </svg> 29 + </button> 30 + </div> 31 + </div> 32 + 33 + <style> 34 + .code-block { 35 + display: flex; 36 + gap: 12px; 37 + border: 1px solid #d1d5db; 38 + border-radius: 4px; 39 + background: #f9fafb; 40 + padding: 12px; 41 + overflow: hidden; 42 + overflow-x: auto; 43 + 44 + pre { 45 + flex-grow: 1; 46 + margin: 0; 47 + font-size: 0.75rem; 48 + line-height: 1.25rem; 49 + } 50 + } 51 + 52 + .actions { 53 + position: sticky; 54 + top: 0; 55 + right: 0; 56 + } 57 + .action-button { 58 + display: flex; 59 + justify-content: center; 60 + align-items: center; 61 + cursor: pointer; 62 + box-shadow: 63 + 0 1px 3px 0 rgb(0 0 0 / 0.1), 64 + 0 1px 2px -1px rgb(0 0 0 / 0.1); 65 + border: 1px solid #d1d5db; 66 + border-radius: 4px; 67 + background: #ffffff; 68 + padding: 0; 69 + width: 32px; 70 + height: 32px; 71 + color: #4b5563; 72 + 73 + @media (pointer: fine) { 74 + opacity: 0; 75 + transition: 75ms ease-in; 76 + 77 + .code-block:hover &, 78 + .code-block:focus-within & { 79 + opacity: 1; 80 + } 81 + 82 + &:hover { 83 + border-color: #9ca3af; 84 + background: #e5e7eb; 85 + color: #1f2937; 86 + } 87 + } 88 + 89 + &:active { 90 + border-color: #9ca3af; 91 + background: #e5e7eb; 92 + color: #1f2937; 93 + } 94 + } 95 + 96 + .icon { 97 + width: 16px; 98 + height: 16px; 99 + } 100 + </style>
+36
packages/svelte-site/src/components/Field.svelte
··· 1 + <script lang="ts"> 2 + import type { Snippet } from 'svelte'; 3 + 4 + interface Props { 5 + label: string; 6 + children: Snippet; 7 + } 8 + 9 + let { label, children }: Props = $props(); 10 + </script> 11 + 12 + <div class="field"> 13 + <label class="input-wrapper"> 14 + <span class="label">{label}</span> 15 + {@render children()} 16 + </label> 17 + </div> 18 + 19 + <style> 20 + .field { 21 + display: flex; 22 + flex-direction: column; 23 + gap: 8px; 24 + } 25 + 26 + .input-wrapper { 27 + display: contents; 28 + } 29 + 30 + .label { 31 + color: #4b5563; 32 + font-weight: 600; 33 + font-size: 0.875rem; 34 + line-height: 1.25rem; 35 + } 36 + </style>
+37
packages/svelte-site/src/components/Lazy.svelte
··· 1 + <script lang="ts" module> 2 + import type { Snippet, Component } from 'svelte'; 3 + 4 + type SvelteComponentModule<C extends Component = Component> = { default: C }; 5 + type LoaderFunction<C extends Component = Component> = () => Promise<SvelteComponentModule<C>>; 6 + 7 + const map = new WeakMap<LoaderFunction, Promise<Component>>(); 8 + const get_promise = <C extends Component>(fn: LoaderFunction<C>): Promise<C> => { 9 + let promise = map.get(fn) satisfies Promise<Component> | undefined; 10 + if (promise === undefined) { 11 + map.set(fn, (promise = fn().then((mod) => mod.default))); 12 + } 13 + 14 + return promise as Promise<C>; 15 + }; 16 + </script> 17 + 18 + <script lang="ts" generics="C extends Component<any>"> 19 + interface Props { 20 + loader: LoaderFunction<C>; 21 + children: Snippet<[component: C]>; 22 + fallback: Snippet<[]>; 23 + boundary: Snippet<[error: unknown]>; 24 + } 25 + 26 + let { loader, children, fallback, boundary }: Props = $props(); 27 + 28 + const promise = $derived(get_promise(loader)); 29 + </script> 30 + 31 + {#await promise} 32 + {@render fallback()} 33 + {:then component} 34 + {@render children(component)} 35 + {:catch err} 36 + {@render boundary(err)} 37 + {/await}
+30
packages/svelte-site/src/components/TextInput.svelte
··· 1 + <script lang="ts"> 2 + interface Props { 3 + type?: 'text' | 'url'; 4 + value?: string; 5 + placeholder?: string; 6 + } 7 + 8 + let { type, value = $bindable(), placeholder }: Props = $props(); 9 + </script> 10 + 11 + <input {type} {placeholder} bind:value class="text-input" /> 12 + 13 + <style> 14 + .text-input { 15 + outline: 2px none #2563eb; 16 + outline-offset: -1px; 17 + border: 1px solid #9ca3af; 18 + border-radius: 4px; 19 + padding: 8px 12px; 20 + font-size: 0.875rem; 21 + line-height: 1.25rem; 22 + 23 + &::placeholder { 24 + color: #9ca3af; 25 + } 26 + &:focus { 27 + outline-style: solid; 28 + } 29 + } 30 + </style>
+115
packages/svelte-site/src/components/display/PostDisplay.svelte
··· 1 + <script lang="ts"> 2 + import { onDestroy } from 'svelte'; 3 + 4 + import type { AppBskyFeedDefs, AppBskyFeedPost } from '@atcute/client/lexicons'; 5 + import { fetchPost as fetch_post } from 'bluesky-post-embed/core'; 6 + 7 + import { getPostUrl } from 'internal/utils/bsky-url.ts'; 8 + import { formatLongDate } from 'internal/utils/date.ts'; 9 + import { parseAtUri } from 'internal/utils/syntax/at-url.ts'; 10 + 11 + import { escape_html } from '../../lib/html'; 12 + import type { ExtractedPostInfo } from '../../lib/matcher'; 13 + 14 + import Banner from '../Banner.svelte'; 15 + import CircularSpinner from '../CircularSpinner.svelte'; 16 + import CodeBlock from '../CodeBlock.svelte'; 17 + import BlueskyPost from '../embeds/BlueskyPost.svelte'; 18 + import Guide from '../guides/Guide.svelte'; 19 + import GuideInstructions from '../guides/GuideInstructions.svelte'; 20 + 21 + interface Props { 22 + matched: ExtractedPostInfo; 23 + } 24 + 25 + let { matched }: Props = $props(); 26 + 27 + let controller: AbortController | undefined; 28 + const promise = $derived.by(() => { 29 + controller?.abort(); 30 + controller = new AbortController(); 31 + 32 + const signal = controller.signal; 33 + const uri = `at://${matched.author}/app.bsky.feed.post/${matched.rkey}`; 34 + 35 + return fetch_post({ uri, signal }); 36 + }); 37 + 38 + onDestroy(() => { 39 + controller?.abort(); 40 + }); 41 + 42 + const JSDELIVR_URL = `https://cdn.jsdelivr.net/npm/bluesky-post-embed@^1.0.0`; 43 + const get_prerequisite_markup = () => { 44 + return `<!-- Core web component and styling --> 45 + <script type="module" src="${JSDELIVR_URL}/+esm"></${'script'}> 46 + <link rel="stylesheet" href="${JSDELIVR_URL}/dist/core.min.css"> 47 + 48 + <!-- Built-in themes --> 49 + <link rel="stylesheet" href="${JSDELIVR_URL}/themes/light.min.css" media="(prefers-color-scheme: light)"> 50 + <link rel="stylesheet" href="${JSDELIVR_URL}/themes/dim.min.css" media="(prefers-color-scheme: dark)"> 51 + 52 + <!-- Fallback/placeholder elements if JS script is taking a while to load or is failing --> 53 + <style> 54 + .bluesky-post-fallback { 55 + margin: 16px 0; 56 + border-left: 3px solid var(--divider); 57 + padding: 4px 8px; 58 + white-space: pre-wrap; 59 + overflow-wrap: break-word; 60 + } 61 + .bluesky-post-fallback p { 62 + margin: 0 0 8px 0; 63 + } 64 + </${'style'}> 65 + `; 66 + }; 67 + 68 + const get_markup = (post: AppBskyFeedDefs.PostView) => { 69 + const author = post.author; 70 + const record = post.record as AppBskyFeedPost.Record; 71 + 72 + return `<bluesky-post src="${escape_html(post.uri)}"> 73 + <blockquote class="bluesky-post-fallback"> 74 + <p dir="auto">${escape_html(record.text)}</p> 75 + — ${author.displayName?.trim() ? `${escape_html(author.displayName)} (@${escape_html(author.handle)})` : `@${escape_html(author.handle)}`} 76 + <a href="${escape_html(getPostUrl(author.did, parseAtUri(post.uri).rkey))}">${formatLongDate(post.indexedAt)}</a> 77 + </blockquote> 78 + </bluesky-post> 79 + `; 80 + }; 81 + </script> 82 + 83 + {#await promise} 84 + <CircularSpinner /> 85 + {:then data} 86 + <BlueskyPost {data} /> 87 + 88 + {#if data.thread} 89 + <Guide title="How do I embed this to my website?"> 90 + <Banner type="inform"> 91 + Doing server-side rendering? Check out examples for 92 + <a href="https://github.com/mary-ext/bluesky-embed-astro">Astro</a> and 93 + <a href="https://github.com/mary-ext/bluesky-embed-sveltekit">SvelteKit</a>. 94 + </Banner> 95 + 96 + <GuideInstructions> 97 + <li> 98 + <p> 99 + Insert the following scripts and stylesheets to the <code>&lt;head&gt;</code> of your website. 100 + </p> 101 + <CodeBlock code={get_prerequisite_markup()} /> 102 + </li> 103 + 104 + <li> 105 + <p>Insert the following markup in wherever you want the post to be.</p> 106 + <CodeBlock code={get_markup(data.thread.post)} /> 107 + </li> 108 + </GuideInstructions> 109 + </Guide> 110 + {/if} 111 + {:catch err} 112 + <Banner type="alert"> 113 + {'' + err} 114 + </Banner> 115 + {/await}
+93
packages/svelte-site/src/components/display/ProfileCardDisplay.svelte
··· 1 + <script lang="ts"> 2 + import { onDestroy } from 'svelte'; 3 + 4 + import type { AppBskyActorDefs } from '@atcute/client/lexicons'; 5 + import { fetchProfileCard as fetch_profile_card } from 'bluesky-profile-card-embed/core'; 6 + 7 + import { escape_html } from '../../lib/html'; 8 + import type { ExtractedProfileInfo } from '../../lib/matcher'; 9 + 10 + import Banner from '../Banner.svelte'; 11 + import CircularSpinner from '../CircularSpinner.svelte'; 12 + import CodeBlock from '../CodeBlock.svelte'; 13 + import BlueskyProfileCard from '../embeds/BlueskyProfileCard.svelte'; 14 + import Guide from '../guides/Guide.svelte'; 15 + import GuideInstructions from '../guides/GuideInstructions.svelte'; 16 + 17 + interface Props { 18 + matched: ExtractedProfileInfo; 19 + } 20 + 21 + let { matched }: Props = $props(); 22 + 23 + let controller: AbortController | undefined; 24 + const promise = $derived.by(() => { 25 + controller?.abort(); 26 + controller = new AbortController(); 27 + 28 + const signal = controller.signal; 29 + const actor = matched.actor; 30 + 31 + return fetch_profile_card({ actor, signal }); 32 + }); 33 + 34 + onDestroy(() => { 35 + controller?.abort(); 36 + }); 37 + 38 + const get_prerequisite_markup = () => { 39 + const JSDELIVR_URL = `https://cdn.jsdelivr.net/npm/bluesky-profile-card-embed@^1.0.0`; 40 + 41 + return `<!-- Core web component and styling --> 42 + <script type="module" src="${JSDELIVR_URL}/+esm"></${'script'}> 43 + <link rel="stylesheet" href="${JSDELIVR_URL}/dist/core.min.css"> 44 + 45 + <!-- Built-in themes --> 46 + <link rel="stylesheet" href="${JSDELIVR_URL}/themes/light.min.css" media="(prefers-color-scheme: light)"> 47 + <link rel="stylesheet" href="${JSDELIVR_URL}/themes/dim.min.css" media="(prefers-color-scheme: dark)"> 48 + `; 49 + }; 50 + 51 + const get_markup = (profile: AppBskyActorDefs.ProfileViewDetailed) => { 52 + const url = `https://bsky.app/profile/${profile.did}`; 53 + 54 + return `<bluesky-profile-card actor="${escape_html(profile.did)}"> 55 + <a target="_blank" href="${escape_html(url)}" class="bluesky-profile-card-fallback"> 56 + ${ 57 + profile.displayName?.trim() 58 + ? `Follow ${escape_html(profile.displayName)} (@${escape_html(profile.handle)}) on Bluesky` 59 + : `Follow @${escape_html(profile.handle)} on Bluesky` 60 + } 61 + </a> 62 + </bluesky-profile-card> 63 + `; 64 + }; 65 + </script> 66 + 67 + {#await promise} 68 + <CircularSpinner /> 69 + {:then data} 70 + <BlueskyProfileCard {data} /> 71 + 72 + {#if data.profile} 73 + <Guide title="How do I embed this to my website?"> 74 + <GuideInstructions> 75 + <li> 76 + <p> 77 + Insert the following scripts and stylesheets to the <code>&lt;head&gt;</code> of your website. 78 + </p> 79 + <CodeBlock code={get_prerequisite_markup()} /> 80 + </li> 81 + 82 + <li> 83 + <p>Insert the following markup in wherever you want the profile feed to be.</p> 84 + <CodeBlock code={get_markup(data.profile)} /> 85 + </li> 86 + </GuideInstructions> 87 + </Guide> 88 + {/if} 89 + {:catch err} 90 + <Banner type="alert"> 91 + {'' + err} 92 + </Banner> 93 + {/await}
+93
packages/svelte-site/src/components/display/ProfileFeedDisplay.svelte
··· 1 + <script lang="ts"> 2 + import { onDestroy } from 'svelte'; 3 + 4 + import type { AppBskyActorDefs } from '@atcute/client/lexicons'; 5 + import { fetchProfileFeed as fetch_profile_feed } from 'bluesky-profile-feed-embed/core'; 6 + 7 + import { escape_html } from '../../lib/html'; 8 + import type { ExtractedProfileInfo } from '../../lib/matcher'; 9 + 10 + import Banner from '../Banner.svelte'; 11 + import CircularSpinner from '../CircularSpinner.svelte'; 12 + import CodeBlock from '../CodeBlock.svelte'; 13 + import BlueskyProfileFeed from '../embeds/BlueskyProfileFeed.svelte'; 14 + import Guide from '../guides/Guide.svelte'; 15 + import GuideInstructions from '../guides/GuideInstructions.svelte'; 16 + 17 + interface Props { 18 + matched: ExtractedProfileInfo; 19 + } 20 + 21 + let { matched }: Props = $props(); 22 + 23 + let controller: AbortController | undefined; 24 + const promise = $derived.by(() => { 25 + controller?.abort(); 26 + controller = new AbortController(); 27 + 28 + const signal = controller.signal; 29 + const actor = matched.actor; 30 + 31 + return fetch_profile_feed({ actor, signal }); 32 + }); 33 + 34 + onDestroy(() => { 35 + controller?.abort(); 36 + }); 37 + 38 + const get_prerequisite_markup = () => { 39 + const JSDELIVR_URL = `https://cdn.jsdelivr.net/npm/bluesky-profile-feed-embed@^1.0.0`; 40 + 41 + return `<!-- Core web component and styling --> 42 + <script type="module" src="${JSDELIVR_URL}/+esm"></${'script'}> 43 + <link rel="stylesheet" href="${JSDELIVR_URL}/dist/core.min.css"> 44 + 45 + <!-- Built-in themes --> 46 + <link rel="stylesheet" href="${JSDELIVR_URL}/themes/light.min.css" media="(prefers-color-scheme: light)"> 47 + <link rel="stylesheet" href="${JSDELIVR_URL}/themes/dim.min.css" media="(prefers-color-scheme: dark)"> 48 + `; 49 + }; 50 + 51 + const get_markup = (profile: AppBskyActorDefs.ProfileViewDetailed) => { 52 + const url = `https://bsky.app/profile/${profile.did}`; 53 + 54 + return `<bluesky-profile-feed actor="${escape_html(profile.did)}" include-pins> 55 + <a target="_blank" href="${escape_html(url)}" class="bluesky-profile-feed-fallback"> 56 + ${ 57 + profile.displayName?.trim() 58 + ? `Posts by ${escape_html(profile.displayName)} (@${escape_html(profile.handle)})` 59 + : `Posts by @${escape_html(profile.handle)}` 60 + } 61 + </a> 62 + </bluesky-profile-feed> 63 + `; 64 + }; 65 + </script> 66 + 67 + {#await promise} 68 + <CircularSpinner /> 69 + {:then data} 70 + <BlueskyProfileFeed {data} /> 71 + 72 + {#if data.profile} 73 + <Guide title="How do I embed this to my website?"> 74 + <GuideInstructions> 75 + <li> 76 + <p> 77 + Insert the following scripts and stylesheets to the <code>&lt;head&gt;</code> of your website. 78 + </p> 79 + <CodeBlock code={get_prerequisite_markup()} /> 80 + </li> 81 + 82 + <li> 83 + <p>Insert the following markup in wherever you want the profile feed to be.</p> 84 + <CodeBlock code={get_markup(data.profile)} /> 85 + </li> 86 + </GuideInstructions> 87 + </Guide> 88 + {/if} 89 + {:catch err} 90 + <Banner type="alert"> 91 + {'' + err} 92 + </Banner> 93 + {/await}
+12
packages/svelte-site/src/components/embeds/BlueskyPost.svelte
··· 1 + <script lang="ts"> 2 + import { type PostData, renderPost } from 'bluesky-post-embed/core'; 3 + import 'bluesky-post-embed/style.css'; 4 + 5 + interface Props { 6 + data: PostData; 7 + } 8 + 9 + let { data }: Props = $props(); 10 + </script> 11 + 12 + <bluesky-post src={data.thread?.post.uri}>{@html renderPost(data)}</bluesky-post>
+12
packages/svelte-site/src/components/embeds/BlueskyProfileCard.svelte
··· 1 + <script lang="ts"> 2 + import { type ProfileCardData, renderProfileCard } from 'bluesky-profile-card-embed/core'; 3 + import 'bluesky-profile-card-embed/style.css'; 4 + 5 + interface Props { 6 + data: ProfileCardData; 7 + } 8 + 9 + let { data }: Props = $props(); 10 + </script> 11 + 12 + <bluesky-profile-card actor={data.profile?.did}>{@html renderProfileCard(data)}</bluesky-profile-card>
+12
packages/svelte-site/src/components/embeds/BlueskyProfileFeed.svelte
··· 1 + <script lang="ts"> 2 + import { type ProfileFeedData, renderProfileFeed } from 'bluesky-profile-feed-embed/core'; 3 + import 'bluesky-profile-feed-embed/style.css'; 4 + 5 + interface Props { 6 + data: ProfileFeedData; 7 + } 8 + 9 + let { data }: Props = $props(); 10 + </script> 11 + 12 + <bluesky-profile-feed actor={data.profile?.did}>{@html renderProfileFeed(data)}</bluesky-profile-feed>
+26
packages/svelte-site/src/components/guides/Guide.svelte
··· 1 + <script lang="ts"> 2 + import type { Snippet } from 'svelte'; 3 + 4 + interface Props { 5 + title: string; 6 + children: Snippet<[]>; 7 + } 8 + 9 + let { title, children }: Props = $props(); 10 + </script> 11 + 12 + <div class="guide"> 13 + <h4 class="guide-header">{title}</h4> 14 + 15 + {@render children()} 16 + </div> 17 + 18 + <style> 19 + .guide { 20 + margin: 36px 0 0 0; 21 + border-top: 1px solid #d1d5db; 22 + } 23 + .guide-header { 24 + margin: 36px 0 16px 0; 25 + } 26 + </style>
+26
packages/svelte-site/src/components/guides/GuideInstructions.svelte
··· 1 + <script lang="ts"> 2 + import type { Snippet } from 'svelte'; 3 + 4 + interface Props { 5 + children: Snippet<[]>; 6 + } 7 + 8 + let { children }: Props = $props(); 9 + </script> 10 + 11 + <ol class="guide-instructions"> 12 + {@render children()} 13 + </ol> 14 + 15 + <style> 16 + .guide-instructions { 17 + margin: 24px 0 0 0; 18 + padding: 0 0 0 22px; 19 + font-size: 0.875rem; 20 + line-height: 1.25rem; 21 + 22 + :global(li + li) { 23 + margin: 24px 0 0 0; 24 + } 25 + } 26 + </style>
+4
packages/svelte-site/src/lib/component.ts
··· 1 + let uid = 0; 2 + export const use_id = () => { 3 + return `s:${uid++}`; 4 + };
+3
packages/svelte-site/src/lib/html.ts
··· 1 + export const escape_html = (text: string): string => { 2 + return text.replace(/[<"&]/g, (c) => '&#' + c.charCodeAt(0) + ';'); 3 + };
+60
packages/svelte-site/src/lib/matcher.ts
··· 1 + import { is_at_identifier, is_tid } from './strings'; 2 + 3 + export interface ExtractedPostInfo { 4 + type: 'post'; 5 + author: string; 6 + rkey: string; 7 + } 8 + 9 + export interface ExtractedProfileInfo { 10 + type: 'profile'; 11 + actor: string; 12 + } 13 + 14 + export type ExtractedInfo = ExtractedPostInfo | ExtractedProfileInfo; 15 + 16 + export const extract_url = (str: string): ExtractedInfo | null => { 17 + const url = safe_parse_url(str); 18 + if (!url) { 19 + return null; 20 + } 21 + 22 + let match: RegExpExecArray | null | undefined; 23 + if (url.host === 'bsky.app' || url.host === 'staging.bsky.app' || url.host === 'main.bsky.dev') { 24 + if ((match = /^\/profile\/([^/]+)\/post\/([^/]+)\/?$/.exec(url.pathname))) { 25 + if (!is_at_identifier(match[1]) || !is_tid(match[2])) { 26 + return null; 27 + } 28 + 29 + return { type: 'post', author: match[1], rkey: match[2] }; 30 + } 31 + 32 + if ((match = /^\/profile\/([^/]+)\/?$/.exec(url.pathname))) { 33 + if (!is_at_identifier(match[1])) { 34 + return null; 35 + } 36 + 37 + return { type: 'profile', actor: match[1] }; 38 + } 39 + } 40 + 41 + return null; 42 + }; 43 + 44 + const safe_parse_url = (str: string): URL | null => { 45 + let url: URL | null | undefined; 46 + if ('parse' in URL) { 47 + url = URL.parse(str); 48 + } else { 49 + try { 50 + // @ts-expect-error: `'parse' in URL` is giving truthy 51 + url = new URL(str); 52 + } catch {} 53 + } 54 + 55 + if (url && (url.protocol === 'https:' || url.protocol === 'http:')) { 56 + return url; 57 + } 58 + 59 + return null; 60 + };
+28
packages/svelte-site/src/lib/strings.ts
··· 1 + export const RECORD_KEY_RE = /^(?!\.{1,2}$)[a-zA-Z0-9_~.:-]{1,512}$/; 2 + 3 + export const is_record_key = (str: string): boolean => { 4 + return str.length >= 1 && str.length <= 512 && RECORD_KEY_RE.test(str); 5 + }; 6 + 7 + export const TID_RE = /^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/; 8 + 9 + export const is_tid = (str: string): boolean => { 10 + return str.length === 13 && TID_RE.test(str); 11 + }; 12 + 13 + export const DID_RE = /^did:([a-z]+):([a-zA-Z0-9._:%-]*[a-zA-Z0-9._-])$/; 14 + 15 + export const is_did = (str: string): boolean => { 16 + return str.length >= 7 && str.length <= 2048 && DID_RE.test(str); 17 + }; 18 + 19 + export const HANDLE_RE = 20 + /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/; 21 + 22 + export const is_handle = (str: string): boolean => { 23 + return str.length >= 3 && str.length <= 253 && HANDLE_RE.test(str); 24 + }; 25 + 26 + export const is_at_identifier = (str: string): boolean => { 27 + return is_did(str) || is_handle(str); 28 + };
+10
packages/svelte-site/src/main.ts
··· 1 + import { mount } from 'svelte'; 2 + 3 + import './styles/normalize.css'; 4 + import 'bluesky-post-embed/themes/light.css'; 5 + 6 + import App from './App.svelte'; 7 + 8 + mount(App, { 9 + target: document.getElementById('app')!, 10 + });
+199
packages/svelte-site/src/styles/normalize.css
··· 1 + /*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */ 2 + 3 + /* 4 + Document 5 + ======== 6 + */ 7 + 8 + /** 9 + Use a better box model (opinionated). 10 + */ 11 + 12 + *, 13 + ::before, 14 + ::after { 15 + box-sizing: border-box; 16 + } 17 + 18 + html { 19 + line-height: 1.15; /* 1. Correct the line height in all browsers. */ 20 + /* Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) */ 21 + font-family: 'Inter', 'Roboto', ui-sans-serif, sans-serif, 'Noto Color Emoji', 'Twemoji Mozilla'; 22 + -webkit-text-size-adjust: 100%; /* 2. Prevent adjustments of font size after orientation changes in iOS. */ 23 + tab-size: 4; /* 3. Use a more readable tab size (opinionated). */ 24 + } 25 + 26 + /* 27 + Sections 28 + ======== 29 + */ 30 + 31 + body { 32 + margin: 0; /* Remove the margin in all browsers. */ 33 + } 34 + 35 + /* 36 + Text-level semantics 37 + ==================== 38 + */ 39 + 40 + /** 41 + Add the correct font weight in Chrome and Safari. 42 + */ 43 + 44 + b, 45 + strong { 46 + font-weight: bolder; 47 + } 48 + 49 + /** 50 + 1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) 51 + 2. Correct the odd 'em' font sizing in all browsers. 52 + */ 53 + 54 + code, 55 + kbd, 56 + samp, 57 + pre { 58 + font-size: 1em; /* 2 */ 59 + font-family: 'JetBrains Mono NL', ui-monospace, monospace; /* 1 */ 60 + } 61 + 62 + /** 63 + Add the correct font size in all browsers. 64 + */ 65 + 66 + small { 67 + font-size: 80%; 68 + } 69 + 70 + /** 71 + Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. 72 + */ 73 + 74 + sub, 75 + sup { 76 + position: relative; 77 + vertical-align: baseline; 78 + font-size: 75%; 79 + line-height: 0; 80 + } 81 + 82 + sub { 83 + bottom: -0.25em; 84 + } 85 + 86 + sup { 87 + top: -0.5em; 88 + } 89 + 90 + /* 91 + Tabular data 92 + ============ 93 + */ 94 + 95 + /** 96 + Correct table border color inheritance in Chrome and Safari. (https://issues.chromium.org/issues/40615503, https://bugs.webkit.org/show_bug.cgi?id=195016) 97 + */ 98 + 99 + table { 100 + border-color: currentcolor; 101 + } 102 + 103 + /* 104 + Forms 105 + ===== 106 + */ 107 + 108 + /** 109 + 1. Change the font styles in all browsers. 110 + 2. Remove the margin in Firefox and Safari. 111 + */ 112 + 113 + button, 114 + input, 115 + optgroup, 116 + select, 117 + textarea { 118 + margin: 0; /* 2 */ 119 + font-size: 100%; /* 1 */ 120 + line-height: 1.15; /* 1 */ 121 + font-family: inherit; /* 1 */ 122 + } 123 + 124 + /** 125 + Correct the inability to style clickable types in iOS and Safari. 126 + */ 127 + 128 + button, 129 + [type='button'], 130 + [type='reset'], 131 + [type='submit'] { 132 + -webkit-appearance: button; 133 + } 134 + 135 + /** 136 + Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. 137 + */ 138 + 139 + legend { 140 + padding: 0; 141 + } 142 + 143 + /** 144 + Add the correct vertical alignment in Chrome and Firefox. 145 + */ 146 + 147 + progress { 148 + vertical-align: baseline; 149 + } 150 + 151 + /** 152 + Correct the cursor style of increment and decrement buttons in Safari. 153 + */ 154 + 155 + ::-webkit-inner-spin-button, 156 + ::-webkit-outer-spin-button { 157 + height: auto; 158 + } 159 + 160 + /** 161 + 1. Correct the odd appearance in Chrome and Safari. 162 + 2. Correct the outline style in Safari. 163 + */ 164 + 165 + [type='search'] { 166 + -webkit-appearance: textfield; /* 1 */ 167 + outline-offset: -2px; /* 2 */ 168 + } 169 + 170 + /** 171 + Remove the inner padding in Chrome and Safari on macOS. 172 + */ 173 + 174 + ::-webkit-search-decoration { 175 + -webkit-appearance: none; 176 + } 177 + 178 + /** 179 + 1. Correct the inability to style clickable types in iOS and Safari. 180 + 2. Change font properties to 'inherit' in Safari. 181 + */ 182 + 183 + ::-webkit-file-upload-button { 184 + -webkit-appearance: button; /* 1 */ 185 + font: inherit; /* 2 */ 186 + } 187 + 188 + /* 189 + Interactive 190 + =========== 191 + */ 192 + 193 + /* 194 + Add the correct display in Chrome and Safari. 195 + */ 196 + 197 + summary { 198 + display: list-item; 199 + }
+2
packages/svelte-site/src/vite-env.d.ts
··· 1 + /// <reference types="svelte" /> 2 + /// <reference types="vite/client" />
+7
packages/svelte-site/svelte.config.js
··· 1 + import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 2 + 3 + export default { 4 + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 5 + // for more information about preprocessors 6 + preprocess: vitePreprocess(), 7 + };
+21
packages/svelte-site/tsconfig.json
··· 1 + { 2 + "extends": "@tsconfig/svelte/tsconfig.json", 3 + "compilerOptions": { 4 + "target": "ESNext", 5 + "useDefineForClassFields": true, 6 + "module": "ESNext", 7 + "resolveJsonModule": true, 8 + /** 9 + * Typecheck JS in `.svelte` and `.js` files by default. 10 + * Disable checkJs if you'd like to use dynamic types in JS. 11 + * Note that setting allowJs false does not prevent the use 12 + * of JS in `.svelte` files. 13 + */ 14 + "allowJs": true, 15 + "checkJs": true, 16 + "isolatedModules": true, 17 + "moduleDetection": "force", 18 + }, 19 + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], 20 + "references": [{ "path": "./tsconfig.node.json" }], 21 + }
+13
packages/svelte-site/tsconfig.node.json
··· 1 + { 2 + "compilerOptions": { 3 + "composite": true, 4 + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 + "skipLibCheck": true, 6 + "module": "ESNext", 7 + "moduleResolution": "bundler", 8 + "strict": true, 9 + "noEmit": true, 10 + "noUncheckedSideEffectImports": true, 11 + }, 12 + "include": ["vite.config.ts"], 13 + }
+14
packages/svelte-site/vite.config.ts
··· 1 + import { defineConfig } from 'vite'; 2 + import { svelte } from '@sveltejs/vite-plugin-svelte'; 3 + 4 + // https://vite.dev/config/ 5 + export default defineConfig({ 6 + build: { 7 + target: 'esnext', 8 + minify: 'terser', 9 + }, 10 + esbuild: { 11 + target: 'esnext', 12 + }, 13 + plugins: [svelte()], 14 + });
+208 -21
pnpm-lock.yaml
··· 27 27 version: 2.1.2(postcss@8.4.49)(prettier@3.4.2) 28 28 prettier-plugin-svelte: 29 29 specifier: ^3.3.2 30 - version: 3.3.2(prettier@3.4.2)(svelte@5.8.1(patch_hash=6qynve6ufonlwufsl6x7wujmdu)) 30 + version: 3.3.2(prettier@3.4.2)(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu)) 31 31 typescript: 32 32 specifier: ^5.7.2 33 33 version: 5.7.2 ··· 46 46 devDependencies: 47 47 '@preact/preset-vite': 48 48 specifier: ^2.9.3 49 - version: 2.9.3(@babel/core@7.26.0)(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)) 49 + version: 2.9.3(@babel/core@7.26.0)(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 50 50 '@tsconfig/svelte': 51 51 specifier: ^5.0.4 52 52 version: 5.0.4 ··· 67 67 version: 4.1.1(picomatch@4.0.2)(svelte@5.8.1(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(typescript@5.7.2) 68 68 vite: 69 69 specifier: ^6.0.3 70 - version: 6.0.3(@types/node@22.10.1) 70 + version: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 71 71 vite-plugin-dts: 72 72 specifier: ^4.3.0 73 - version: 4.3.0(@types/node@22.10.1)(rollup@4.28.1)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)) 73 + version: 4.3.0(@types/node@22.10.1)(rollup@4.28.1)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 74 74 75 75 packages/bluesky-profile-card-embed: 76 76 dependencies: ··· 86 86 devDependencies: 87 87 '@preact/preset-vite': 88 88 specifier: ^2.9.3 89 - version: 2.9.3(@babel/core@7.26.0)(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)) 89 + version: 2.9.3(@babel/core@7.26.0)(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 90 90 '@tsconfig/svelte': 91 91 specifier: ^5.0.4 92 92 version: 5.0.4 ··· 107 107 version: 4.1.1(picomatch@4.0.2)(svelte@5.8.1(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(typescript@5.7.2) 108 108 vite: 109 109 specifier: ^6.0.3 110 - version: 6.0.3(@types/node@22.10.1) 110 + version: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 111 111 vite-plugin-dts: 112 112 specifier: ^4.3.0 113 - version: 4.3.0(@types/node@22.10.1)(rollup@4.28.1)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)) 113 + version: 4.3.0(@types/node@22.10.1)(rollup@4.28.1)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 114 114 115 115 packages/bluesky-profile-feed-embed: 116 116 dependencies: ··· 141 141 version: 4.1.1(picomatch@4.0.2)(svelte@5.8.1(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(typescript@5.7.2) 142 142 vite: 143 143 specifier: ^6.0.3 144 - version: 6.0.3(@types/node@22.10.1) 144 + version: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 145 145 vite-plugin-dts: 146 146 specifier: ^4.3.0 147 - version: 4.3.0(@types/node@22.10.1)(rollup@4.28.1)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)) 147 + version: 4.3.0(@types/node@22.10.1)(rollup@4.28.1)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 148 148 149 149 packages/internal: 150 150 devDependencies: ··· 187 187 devDependencies: 188 188 '@preact/preset-vite': 189 189 specifier: ^2.9.3 190 - version: 2.9.3(@babel/core@7.26.0)(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)) 190 + version: 2.9.3(@babel/core@7.26.0)(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 191 + vite: 192 + specifier: ^6.0.3 193 + version: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 194 + 195 + packages/svelte-site: 196 + dependencies: 197 + '@atcute/bluesky': 198 + specifier: ^1.0.9 199 + version: 1.0.9(@atcute/client@2.0.6) 200 + '@atcute/client': 201 + specifier: ^2.0.6 202 + version: 2.0.6 203 + bluesky-post-embed: 204 + specifier: workspace:^ 205 + version: link:../bluesky-post-embed 206 + bluesky-profile-card-embed: 207 + specifier: workspace:^ 208 + version: link:../bluesky-profile-card-embed 209 + bluesky-profile-feed-embed: 210 + specifier: workspace:^ 211 + version: link:../bluesky-profile-feed-embed 212 + internal: 213 + specifier: workspace:^ 214 + version: link:../internal 215 + devDependencies: 216 + '@sveltejs/vite-plugin-svelte': 217 + specifier: ^5.0.1 218 + version: 5.0.1(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 219 + '@tsconfig/svelte': 220 + specifier: ^5.0.4 221 + version: 5.0.4 222 + svelte: 223 + specifier: ^5.11.2 224 + version: 5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu) 225 + svelte-check: 226 + specifier: ^4.1.1 227 + version: 4.1.1(picomatch@4.0.2)(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(typescript@5.7.2) 228 + terser: 229 + specifier: ^5.37.0 230 + version: 5.37.0 231 + tslib: 232 + specifier: ^2.8.1 233 + version: 2.8.1 191 234 vite: 192 235 specifier: ^6.0.3 193 - version: 6.0.3(@types/node@22.10.1) 236 + version: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 194 237 195 238 packages: 196 239 ··· 460 503 resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 461 504 engines: {node: '>=6.0.0'} 462 505 506 + '@jridgewell/source-map@0.3.6': 507 + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} 508 + 463 509 '@jridgewell/sourcemap-codec@1.5.0': 464 510 resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 465 511 ··· 632 678 '@rushstack/ts-command-line@4.23.1': 633 679 resolution: {integrity: sha512-40jTmYoiu/xlIpkkRsVfENtBq4CW3R4azbL0Vmda+fMwHWqss6wwf/Cy/UJmMqIzpfYc2OTnjYP1ZLD3CmyeCA==} 634 680 681 + '@sveltejs/vite-plugin-svelte-inspector@4.0.1': 682 + resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} 683 + engines: {node: ^18.0.0 || ^20.0.0 || >=22} 684 + peerDependencies: 685 + '@sveltejs/vite-plugin-svelte': ^5.0.0 686 + svelte: ^5.0.0 687 + vite: ^6.0.0 688 + 689 + '@sveltejs/vite-plugin-svelte@5.0.1': 690 + resolution: {integrity: sha512-D5l5+STmywGoLST07T9mrqqFFU+xgv5fqyTWM+VbxTvQ6jujNn4h3lQNCvlwVYs4Erov8i0K5Rwr3LQtmBYmBw==} 691 + engines: {node: ^18.0.0 || ^20.0.0 || >=22} 692 + peerDependencies: 693 + svelte: ^5.0.0 694 + vite: ^6.0.0 695 + 635 696 '@tsconfig/svelte@5.0.4': 636 697 resolution: {integrity: sha512-BV9NplVgLmSi4mwKzD8BD/NQ8erOY/nUE/GpgWe2ckx+wIQF5RyRirn/QsSSCPeulVpc3RA/iJt6DpfTIZps0Q==} 637 698 ··· 738 799 engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 739 800 hasBin: true 740 801 802 + buffer-from@1.1.2: 803 + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 804 + 741 805 caniuse-lite@1.0.30001687: 742 806 resolution: {integrity: sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==} 743 807 ··· 745 809 resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} 746 810 engines: {node: '>= 14.16.0'} 747 811 812 + commander@2.20.3: 813 + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 814 + 748 815 compare-versions@6.1.1: 749 816 resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} 750 817 ··· 784 851 peerDependenciesMeta: 785 852 supports-color: 786 853 optional: true 854 + 855 + deepmerge@4.3.1: 856 + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 857 + engines: {node: '>=0.10.0'} 787 858 788 859 dom-serializer@2.0.0: 789 860 resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} ··· 902 973 jsonfile@4.0.0: 903 974 resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} 904 975 976 + kleur@4.1.5: 977 + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 978 + engines: {node: '>=6'} 979 + 905 980 kolorist@1.8.0: 906 981 resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} 907 982 ··· 924 999 925 1000 magic-string@0.30.14: 926 1001 resolution: {integrity: sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==} 1002 + 1003 + magic-string@0.30.15: 1004 + resolution: {integrity: sha512-zXeaYRgZ6ldS1RJJUrMrYgNJ4fdwnyI6tVqoiIhyCyv5IVTK9BU8Ic2l253GGETQHxI4HNUwhJ3fjDhKqEoaAw==} 927 1005 928 1006 magic-string@0.30.5: 929 1007 resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} ··· 1060 1138 resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1061 1139 engines: {node: '>=0.10.0'} 1062 1140 1141 + source-map-support@0.5.21: 1142 + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 1143 + 1063 1144 source-map@0.6.1: 1064 1145 resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 1065 1146 engines: {node: '>=0.10.0'} ··· 1099 1180 svelte: ^4.0.0 || ^5.0.0-next.0 1100 1181 typescript: '>=5.0.0' 1101 1182 1183 + svelte@5.11.2: 1184 + resolution: {integrity: sha512-kGWswlBaohYxZHML9jp8ZYXkwjKd+WTpyAK1CCDmNzsefZHQjvsa7kbrKUckcFloNmdzwQwaZq+NyunuNOE6lw==} 1185 + engines: {node: '>=18'} 1186 + 1102 1187 svelte@5.8.1: 1103 1188 resolution: {integrity: sha512-tqJY46Xoe+KiKvD4/guNlqpE+jco4IBcuaM6Ei9SEMETtsbLMfbak9XjTacqd6aGMmWXh7uFInfFTd4yES5r0A==} 1104 1189 engines: {node: '>=18'} 1190 + 1191 + terser@5.37.0: 1192 + resolution: {integrity: sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==} 1193 + engines: {node: '>=10'} 1194 + hasBin: true 1195 + 1196 + tslib@2.8.1: 1197 + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1105 1198 1106 1199 typescript@5.4.2: 1107 1200 resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} ··· 1182 1275 yaml: 1183 1276 optional: true 1184 1277 1278 + vitefu@1.0.4: 1279 + resolution: {integrity: sha512-y6zEE3PQf6uu/Mt6DTJ9ih+kyJLr4XcSgHR2zUkM8SWDhuixEJxfJ6CZGMHh1Ec3vPLoEA0IHU5oWzVqw8ulow==} 1280 + peerDependencies: 1281 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 1282 + peerDependenciesMeta: 1283 + vite: 1284 + optional: true 1285 + 1185 1286 vscode-uri@3.0.8: 1186 1287 resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} 1187 1288 ··· 1423 1524 1424 1525 '@jridgewell/set-array@1.2.1': {} 1425 1526 1527 + '@jridgewell/source-map@0.3.6': 1528 + dependencies: 1529 + '@jridgewell/gen-mapping': 0.3.5 1530 + '@jridgewell/trace-mapping': 0.3.25 1531 + 1426 1532 '@jridgewell/sourcemap-codec@1.5.0': {} 1427 1533 1428 1534 '@jridgewell/trace-mapping@0.3.25': ··· 1465 1571 1466 1572 '@microsoft/tsdoc@0.15.1': {} 1467 1573 1468 - '@preact/preset-vite@2.9.3(@babel/core@7.26.0)(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1))': 1574 + '@preact/preset-vite@2.9.3(@babel/core@7.26.0)(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0))': 1469 1575 dependencies: 1470 1576 '@babel/code-frame': 7.26.2 1471 1577 '@babel/core': 7.26.0 1472 1578 '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) 1473 1579 '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.0) 1474 - '@prefresh/vite': 2.4.6(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)) 1580 + '@prefresh/vite': 2.4.6(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 1475 1581 '@rollup/pluginutils': 4.2.1 1476 1582 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.26.0) 1477 1583 debug: 4.4.0 ··· 1480 1586 node-html-parser: 6.1.13 1481 1587 source-map: 0.7.4 1482 1588 stack-trace: 1.0.0-pre2 1483 - vite: 6.0.3(@types/node@22.10.1) 1589 + vite: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 1484 1590 transitivePeerDependencies: 1485 1591 - preact 1486 1592 - supports-color ··· 1493 1599 1494 1600 '@prefresh/utils@1.2.0': {} 1495 1601 1496 - '@prefresh/vite@2.4.6(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1))': 1602 + '@prefresh/vite@2.4.6(preact@10.25.1)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0))': 1497 1603 dependencies: 1498 1604 '@babel/core': 7.26.0 1499 1605 '@prefresh/babel-plugin': 0.5.1 ··· 1501 1607 '@prefresh/utils': 1.2.0 1502 1608 '@rollup/pluginutils': 4.2.1 1503 1609 preact: 10.25.1 1504 - vite: 6.0.3(@types/node@22.10.1) 1610 + vite: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 1505 1611 transitivePeerDependencies: 1506 1612 - supports-color 1507 1613 ··· 1609 1715 transitivePeerDependencies: 1610 1716 - '@types/node' 1611 1717 1718 + '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.1(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)))(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0))': 1719 + dependencies: 1720 + '@sveltejs/vite-plugin-svelte': 5.0.1(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 1721 + debug: 4.4.0 1722 + svelte: 5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu) 1723 + vite: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 1724 + transitivePeerDependencies: 1725 + - supports-color 1726 + 1727 + '@sveltejs/vite-plugin-svelte@5.0.1(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0))': 1728 + dependencies: 1729 + '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.0.1(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)))(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 1730 + debug: 4.4.0 1731 + deepmerge: 4.3.1 1732 + kleur: 4.1.5 1733 + magic-string: 0.30.15 1734 + svelte: 5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu) 1735 + vite: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 1736 + vitefu: 1.0.4(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)) 1737 + transitivePeerDependencies: 1738 + - supports-color 1739 + 1612 1740 '@tsconfig/svelte@5.0.4': {} 1613 1741 1614 1742 '@types/argparse@1.0.38': {} ··· 1724 1852 node-releases: 2.0.18 1725 1853 update-browserslist-db: 1.1.1(browserslist@4.24.2) 1726 1854 1855 + buffer-from@1.1.2: {} 1856 + 1727 1857 caniuse-lite@1.0.30001687: {} 1728 1858 1729 1859 chokidar@4.0.1: 1730 1860 dependencies: 1731 1861 readdirp: 4.0.2 1862 + 1863 + commander@2.20.3: {} 1732 1864 1733 1865 compare-versions@6.1.1: {} 1734 1866 ··· 1760 1892 dependencies: 1761 1893 ms: 2.1.3 1762 1894 1895 + deepmerge@4.3.1: {} 1896 + 1763 1897 dom-serializer@2.0.0: 1764 1898 dependencies: 1765 1899 domelementtype: 2.3.0 ··· 1875 2009 optionalDependencies: 1876 2010 graceful-fs: 4.2.11 1877 2011 2012 + kleur@4.1.5: {} 2013 + 1878 2014 kolorist@1.8.0: {} 1879 2015 1880 2016 local-pkg@0.5.1: ··· 1895 2031 yallist: 4.0.0 1896 2032 1897 2033 magic-string@0.30.14: 2034 + dependencies: 2035 + '@jridgewell/sourcemap-codec': 1.5.0 2036 + 2037 + magic-string@0.30.15: 1898 2038 dependencies: 1899 2039 '@jridgewell/sourcemap-codec': 1.5.0 1900 2040 ··· 1979 2119 transitivePeerDependencies: 1980 2120 - postcss 1981 2121 1982 - prettier-plugin-svelte@3.3.2(prettier@3.4.2)(svelte@5.8.1(patch_hash=6qynve6ufonlwufsl6x7wujmdu)): 2122 + prettier-plugin-svelte@3.3.2(prettier@3.4.2)(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu)): 1983 2123 dependencies: 1984 2124 prettier: 3.4.2 1985 - svelte: 5.8.1(patch_hash=6qynve6ufonlwufsl6x7wujmdu) 2125 + svelte: 5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu) 1986 2126 1987 2127 prettier@3.4.2: {} 1988 2128 ··· 2035 2175 2036 2176 source-map-js@1.2.1: {} 2037 2177 2178 + source-map-support@0.5.21: 2179 + dependencies: 2180 + buffer-from: 1.1.2 2181 + source-map: 0.6.1 2182 + 2038 2183 source-map@0.6.1: {} 2039 2184 2040 2185 source-map@0.7.4: {} ··· 2053 2198 2054 2199 supports-preserve-symlinks-flag@1.0.0: {} 2055 2200 2201 + svelte-check@4.1.1(picomatch@4.0.2)(svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(typescript@5.7.2): 2202 + dependencies: 2203 + '@jridgewell/trace-mapping': 0.3.25 2204 + chokidar: 4.0.1 2205 + fdir: 6.4.2(picomatch@4.0.2) 2206 + picocolors: 1.1.1 2207 + sade: 1.8.1 2208 + svelte: 5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu) 2209 + typescript: 5.7.2 2210 + transitivePeerDependencies: 2211 + - picomatch 2212 + 2056 2213 svelte-check@4.1.1(picomatch@4.0.2)(svelte@5.8.1(patch_hash=6qynve6ufonlwufsl6x7wujmdu))(typescript@5.7.2): 2057 2214 dependencies: 2058 2215 '@jridgewell/trace-mapping': 0.3.25 ··· 2065 2222 transitivePeerDependencies: 2066 2223 - picomatch 2067 2224 2225 + svelte@5.11.2(patch_hash=6qynve6ufonlwufsl6x7wujmdu): 2226 + dependencies: 2227 + '@ampproject/remapping': 2.3.0 2228 + '@jridgewell/sourcemap-codec': 1.5.0 2229 + '@types/estree': 1.0.6 2230 + acorn: 8.14.0 2231 + acorn-typescript: 1.4.13(acorn@8.14.0) 2232 + aria-query: 5.3.2 2233 + axobject-query: 4.1.0 2234 + esm-env: 1.2.1 2235 + esrap: 1.2.3 2236 + is-reference: 3.0.3 2237 + locate-character: 3.0.0 2238 + magic-string: 0.30.15 2239 + zimmerframe: 1.1.2 2240 + 2068 2241 svelte@5.8.1(patch_hash=6qynve6ufonlwufsl6x7wujmdu): 2069 2242 dependencies: 2070 2243 '@ampproject/remapping': 2.3.0 ··· 2081 2254 magic-string: 0.30.14 2082 2255 zimmerframe: 1.1.2 2083 2256 2257 + terser@5.37.0: 2258 + dependencies: 2259 + '@jridgewell/source-map': 0.3.6 2260 + acorn: 8.14.0 2261 + commander: 2.20.3 2262 + source-map-support: 0.5.21 2263 + 2264 + tslib@2.8.1: {} 2265 + 2084 2266 typescript@5.4.2: {} 2085 2267 2086 2268 typescript@5.7.2: {} ··· 2101 2283 dependencies: 2102 2284 punycode: 2.3.1 2103 2285 2104 - vite-plugin-dts@4.3.0(@types/node@22.10.1)(rollup@4.28.1)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)): 2286 + vite-plugin-dts@4.3.0(@types/node@22.10.1)(rollup@4.28.1)(typescript@5.7.2)(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)): 2105 2287 dependencies: 2106 2288 '@microsoft/api-extractor': 7.48.0(@types/node@22.10.1) 2107 2289 '@rollup/pluginutils': 5.1.3(rollup@4.28.1) ··· 2114 2296 magic-string: 0.30.14 2115 2297 typescript: 5.7.2 2116 2298 optionalDependencies: 2117 - vite: 6.0.3(@types/node@22.10.1) 2299 + vite: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 2118 2300 transitivePeerDependencies: 2119 2301 - '@types/node' 2120 2302 - rollup 2121 2303 - supports-color 2122 2304 2123 - vite@6.0.3(@types/node@22.10.1): 2305 + vite@6.0.3(@types/node@22.10.1)(terser@5.37.0): 2124 2306 dependencies: 2125 2307 esbuild: 0.24.0 2126 2308 postcss: 8.4.49 ··· 2128 2310 optionalDependencies: 2129 2311 '@types/node': 22.10.1 2130 2312 fsevents: 2.3.3 2313 + terser: 5.37.0 2314 + 2315 + vitefu@1.0.4(vite@6.0.3(@types/node@22.10.1)(terser@5.37.0)): 2316 + optionalDependencies: 2317 + vite: 6.0.3(@types/node@22.10.1)(terser@5.37.0) 2131 2318 2132 2319 vscode-uri@3.0.8: {} 2133 2320
+1
pnpm-workspace.yaml
··· 1 1 packages: 2 2 - packages/internal 3 3 - packages/site 4 + - packages/svelte-site 4 5 - packages/bluesky-post-embed 5 6 - packages/bluesky-profile-card-embed 6 7 - packages/bluesky-profile-feed-embed