@ewanc26/svelte-standard-site 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +108 -0
- package/dist/__tests__/content.test.d.ts +4 -0
- package/dist/__tests__/content.test.js +128 -0
- package/dist/client.d.ts +71 -0
- package/dist/client.js +307 -0
- package/dist/components/Comments.svelte +277 -0
- package/dist/components/Comments.svelte.d.ts +17 -0
- package/dist/components/DocumentCard.svelte +95 -0
- package/dist/components/DocumentCard.svelte.d.ts +11 -0
- package/dist/components/PublicationCard.svelte +54 -0
- package/dist/components/PublicationCard.svelte.d.ts +9 -0
- package/dist/components/StandardSiteLayout.svelte +102 -0
- package/dist/components/StandardSiteLayout.svelte.d.ts +18 -0
- package/dist/components/ThemeToggle.svelte +55 -0
- package/dist/components/ThemeToggle.svelte.d.ts +6 -0
- package/dist/components/common/DateDisplay.svelte +38 -0
- package/dist/components/common/DateDisplay.svelte.d.ts +11 -0
- package/dist/components/common/TagList.svelte +31 -0
- package/dist/components/common/TagList.svelte.d.ts +8 -0
- package/dist/components/common/ThemedCard.svelte +65 -0
- package/dist/components/common/ThemedCard.svelte.d.ts +11 -0
- package/dist/components/common/ThemedContainer.svelte +55 -0
- package/dist/components/common/ThemedContainer.svelte.d.ts +11 -0
- package/dist/components/common/ThemedText.svelte +75 -0
- package/dist/components/common/ThemedText.svelte.d.ts +11 -0
- package/dist/components/document/BlockRenderer.svelte +67 -0
- package/dist/components/document/BlockRenderer.svelte.d.ts +9 -0
- package/dist/components/document/CanvasRenderer.svelte +41 -0
- package/dist/components/document/CanvasRenderer.svelte.d.ts +22 -0
- package/dist/components/document/DocumentRenderer.svelte +68 -0
- package/dist/components/document/DocumentRenderer.svelte.d.ts +17 -0
- package/dist/components/document/InlineMath.svelte +41 -0
- package/dist/components/document/InlineMath.svelte.d.ts +7 -0
- package/dist/components/document/LeafletContentRenderer.svelte +64 -0
- package/dist/components/document/LeafletContentRenderer.svelte.d.ts +36 -0
- package/dist/components/document/LinearDocumentRenderer.svelte +45 -0
- package/dist/components/document/LinearDocumentRenderer.svelte.d.ts +18 -0
- package/dist/components/document/MarkdownRenderer.svelte +62 -0
- package/dist/components/document/MarkdownRenderer.svelte.d.ts +10 -0
- package/dist/components/document/RichText.svelte +272 -0
- package/dist/components/document/RichText.svelte.d.ts +18 -0
- package/dist/components/document/blocks/BlockquoteBlock.svelte +29 -0
- package/dist/components/document/blocks/BlockquoteBlock.svelte.d.ts +10 -0
- package/dist/components/document/blocks/BskyPostBlock.svelte +202 -0
- package/dist/components/document/blocks/BskyPostBlock.svelte.d.ts +13 -0
- package/dist/components/document/blocks/ButtonBlock.svelte +24 -0
- package/dist/components/document/blocks/ButtonBlock.svelte.d.ts +10 -0
- package/dist/components/document/blocks/CodeBlock.svelte +68 -0
- package/dist/components/document/blocks/CodeBlock.svelte.d.ts +12 -0
- package/dist/components/document/blocks/HeaderBlock.svelte +56 -0
- package/dist/components/document/blocks/HeaderBlock.svelte.d.ts +11 -0
- package/dist/components/document/blocks/HorizontalRuleBlock.svelte +14 -0
- package/dist/components/document/blocks/HorizontalRuleBlock.svelte.d.ts +6 -0
- package/dist/components/document/blocks/IframeBlock.svelte +32 -0
- package/dist/components/document/blocks/IframeBlock.svelte.d.ts +10 -0
- package/dist/components/document/blocks/ImageBlock.svelte +55 -0
- package/dist/components/document/blocks/ImageBlock.svelte.d.ts +25 -0
- package/dist/components/document/blocks/MathBlock.svelte +34 -0
- package/dist/components/document/blocks/MathBlock.svelte.d.ts +10 -0
- package/dist/components/document/blocks/PageBlock.svelte +66 -0
- package/dist/components/document/blocks/PageBlock.svelte.d.ts +10 -0
- package/dist/components/document/blocks/PollBlock.svelte +122 -0
- package/dist/components/document/blocks/PollBlock.svelte.d.ts +27 -0
- package/dist/components/document/blocks/TextBlock.svelte +26 -0
- package/dist/components/document/blocks/TextBlock.svelte.d.ts +11 -0
- package/dist/components/document/blocks/UnorderedListBlock.svelte +71 -0
- package/dist/components/document/blocks/UnorderedListBlock.svelte.d.ts +9 -0
- package/dist/components/document/blocks/WebsiteBlock.svelte +81 -0
- package/dist/components/document/blocks/WebsiteBlock.svelte.d.ts +21 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.js +13 -0
- package/dist/config/env.d.ts +11 -0
- package/dist/config/env.js +26 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +23 -0
- package/dist/publisher.d.ts +193 -0
- package/dist/publisher.js +349 -0
- package/dist/schemas.d.ts +626 -0
- package/dist/schemas.js +113 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.js +1 -0
- package/dist/stores/theme.d.ts +11 -0
- package/dist/stores/theme.js +67 -0
- package/dist/styles/base.css +188 -0
- package/dist/styles/themes.css +5 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.js +4 -0
- package/dist/utils/agents.d.ts +35 -0
- package/dist/utils/agents.js +96 -0
- package/dist/utils/at-uri.d.ts +50 -0
- package/dist/utils/at-uri.js +71 -0
- package/dist/utils/cache.d.ts +14 -0
- package/dist/utils/cache.js +33 -0
- package/dist/utils/comments.d.ts +61 -0
- package/dist/utils/comments.js +159 -0
- package/dist/utils/content.d.ts +94 -0
- package/dist/utils/content.js +178 -0
- package/dist/utils/document.d.ts +23 -0
- package/dist/utils/document.js +33 -0
- package/dist/utils/theme-helpers.d.ts +34 -0
- package/dist/utils/theme-helpers.js +63 -0
- package/dist/utils/theme.d.ts +18 -0
- package/dist/utils/theme.js +24 -0
- package/dist/utils/verification.d.ts +129 -0
- package/dist/utils/verification.js +157 -0
- package/package.json +139 -0
- package/src/lib/__tests__/content.test.ts +155 -0
- package/src/lib/client.ts +368 -0
- package/src/lib/components/Comments.svelte +277 -0
- package/src/lib/components/DocumentCard.svelte +95 -0
- package/src/lib/components/PublicationCard.svelte +54 -0
- package/src/lib/components/StandardSiteLayout.svelte +102 -0
- package/src/lib/components/ThemeToggle.svelte +55 -0
- package/src/lib/components/common/DateDisplay.svelte +38 -0
- package/src/lib/components/common/TagList.svelte +31 -0
- package/src/lib/components/common/ThemedCard.svelte +65 -0
- package/src/lib/components/common/ThemedContainer.svelte +55 -0
- package/src/lib/components/common/ThemedText.svelte +75 -0
- package/src/lib/components/document/BlockRenderer.svelte +67 -0
- package/src/lib/components/document/CanvasRenderer.svelte +41 -0
- package/src/lib/components/document/DocumentRenderer.svelte +68 -0
- package/src/lib/components/document/InlineMath.svelte +41 -0
- package/src/lib/components/document/LeafletContentRenderer.svelte +64 -0
- package/src/lib/components/document/LinearDocumentRenderer.svelte +45 -0
- package/src/lib/components/document/MarkdownRenderer.svelte +62 -0
- package/src/lib/components/document/RichText.svelte +272 -0
- package/src/lib/components/document/blocks/BlockquoteBlock.svelte +29 -0
- package/src/lib/components/document/blocks/BskyPostBlock.svelte +202 -0
- package/src/lib/components/document/blocks/ButtonBlock.svelte +24 -0
- package/src/lib/components/document/blocks/CodeBlock.svelte +68 -0
- package/src/lib/components/document/blocks/HeaderBlock.svelte +56 -0
- package/src/lib/components/document/blocks/HorizontalRuleBlock.svelte +14 -0
- package/src/lib/components/document/blocks/IframeBlock.svelte +32 -0
- package/src/lib/components/document/blocks/ImageBlock.svelte +55 -0
- package/src/lib/components/document/blocks/MathBlock.svelte +34 -0
- package/src/lib/components/document/blocks/PageBlock.svelte +66 -0
- package/src/lib/components/document/blocks/PollBlock.svelte +122 -0
- package/src/lib/components/document/blocks/TextBlock.svelte +26 -0
- package/src/lib/components/document/blocks/UnorderedListBlock.svelte +71 -0
- package/src/lib/components/document/blocks/WebsiteBlock.svelte +81 -0
- package/src/lib/components/index.ts +15 -0
- package/src/lib/config/env.ts +31 -0
- package/src/lib/index.ts +104 -0
- package/src/lib/publisher.ts +489 -0
- package/src/lib/schemas.ts +137 -0
- package/src/lib/stores/index.ts +1 -0
- package/src/lib/stores/theme.ts +80 -0
- package/src/lib/styles/base.css +188 -0
- package/src/lib/styles/themes.css +5 -0
- package/src/lib/types.ts +116 -0
- package/src/lib/utils/agents.ts +124 -0
- package/src/lib/utils/at-uri.ts +89 -0
- package/src/lib/utils/cache.ts +46 -0
- package/src/lib/utils/comments.ts +217 -0
- package/src/lib/utils/content.ts +234 -0
- package/src/lib/utils/document.ts +41 -0
- package/src/lib/utils/theme-helpers.ts +87 -0
- package/src/lib/utils/theme.ts +33 -0
- package/src/lib/utils/verification.ts +180 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { BasicTheme } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate color-mix CSS for theme colors with transparency
|
|
4
|
+
*/
|
|
5
|
+
export declare function mixThemeColor(variable: string, opacity: number, fallback?: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Get theme-aware color styles for text
|
|
8
|
+
*/
|
|
9
|
+
export declare function getThemedTextColor(hasTheme: boolean, opacity?: number): {
|
|
10
|
+
color?: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Get theme-aware background color
|
|
14
|
+
*/
|
|
15
|
+
export declare function getThemedBackground(hasTheme: boolean, opacity?: number): {
|
|
16
|
+
backgroundColor?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Get theme-aware border color
|
|
20
|
+
*/
|
|
21
|
+
export declare function getThemedBorder(hasTheme: boolean, opacity?: number): {
|
|
22
|
+
borderColor?: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Get theme-aware accent color
|
|
26
|
+
*/
|
|
27
|
+
export declare function getThemedAccent(hasTheme: boolean, opacity?: number): {
|
|
28
|
+
color?: string;
|
|
29
|
+
backgroundColor?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Convert BasicTheme to CSS custom properties
|
|
33
|
+
*/
|
|
34
|
+
export declare function themeToCssVars(theme?: BasicTheme): Record<string, string>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { rgbToCSS } from './theme.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate color-mix CSS for theme colors with transparency
|
|
4
|
+
*/
|
|
5
|
+
export function mixThemeColor(variable, opacity, fallback = 'transparent') {
|
|
6
|
+
return `color-mix(in srgb, var(${variable}) ${opacity}%, ${fallback})`;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Get theme-aware color styles for text
|
|
10
|
+
*/
|
|
11
|
+
export function getThemedTextColor(hasTheme, opacity = 100) {
|
|
12
|
+
if (!hasTheme)
|
|
13
|
+
return {};
|
|
14
|
+
return opacity === 100
|
|
15
|
+
? { color: 'var(--theme-foreground)' }
|
|
16
|
+
: { color: mixThemeColor('--theme-foreground', opacity) };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get theme-aware background color
|
|
20
|
+
*/
|
|
21
|
+
export function getThemedBackground(hasTheme, opacity) {
|
|
22
|
+
if (!hasTheme)
|
|
23
|
+
return {};
|
|
24
|
+
if (opacity === undefined) {
|
|
25
|
+
return { backgroundColor: 'var(--theme-background)' };
|
|
26
|
+
}
|
|
27
|
+
return { backgroundColor: mixThemeColor('--theme-background', opacity) };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get theme-aware border color
|
|
31
|
+
*/
|
|
32
|
+
export function getThemedBorder(hasTheme, opacity = 20) {
|
|
33
|
+
if (!hasTheme)
|
|
34
|
+
return {};
|
|
35
|
+
return { borderColor: mixThemeColor('--theme-foreground', opacity) };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get theme-aware accent color
|
|
39
|
+
*/
|
|
40
|
+
export function getThemedAccent(hasTheme, opacity) {
|
|
41
|
+
if (!hasTheme)
|
|
42
|
+
return {};
|
|
43
|
+
if (opacity === undefined) {
|
|
44
|
+
return { color: 'var(--theme-accent)' };
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
backgroundColor: mixThemeColor('--theme-accent', opacity),
|
|
48
|
+
color: 'var(--theme-accent)'
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Convert BasicTheme to CSS custom properties
|
|
53
|
+
*/
|
|
54
|
+
export function themeToCssVars(theme) {
|
|
55
|
+
if (!theme)
|
|
56
|
+
return {};
|
|
57
|
+
return {
|
|
58
|
+
'--theme-background': rgbToCSS(theme.background),
|
|
59
|
+
'--theme-foreground': rgbToCSS(theme.foreground),
|
|
60
|
+
'--theme-accent': rgbToCSS(theme.accent),
|
|
61
|
+
'--theme-accent-foreground': rgbToCSS(theme.accentForeground)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RGBColor } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert RGB color object to CSS rgb() string
|
|
4
|
+
*/
|
|
5
|
+
export declare function rgbToCSS(color: RGBColor): string;
|
|
6
|
+
/**
|
|
7
|
+
* Convert RGB color object to hex string
|
|
8
|
+
*/
|
|
9
|
+
export declare function rgbToHex(color: RGBColor): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get theme CSS variables from BasicTheme
|
|
12
|
+
*/
|
|
13
|
+
export declare function getThemeVars(theme: {
|
|
14
|
+
background: RGBColor;
|
|
15
|
+
foreground: RGBColor;
|
|
16
|
+
accent: RGBColor;
|
|
17
|
+
accentForeground: RGBColor;
|
|
18
|
+
}): Record<string, string>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert RGB color object to CSS rgb() string
|
|
3
|
+
*/
|
|
4
|
+
export function rgbToCSS(color) {
|
|
5
|
+
return `rgb(${color.r}, ${color.g}, ${color.b})`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Convert RGB color object to hex string
|
|
9
|
+
*/
|
|
10
|
+
export function rgbToHex(color) {
|
|
11
|
+
const toHex = (n) => n.toString(16).padStart(2, '0');
|
|
12
|
+
return `#${toHex(color.r)}${toHex(color.g)}${toHex(color.b)}`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get theme CSS variables from BasicTheme
|
|
16
|
+
*/
|
|
17
|
+
export function getThemeVars(theme) {
|
|
18
|
+
return {
|
|
19
|
+
'--theme-background': rgbToCSS(theme.background),
|
|
20
|
+
'--theme-foreground': rgbToCSS(theme.foreground),
|
|
21
|
+
'--theme-accent': rgbToCSS(theme.accent),
|
|
22
|
+
'--theme-accent-foreground': rgbToCSS(theme.accentForeground)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification utilities for proving content ownership
|
|
3
|
+
*
|
|
4
|
+
* Creates `.well-known` endpoints and `<link>` tags to verify that
|
|
5
|
+
* you own the content published to ATProto.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // SvelteKit endpoint: src/routes/.well-known/site.standard.publication/+server.ts
|
|
10
|
+
* import { generatePublicationWellKnown } from 'svelte-standard-site/verification';
|
|
11
|
+
* import { text } from '@sveltejs/kit';
|
|
12
|
+
*
|
|
13
|
+
* export function GET() {
|
|
14
|
+
* return text(
|
|
15
|
+
* generatePublicationWellKnown({
|
|
16
|
+
* did: 'did:plc:xxx',
|
|
17
|
+
* publicationRkey: '3abc123xyz',
|
|
18
|
+
* })
|
|
19
|
+
* );
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Parse an AT-URI to extract its components
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseAtUri(uri: string): {
|
|
27
|
+
did: string;
|
|
28
|
+
collection: string;
|
|
29
|
+
rkey: string;
|
|
30
|
+
} | null;
|
|
31
|
+
/**
|
|
32
|
+
* Build an AT-URI for a document
|
|
33
|
+
*/
|
|
34
|
+
export declare function getDocumentAtUri(did: string, rkey: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Build an AT-URI for a publication
|
|
37
|
+
*/
|
|
38
|
+
export declare function getPublicationAtUri(did: string, rkey: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Generate content for /.well-known/site.standard.publication endpoint
|
|
41
|
+
*
|
|
42
|
+
* This endpoint proves you own your publication record on ATProto.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* // src/routes/.well-known/site.standard.publication/+server.ts
|
|
47
|
+
* import { generatePublicationWellKnown } from 'svelte-standard-site/verification';
|
|
48
|
+
* import { text } from '@sveltejs/kit';
|
|
49
|
+
*
|
|
50
|
+
* export function GET() {
|
|
51
|
+
* return text(
|
|
52
|
+
* generatePublicationWellKnown({
|
|
53
|
+
* did: 'did:plc:xxx',
|
|
54
|
+
* publicationRkey: '3abc123xyz',
|
|
55
|
+
* })
|
|
56
|
+
* );
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function generatePublicationWellKnown(options: {
|
|
61
|
+
did: string;
|
|
62
|
+
publicationRkey: string;
|
|
63
|
+
}): string;
|
|
64
|
+
/**
|
|
65
|
+
* Generate a <link> tag for document verification
|
|
66
|
+
*
|
|
67
|
+
* Add this to your document's <head> to verify ownership.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```svelte
|
|
71
|
+
* <svelte:head>
|
|
72
|
+
* {@html generateDocumentLinkTag({
|
|
73
|
+
* did: 'did:plc:xxx',
|
|
74
|
+
* documentRkey: '3xyz789abc',
|
|
75
|
+
* })}
|
|
76
|
+
* </svelte:head>
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function generateDocumentLinkTag(options: {
|
|
80
|
+
did: string;
|
|
81
|
+
documentRkey: string;
|
|
82
|
+
}): string;
|
|
83
|
+
/**
|
|
84
|
+
* Generate a <link> tag for publication verification
|
|
85
|
+
*
|
|
86
|
+
* Add this to your site's <head> to verify publication ownership.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```svelte
|
|
90
|
+
* <svelte:head>
|
|
91
|
+
* {@html generatePublicationLinkTag({
|
|
92
|
+
* did: 'did:plc:xxx',
|
|
93
|
+
* publicationRkey: '3abc123xyz',
|
|
94
|
+
* })}
|
|
95
|
+
* </svelte:head>
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare function generatePublicationLinkTag(options: {
|
|
99
|
+
did: string;
|
|
100
|
+
publicationRkey: string;
|
|
101
|
+
}): string;
|
|
102
|
+
/**
|
|
103
|
+
* Verify that a well-known endpoint returns the expected AT-URI
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* const isValid = await verifyPublicationWellKnown(
|
|
108
|
+
* 'https://yourblog.com',
|
|
109
|
+
* 'did:plc:xxx',
|
|
110
|
+
* '3abc123xyz'
|
|
111
|
+
* );
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare function verifyPublicationWellKnown(siteUrl: string, did: string, publicationRkey: string): Promise<boolean>;
|
|
115
|
+
/**
|
|
116
|
+
* Extract AT-URI from a <link> tag in HTML
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* const html = '<link rel="site.standard.document" href="at://did:plc:xxx/site.standard.document/3xyz">';
|
|
121
|
+
* const uri = extractDocumentLinkFromHtml(html);
|
|
122
|
+
* // => 'at://did:plc:xxx/site.standard.document/3xyz'
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export declare function extractDocumentLinkFromHtml(html: string): string | null;
|
|
126
|
+
/**
|
|
127
|
+
* Extract publication AT-URI from a <link> tag in HTML
|
|
128
|
+
*/
|
|
129
|
+
export declare function extractPublicationLinkFromHtml(html: string): string | null;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verification utilities for proving content ownership
|
|
3
|
+
*
|
|
4
|
+
* Creates `.well-known` endpoints and `<link>` tags to verify that
|
|
5
|
+
* you own the content published to ATProto.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // SvelteKit endpoint: src/routes/.well-known/site.standard.publication/+server.ts
|
|
10
|
+
* import { generatePublicationWellKnown } from 'svelte-standard-site/verification';
|
|
11
|
+
* import { text } from '@sveltejs/kit';
|
|
12
|
+
*
|
|
13
|
+
* export function GET() {
|
|
14
|
+
* return text(
|
|
15
|
+
* generatePublicationWellKnown({
|
|
16
|
+
* did: 'did:plc:xxx',
|
|
17
|
+
* publicationRkey: '3abc123xyz',
|
|
18
|
+
* })
|
|
19
|
+
* );
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Parse an AT-URI to extract its components
|
|
25
|
+
*/
|
|
26
|
+
export function parseAtUri(uri) {
|
|
27
|
+
const match = uri.match(/^at:\/\/([^/]+)\/([^/]+)\/(.+)$/);
|
|
28
|
+
if (!match)
|
|
29
|
+
return null;
|
|
30
|
+
return {
|
|
31
|
+
did: match[1],
|
|
32
|
+
collection: match[2],
|
|
33
|
+
rkey: match[3]
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build an AT-URI for a document
|
|
38
|
+
*/
|
|
39
|
+
export function getDocumentAtUri(did, rkey) {
|
|
40
|
+
return `at://${did}/site.standard.document/${rkey}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build an AT-URI for a publication
|
|
44
|
+
*/
|
|
45
|
+
export function getPublicationAtUri(did, rkey) {
|
|
46
|
+
return `at://${did}/site.standard.publication/${rkey}`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate content for /.well-known/site.standard.publication endpoint
|
|
50
|
+
*
|
|
51
|
+
* This endpoint proves you own your publication record on ATProto.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* // src/routes/.well-known/site.standard.publication/+server.ts
|
|
56
|
+
* import { generatePublicationWellKnown } from 'svelte-standard-site/verification';
|
|
57
|
+
* import { text } from '@sveltejs/kit';
|
|
58
|
+
*
|
|
59
|
+
* export function GET() {
|
|
60
|
+
* return text(
|
|
61
|
+
* generatePublicationWellKnown({
|
|
62
|
+
* did: 'did:plc:xxx',
|
|
63
|
+
* publicationRkey: '3abc123xyz',
|
|
64
|
+
* })
|
|
65
|
+
* );
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export function generatePublicationWellKnown(options) {
|
|
70
|
+
return getPublicationAtUri(options.did, options.publicationRkey);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Generate a <link> tag for document verification
|
|
74
|
+
*
|
|
75
|
+
* Add this to your document's <head> to verify ownership.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```svelte
|
|
79
|
+
* <svelte:head>
|
|
80
|
+
* {@html generateDocumentLinkTag({
|
|
81
|
+
* did: 'did:plc:xxx',
|
|
82
|
+
* documentRkey: '3xyz789abc',
|
|
83
|
+
* })}
|
|
84
|
+
* </svelte:head>
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export function generateDocumentLinkTag(options) {
|
|
88
|
+
const atUri = getDocumentAtUri(options.did, options.documentRkey);
|
|
89
|
+
return `<link rel="site.standard.document" href="${atUri}">`;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generate a <link> tag for publication verification
|
|
93
|
+
*
|
|
94
|
+
* Add this to your site's <head> to verify publication ownership.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```svelte
|
|
98
|
+
* <svelte:head>
|
|
99
|
+
* {@html generatePublicationLinkTag({
|
|
100
|
+
* did: 'did:plc:xxx',
|
|
101
|
+
* publicationRkey: '3abc123xyz',
|
|
102
|
+
* })}
|
|
103
|
+
* </svelte:head>
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export function generatePublicationLinkTag(options) {
|
|
107
|
+
const atUri = getPublicationAtUri(options.did, options.publicationRkey);
|
|
108
|
+
return `<link rel="site.standard.publication" href="${atUri}">`;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Verify that a well-known endpoint returns the expected AT-URI
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* const isValid = await verifyPublicationWellKnown(
|
|
116
|
+
* 'https://yourblog.com',
|
|
117
|
+
* 'did:plc:xxx',
|
|
118
|
+
* '3abc123xyz'
|
|
119
|
+
* );
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export async function verifyPublicationWellKnown(siteUrl, did, publicationRkey) {
|
|
123
|
+
try {
|
|
124
|
+
const cleanUrl = siteUrl.replace(/\/$/, '');
|
|
125
|
+
const response = await fetch(`${cleanUrl}/.well-known/site.standard.publication`);
|
|
126
|
+
if (!response.ok)
|
|
127
|
+
return false;
|
|
128
|
+
const content = await response.text();
|
|
129
|
+
const expectedUri = getPublicationAtUri(did, publicationRkey);
|
|
130
|
+
return content.trim() === expectedUri;
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
console.error('Failed to verify publication well-known:', error);
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Extract AT-URI from a <link> tag in HTML
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const html = '<link rel="site.standard.document" href="at://did:plc:xxx/site.standard.document/3xyz">';
|
|
143
|
+
* const uri = extractDocumentLinkFromHtml(html);
|
|
144
|
+
* // => 'at://did:plc:xxx/site.standard.document/3xyz'
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export function extractDocumentLinkFromHtml(html) {
|
|
148
|
+
const match = html.match(/<link\s+rel="site\.standard\.document"\s+href="(at:\/\/[^"]+)"\s*\/?>/i);
|
|
149
|
+
return match ? match[1] : null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Extract publication AT-URI from a <link> tag in HTML
|
|
153
|
+
*/
|
|
154
|
+
export function extractPublicationLinkFromHtml(html) {
|
|
155
|
+
const match = html.match(/<link\s+rel="site\.standard\.publication"\s+href="(at:\/\/[^"]+)"\s*\/?>/i);
|
|
156
|
+
return match ? match[1] : null;
|
|
157
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ewanc26/svelte-standard-site",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "SvelteKit library for reading and writing AT Protocol longform content via site.standard.* records — with a complete design system, federated comments, publishing tools, and content verification.",
|
|
5
|
+
"license": "AGPL-3.0-only",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Ewan Croft",
|
|
8
|
+
"url": "https://github.com/ewanc26"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"svelte": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"svelte": "./dist/index.js",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./publisher": {
|
|
20
|
+
"types": "./dist/publisher.d.ts",
|
|
21
|
+
"default": "./dist/publisher.js"
|
|
22
|
+
},
|
|
23
|
+
"./content": {
|
|
24
|
+
"types": "./dist/utils/content.d.ts",
|
|
25
|
+
"default": "./dist/utils/content.js"
|
|
26
|
+
},
|
|
27
|
+
"./comments": {
|
|
28
|
+
"types": "./dist/utils/comments.d.ts",
|
|
29
|
+
"default": "./dist/utils/comments.js"
|
|
30
|
+
},
|
|
31
|
+
"./verification": {
|
|
32
|
+
"types": "./dist/utils/verification.d.ts",
|
|
33
|
+
"default": "./dist/utils/verification.js"
|
|
34
|
+
},
|
|
35
|
+
"./schemas": {
|
|
36
|
+
"types": "./dist/schemas.d.ts",
|
|
37
|
+
"default": "./dist/schemas.js"
|
|
38
|
+
},
|
|
39
|
+
"./config/env": {
|
|
40
|
+
"types": "./dist/config/env.d.ts",
|
|
41
|
+
"default": "./dist/config/env.js"
|
|
42
|
+
},
|
|
43
|
+
"./styles/base.css": {
|
|
44
|
+
"default": "./dist/styles/base.css"
|
|
45
|
+
},
|
|
46
|
+
"./styles/themes.css": {
|
|
47
|
+
"default": "./dist/styles/themes.css"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"dist",
|
|
52
|
+
"src/lib",
|
|
53
|
+
"README.md"
|
|
54
|
+
],
|
|
55
|
+
"sideEffects": [
|
|
56
|
+
"**/*.css"
|
|
57
|
+
],
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"@sveltejs/kit": "^2.0.0",
|
|
63
|
+
"svelte": "^5.0.0"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"@atproto/api": "^0.18.16",
|
|
67
|
+
"@lucide/svelte": "^0.562.0",
|
|
68
|
+
"katex": "^0.16.27",
|
|
69
|
+
"rehype-slug": "^6.0.0",
|
|
70
|
+
"rehype-stringify": "^10.0.1",
|
|
71
|
+
"remark-gfm": "^4.0.1",
|
|
72
|
+
"remark-parse": "^11.0.0",
|
|
73
|
+
"remark-rehype": "^11.1.2",
|
|
74
|
+
"shiki": "^3.21.0",
|
|
75
|
+
"unified": "^11.0.5",
|
|
76
|
+
"zod": "^3.24.0",
|
|
77
|
+
"@ewanc26/atproto": "0.2.0",
|
|
78
|
+
"@ewanc26/tid": "1.1.0",
|
|
79
|
+
"@ewanc26/utils": "0.1.0"
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@sveltejs/adapter-auto": "^7.0.0",
|
|
83
|
+
"@sveltejs/kit": "^2.49.1",
|
|
84
|
+
"@sveltejs/package": "^2.5.7",
|
|
85
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
|
86
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
87
|
+
"@tailwindcss/vite": "^4.1.17",
|
|
88
|
+
"@types/node": "^22.0.0",
|
|
89
|
+
"prettier": "^3.7.4",
|
|
90
|
+
"prettier-plugin-svelte": "^3.4.0",
|
|
91
|
+
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
92
|
+
"publint": "^0.3.15",
|
|
93
|
+
"svelte": "^5.45.6",
|
|
94
|
+
"svelte-check": "^4.3.4",
|
|
95
|
+
"tailwindcss": "^4.1.17",
|
|
96
|
+
"typescript": "^5.9.3",
|
|
97
|
+
"vite": "^7.2.6",
|
|
98
|
+
"vitest": "^4.0.16"
|
|
99
|
+
},
|
|
100
|
+
"keywords": [
|
|
101
|
+
"svelte",
|
|
102
|
+
"sveltekit",
|
|
103
|
+
"atproto",
|
|
104
|
+
"at-protocol",
|
|
105
|
+
"bluesky",
|
|
106
|
+
"site-standard",
|
|
107
|
+
"blog",
|
|
108
|
+
"cms",
|
|
109
|
+
"design-system",
|
|
110
|
+
"components",
|
|
111
|
+
"dark-mode",
|
|
112
|
+
"light-mode",
|
|
113
|
+
"theme",
|
|
114
|
+
"publishing",
|
|
115
|
+
"federation",
|
|
116
|
+
"comments"
|
|
117
|
+
],
|
|
118
|
+
"repository": {
|
|
119
|
+
"type": "git",
|
|
120
|
+
"url": "git+https://github.com/ewanc26/pkgs.git",
|
|
121
|
+
"directory": "packages/svelte-standard-site"
|
|
122
|
+
},
|
|
123
|
+
"homepage": "https://github.com/ewanc26/pkgs/tree/main/packages/svelte-standard-site",
|
|
124
|
+
"bugs": {
|
|
125
|
+
"url": "https://github.com/ewanc26/pkgs/issues"
|
|
126
|
+
},
|
|
127
|
+
"scripts": {
|
|
128
|
+
"build": "svelte-kit sync && svelte-package -i src/lib -o dist && publint",
|
|
129
|
+
"dev": "svelte-kit sync && svelte-package -i src/lib -o dist --watch",
|
|
130
|
+
"dev:app": "vite dev",
|
|
131
|
+
"preview": "vite preview",
|
|
132
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
133
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
134
|
+
"test": "vitest run",
|
|
135
|
+
"test:watch": "vitest",
|
|
136
|
+
"format": "prettier --write .",
|
|
137
|
+
"lint": "prettier --check ."
|
|
138
|
+
}
|
|
139
|
+
}
|