@businessdash/sdk 0.9.60 → 0.9.80
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/README.md +991 -295
- package/assets/biab-sw.js +92 -0
- package/dist/account-core/index.d.ts +126 -0
- package/dist/account-core/index.d.ts.map +1 -0
- package/dist/account-core/index.js +191 -0
- package/dist/account-core/index.js.map +1 -0
- package/dist/account.d.ts +11 -0
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +11 -0
- package/dist/account.js.map +1 -0
- package/dist/auth-handler.d.ts +1 -1
- package/dist/auth-links.d.ts +33 -0
- package/dist/auth-links.d.ts.map +1 -0
- package/dist/auth-links.js +64 -0
- package/dist/auth-links.js.map +1 -0
- package/dist/blog-core/index.d.ts +112 -0
- package/dist/blog-core/index.d.ts.map +1 -0
- package/dist/blog-core/index.js +330 -0
- package/dist/blog-core/index.js.map +1 -0
- package/dist/blog.d.ts +11 -0
- package/dist/blog.d.ts.map +1 -0
- package/dist/blog.js +11 -0
- package/dist/blog.js.map +1 -0
- package/dist/chat-core/index.d.ts +97 -0
- package/dist/chat-core/index.d.ts.map +1 -0
- package/dist/chat-core/index.js +237 -0
- package/dist/chat-core/index.js.map +1 -0
- package/dist/chat.d.ts +11 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +11 -0
- package/dist/chat.js.map +1 -0
- package/dist/checkout-core/index.d.ts +65 -0
- package/dist/checkout-core/index.d.ts.map +1 -0
- package/dist/checkout-core/index.js +159 -0
- package/dist/checkout-core/index.js.map +1 -0
- package/dist/checkout.d.ts +10 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +10 -0
- package/dist/checkout.js.map +1 -0
- package/dist/cli.js +133 -25
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +622 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +888 -1
- package/dist/client.js.map +1 -1
- package/dist/consent-core/index.cjs +107 -0
- package/dist/consent-core/index.d.ts +103 -0
- package/dist/consent-core/index.d.ts.map +1 -0
- package/dist/consent-core/index.js +157 -0
- package/dist/consent-core/index.js.map +1 -0
- package/dist/contracts.d.ts +3526 -767
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +571 -4
- package/dist/contracts.js.map +1 -1
- package/dist/data-model-schema.d.ts +1 -1
- package/dist/data-model-schema.d.ts.map +1 -1
- package/dist/element.d.ts +30 -0
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +56 -0
- package/dist/element.js.map +1 -1
- package/dist/embed-protocol.d.ts +86 -0
- package/dist/embed-protocol.d.ts.map +1 -0
- package/dist/embed-protocol.js +60 -0
- package/dist/embed-protocol.js.map +1 -0
- package/dist/framework-support.d.ts +122 -0
- package/dist/framework-support.d.ts.map +1 -0
- package/dist/framework-support.js +323 -0
- package/dist/framework-support.js.map +1 -0
- package/dist/index.cjs +1355 -24
- package/dist/legal-core/index.cjs +115 -0
- package/dist/legal-core/index.d.ts +160 -0
- package/dist/legal-core/index.d.ts.map +1 -0
- package/dist/legal-core/index.js +220 -0
- package/dist/legal-core/index.js.map +1 -0
- package/dist/marketing-core/index.d.ts +66 -0
- package/dist/marketing-core/index.d.ts.map +1 -0
- package/dist/marketing-core/index.js +154 -0
- package/dist/marketing-core/index.js.map +1 -0
- package/dist/marketing.d.ts +7 -0
- package/dist/marketing.d.ts.map +1 -0
- package/dist/marketing.js +7 -0
- package/dist/marketing.js.map +1 -0
- package/dist/mcp-adapters/index.d.ts +135 -0
- package/dist/mcp-adapters/index.d.ts.map +1 -0
- package/dist/mcp-adapters/index.js +187 -0
- package/dist/mcp-adapters/index.js.map +1 -0
- package/dist/mcp-adapters.d.ts +7 -0
- package/dist/mcp-adapters.d.ts.map +1 -0
- package/dist/mcp-adapters.js +7 -0
- package/dist/mcp-adapters.js.map +1 -0
- package/dist/model3d-core/index.cjs +95 -0
- package/dist/model3d-core/index.d.ts +167 -0
- package/dist/model3d-core/index.d.ts.map +1 -0
- package/dist/model3d-core/index.js +158 -0
- package/dist/model3d-core/index.js.map +1 -0
- package/dist/notifications-core/index.cjs +315 -0
- package/dist/notifications-core/index.d.ts +229 -0
- package/dist/notifications-core/index.d.ts.map +1 -0
- package/dist/notifications-core/index.js +445 -0
- package/dist/notifications-core/index.js.map +1 -0
- package/dist/portal-core/index.d.ts +451 -0
- package/dist/portal-core/index.d.ts.map +1 -0
- package/dist/portal-core/index.js +819 -0
- package/dist/portal-core/index.js.map +1 -0
- package/dist/portal.d.ts +7 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +7 -0
- package/dist/portal.js.map +1 -0
- package/dist/push-core/index.cjs +171 -0
- package/dist/push-core/index.d.ts +149 -0
- package/dist/push-core/index.d.ts.map +1 -0
- package/dist/push-core/index.js +231 -0
- package/dist/push-core/index.js.map +1 -0
- package/dist/react-marketing.d.ts +1 -17
- package/dist/react-marketing.d.ts.map +1 -1
- package/dist/react-marketing.js +4 -0
- package/dist/react-marketing.js.map +1 -1
- package/dist/react.d.ts +294 -101
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +302 -246
- package/dist/react.js.map +1 -1
- package/dist/seed-core/index.d.ts +354 -0
- package/dist/seed-core/index.d.ts.map +1 -0
- package/dist/seed-core/index.js +420 -0
- package/dist/seed-core/index.js.map +1 -0
- package/dist/seed.d.ts +7 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +7 -0
- package/dist/seed.js.map +1 -0
- package/dist/seo-core/blog.d.ts +94 -0
- package/dist/seo-core/blog.d.ts.map +1 -0
- package/dist/seo-core/blog.js +149 -0
- package/dist/seo-core/blog.js.map +1 -0
- package/dist/seo-core/commerce.d.ts +64 -0
- package/dist/seo-core/commerce.d.ts.map +1 -0
- package/dist/seo-core/commerce.js +87 -0
- package/dist/seo-core/commerce.js.map +1 -0
- package/dist/seo-core/index.cjs +751 -0
- package/dist/seo-core/index.d.ts +226 -0
- package/dist/seo-core/index.d.ts.map +1 -0
- package/dist/seo-core/index.js +455 -0
- package/dist/seo-core/index.js.map +1 -0
- package/dist/seo-core/local.d.ts +181 -0
- package/dist/seo-core/local.d.ts.map +1 -0
- package/dist/seo-core/local.js +193 -0
- package/dist/seo-core/local.js.map +1 -0
- package/dist/sitemap-core/index.cjs +167 -0
- package/dist/sitemap-core/index.d.ts +155 -0
- package/dist/sitemap-core/index.d.ts.map +1 -0
- package/dist/sitemap-core/index.js +195 -0
- package/dist/sitemap-core/index.js.map +1 -0
- package/dist/social-core/index.d.ts +74 -0
- package/dist/social-core/index.d.ts.map +1 -0
- package/dist/social-core/index.js +72 -0
- package/dist/social-core/index.js.map +1 -0
- package/dist/social.d.ts +7 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +7 -0
- package/dist/social.js.map +1 -0
- package/dist/solid-compat.d.ts +204 -0
- package/dist/solid-compat.d.ts.map +1 -0
- package/dist/solid-compat.js +221 -0
- package/dist/solid-compat.js.map +1 -0
- package/dist/store-core/index.d.ts +141 -0
- package/dist/store-core/index.d.ts.map +1 -0
- package/dist/store-core/index.js +277 -0
- package/dist/store-core/index.js.map +1 -0
- package/dist/store.d.ts +12 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +12 -0
- package/dist/store.js.map +1 -0
- package/dist/vanilla.d.ts +111 -0
- package/dist/vanilla.d.ts.map +1 -1
- package/dist/vanilla.js +206 -0
- package/dist/vanilla.js.map +1 -1
- package/dist/verify-core/index.d.ts +98 -0
- package/dist/verify-core/index.d.ts.map +1 -0
- package/dist/verify-core/index.js +186 -0
- package/dist/verify-core/index.js.map +1 -0
- package/dist/verify.d.ts +8 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +8 -0
- package/dist/verify.js.map +1 -0
- package/openapi.json +4516 -1311
- package/package.json +128 -11
- package/src/account-core/index.ts +309 -0
- package/src/account.ts +11 -0
- package/src/angular/headless.ts +519 -0
- package/src/angular/index.ts +3 -0
- package/src/auth-links.ts +76 -0
- package/src/blog-core/index.ts +423 -0
- package/src/blog.ts +11 -0
- package/src/chat-core/index.ts +335 -0
- package/src/chat.ts +11 -0
- package/src/checkout-core/index.ts +225 -0
- package/src/checkout.ts +10 -0
- package/src/cli.ts +184 -28
- package/src/client.ts +1097 -0
- package/src/consent-core/index.ts +213 -0
- package/src/contracts.ts +768 -11
- package/src/data-model-schema.ts +1 -1
- package/src/element.ts +102 -0
- package/src/embed-protocol.ts +100 -0
- package/src/framework-support.ts +440 -0
- package/src/legal-core/index.ts +276 -0
- package/src/marketing-core/index.ts +209 -0
- package/src/marketing.ts +7 -0
- package/src/mcp-adapters/index.ts +264 -0
- package/src/mcp-adapters.ts +7 -0
- package/src/model3d-core/index.ts +248 -0
- package/src/notifications-core/index.ts +650 -0
- package/src/portal-core/index.ts +1564 -0
- package/src/portal.ts +7 -0
- package/src/push-core/index.ts +335 -0
- package/src/qwik.tsx +602 -2
- package/src/react-marketing.tsx +5 -0
- package/src/react.tsx +434 -319
- package/src/seed-core/index.ts +735 -0
- package/src/seed.ts +7 -0
- package/src/seo-core/blog.ts +216 -0
- package/src/seo-core/commerce.ts +138 -0
- package/src/seo-core/index.ts +605 -0
- package/src/seo-core/local.ts +333 -0
- package/src/sitemap-core/index.ts +296 -0
- package/src/social-core/index.ts +103 -0
- package/src/social.ts +7 -0
- package/src/solid-compat.tsx +347 -0
- package/src/solid-surfaces.tsx +1311 -0
- package/src/solid.tsx +82 -60
- package/src/store-core/index.ts +426 -0
- package/src/store.ts +12 -0
- package/src/svelte/SocialLinks.svelte +84 -0
- package/src/svelte/headless.ts +435 -0
- package/src/svelte/index.ts +9 -0
- package/src/vanilla.ts +367 -0
- package/src/verify-core/index.ts +288 -0
- package/src/verify.ts +8 -0
- package/src/vue/headless.ts +527 -0
- package/src/vue/index.ts +3 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@businessdash/sdk/sitemap` — build a sitemap that matches YOUR site.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the platform cannot do this alone
|
|
5
|
+
*
|
|
6
|
+
* BusinessDash knows an org has 40 blog posts. It does not know whether their
|
|
7
|
+
* site renders them at `/blog/[slug]`, `/updates/[slug]`, `/news/[slug]`, or
|
|
8
|
+
* not at all. Guessing produces a sitemap full of URLs that 404 — which is
|
|
9
|
+
* meaningfully worse than a smaller sitemap, because a crawler that finds
|
|
10
|
+
* broken URLs in your sitemap discounts the whole file.
|
|
11
|
+
*
|
|
12
|
+
* So the split is: the platform emits the URLs whose shape it owns (site-builder
|
|
13
|
+
* pages, legal documents, programmatic pages — it defines those route
|
|
14
|
+
* patterns), and this merges in the rest using paths YOU declare.
|
|
15
|
+
*
|
|
16
|
+
* ## Everything is opt-in, and the default is omission
|
|
17
|
+
*
|
|
18
|
+
* A mobile mechanic has no store. If you do not declare `routes.product`, no
|
|
19
|
+
* product URLs are emitted — and even if you did, the platform would refuse the
|
|
20
|
+
* data because the org has no `ecommerce.storefront` entitlement. Two
|
|
21
|
+
* independent gates, both defaulting to "no".
|
|
22
|
+
*
|
|
23
|
+
* That asymmetry is deliberate. A missing URL costs you the indexing of one
|
|
24
|
+
* page, which Google will usually find by crawling anyway. A sitemap full of
|
|
25
|
+
* 404s costs you trust in every URL in the file. When unsure, this omits.
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const xml = await buildSitemap({
|
|
29
|
+
* client,
|
|
30
|
+
* siteId: SITE_ID,
|
|
31
|
+
* baseUrl: 'https://acme.com',
|
|
32
|
+
* staticPaths: ['/', '/about', '/contact'],
|
|
33
|
+
* routes: {
|
|
34
|
+
* blog: '/blog', // → /blog/{slug}
|
|
35
|
+
* product: '/store', // → /store/{id}
|
|
36
|
+
* // no `legal` key → the platform already emits those at their own slugs
|
|
37
|
+
* },
|
|
38
|
+
* })
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @module
|
|
42
|
+
*/
|
|
43
|
+
/** Where a kind of platform content lives on YOUR site. */
|
|
44
|
+
export type SitemapRoutes = {
|
|
45
|
+
/**
|
|
46
|
+
* Path prefix for blog posts — `/blog` yields `/blog/{slug}`.
|
|
47
|
+
*
|
|
48
|
+
* Omit if you do not render a blog. Requires the `blog.public`
|
|
49
|
+
* entitlement; without it the platform returns nothing and this skips the
|
|
50
|
+
* section rather than failing.
|
|
51
|
+
*/
|
|
52
|
+
blog?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Path prefix for products — `/store` yields `/store/{id}`.
|
|
55
|
+
*
|
|
56
|
+
* Omit if you do not sell anything. Requires `ecommerce.storefront`.
|
|
57
|
+
*/
|
|
58
|
+
product?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Prefix for the org's legal pages, if you mounted them somewhere other
|
|
61
|
+
* than the site root.
|
|
62
|
+
*
|
|
63
|
+
* Usually omitted: the platform already emits legal URLs at their own
|
|
64
|
+
* slugs (`/privacy`), which is where the SDK's catch-all serves them.
|
|
65
|
+
* Set it only if your catch-all lives under a prefix.
|
|
66
|
+
*/
|
|
67
|
+
legal?: string;
|
|
68
|
+
};
|
|
69
|
+
export type SitemapEntry = {
|
|
70
|
+
/** Absolute URL. */
|
|
71
|
+
loc: string;
|
|
72
|
+
/** ISO 8601. Omitted when nothing meaningful is known. */
|
|
73
|
+
lastmod?: string;
|
|
74
|
+
};
|
|
75
|
+
export type BuildSitemapOptions = {
|
|
76
|
+
client: SitemapClientLike;
|
|
77
|
+
siteId: string;
|
|
78
|
+
/** Your canonical origin, e.g. `https://acme.com`. No trailing slash needed. */
|
|
79
|
+
baseUrl: string;
|
|
80
|
+
/**
|
|
81
|
+
* Paths you hand-wrote in your own repo — the homepage, an about page, a
|
|
82
|
+
* landing page. The platform cannot know these exist.
|
|
83
|
+
*
|
|
84
|
+
* Always include `/`. A sitemap without the homepage is a common and
|
|
85
|
+
* entirely self-inflicted omission.
|
|
86
|
+
*/
|
|
87
|
+
staticPaths?: string[];
|
|
88
|
+
routes?: SitemapRoutes;
|
|
89
|
+
/** How many blog posts to enumerate. Default 1000. */
|
|
90
|
+
blogLimit?: number;
|
|
91
|
+
/** How many products to enumerate. Default 1000. */
|
|
92
|
+
productLimit?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Called when a section is skipped, with the reason.
|
|
95
|
+
*
|
|
96
|
+
* Worth logging during setup: "skipped products — org has no
|
|
97
|
+
* ecommerce.storefront entitlement" is the difference between a deliberate
|
|
98
|
+
* omission and a silent one you discover months later in Search Console.
|
|
99
|
+
*/
|
|
100
|
+
onSkip?: (section: string, reason: string) => void;
|
|
101
|
+
};
|
|
102
|
+
/** The subset of the SDK client this needs. */
|
|
103
|
+
export type SitemapClientLike = {
|
|
104
|
+
blog: {
|
|
105
|
+
listPosts(input?: {
|
|
106
|
+
limit?: number;
|
|
107
|
+
}): Promise<{
|
|
108
|
+
posts: Array<{
|
|
109
|
+
slug: string;
|
|
110
|
+
updatedAt?: string | null;
|
|
111
|
+
}>;
|
|
112
|
+
}>;
|
|
113
|
+
};
|
|
114
|
+
storefront: {
|
|
115
|
+
listProducts(input?: {
|
|
116
|
+
limit?: number;
|
|
117
|
+
}): Promise<{
|
|
118
|
+
products: Array<{
|
|
119
|
+
id: string;
|
|
120
|
+
updatedAt?: string | null;
|
|
121
|
+
}>;
|
|
122
|
+
}>;
|
|
123
|
+
};
|
|
124
|
+
site(siteId: string): {
|
|
125
|
+
sitemapEntries(): Promise<{
|
|
126
|
+
entries: SitemapEntry[];
|
|
127
|
+
}>;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Collect every URL for the site, deduplicated and ordered.
|
|
132
|
+
*
|
|
133
|
+
* Sections fail independently — one unreachable surface never takes the
|
|
134
|
+
* sitemap down with it.
|
|
135
|
+
*/
|
|
136
|
+
export declare function collectSitemapEntries(options: BuildSitemapOptions): Promise<SitemapEntry[]>;
|
|
137
|
+
/** Serialise entries as a sitemap document. */
|
|
138
|
+
export declare function renderSitemapXml(entries: SitemapEntry[]): string;
|
|
139
|
+
/**
|
|
140
|
+
* The whole thing: collect, then serialise.
|
|
141
|
+
*
|
|
142
|
+
* Never throws. A sitemap route that 500s is worse than one that returns fewer
|
|
143
|
+
* URLs — crawlers retry a thin sitemap and back off from an error page.
|
|
144
|
+
*/
|
|
145
|
+
export declare function buildSitemap(options: BuildSitemapOptions): Promise<string>;
|
|
146
|
+
/**
|
|
147
|
+
* A sitemap with only the homepage in it.
|
|
148
|
+
*
|
|
149
|
+
* The fallback when BusinessDash is unconfigured or unreachable. Deliberately
|
|
150
|
+
* NOT an empty `<urlset>`: an empty sitemap affirmatively tells a crawler the
|
|
151
|
+
* site has no pages, which is a worse claim than saying nothing. One honest URL
|
|
152
|
+
* is the smallest truthful document.
|
|
153
|
+
*/
|
|
154
|
+
export declare function minimalSitemapXml(baseUrl: string): string;
|
|
155
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sitemap-core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAKH,2DAA2D;AAC3D,MAAM,MAAM,aAAa,GAAG;IAC3B;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE;QACL,SAAS,CAAC,KAAK,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC;YAC9C,KAAK,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;aAAE,CAAC,CAAC;SAC1D,CAAC,CAAC;KACH,CAAC;IACF,UAAU,EAAE;QACX,YAAY,CAAC,KAAK,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO,CAAC;YACjD,QAAQ,EAAE,KAAK,CAAC;gBAAE,EAAE,EAAE,MAAM,CAAC;gBAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;aAAE,CAAC,CAAC;SAC3D,CAAC,CAAC;KACH,CAAC;IACF,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG;QACrB,cAAc,IAAI,OAAO,CAAC;YAAE,OAAO,EAAE,YAAY,EAAE,CAAA;SAAE,CAAC,CAAC;KACvD,CAAC;CACF,CAAC;AA8BF;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,mBAAmB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CA0FzB;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAgBhE;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,OAAO,EAAE,mBAAmB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@businessdash/sdk/sitemap` — build a sitemap that matches YOUR site.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the platform cannot do this alone
|
|
5
|
+
*
|
|
6
|
+
* BusinessDash knows an org has 40 blog posts. It does not know whether their
|
|
7
|
+
* site renders them at `/blog/[slug]`, `/updates/[slug]`, `/news/[slug]`, or
|
|
8
|
+
* not at all. Guessing produces a sitemap full of URLs that 404 — which is
|
|
9
|
+
* meaningfully worse than a smaller sitemap, because a crawler that finds
|
|
10
|
+
* broken URLs in your sitemap discounts the whole file.
|
|
11
|
+
*
|
|
12
|
+
* So the split is: the platform emits the URLs whose shape it owns (site-builder
|
|
13
|
+
* pages, legal documents, programmatic pages — it defines those route
|
|
14
|
+
* patterns), and this merges in the rest using paths YOU declare.
|
|
15
|
+
*
|
|
16
|
+
* ## Everything is opt-in, and the default is omission
|
|
17
|
+
*
|
|
18
|
+
* A mobile mechanic has no store. If you do not declare `routes.product`, no
|
|
19
|
+
* product URLs are emitted — and even if you did, the platform would refuse the
|
|
20
|
+
* data because the org has no `ecommerce.storefront` entitlement. Two
|
|
21
|
+
* independent gates, both defaulting to "no".
|
|
22
|
+
*
|
|
23
|
+
* That asymmetry is deliberate. A missing URL costs you the indexing of one
|
|
24
|
+
* page, which Google will usually find by crawling anyway. A sitemap full of
|
|
25
|
+
* 404s costs you trust in every URL in the file. When unsure, this omits.
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const xml = await buildSitemap({
|
|
29
|
+
* client,
|
|
30
|
+
* siteId: SITE_ID,
|
|
31
|
+
* baseUrl: 'https://acme.com',
|
|
32
|
+
* staticPaths: ['/', '/about', '/contact'],
|
|
33
|
+
* routes: {
|
|
34
|
+
* blog: '/blog', // → /blog/{slug}
|
|
35
|
+
* product: '/store', // → /store/{id}
|
|
36
|
+
* // no `legal` key → the platform already emits those at their own slugs
|
|
37
|
+
* },
|
|
38
|
+
* })
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @module
|
|
42
|
+
*/
|
|
43
|
+
import { BiabAccessRejectedError } from "../errors.js";
|
|
44
|
+
import { isReservedPagePath } from "../reserved-paths.js";
|
|
45
|
+
function joinUrl(baseUrl, path) {
|
|
46
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
47
|
+
const suffix = path.startsWith("/") ? path : `/${path}`;
|
|
48
|
+
return `${base}${suffix === "/" ? "/" : suffix.replace(/\/+$/, "")}`;
|
|
49
|
+
}
|
|
50
|
+
function escapeXml(value) {
|
|
51
|
+
return value
|
|
52
|
+
.replace(/&/g, "&")
|
|
53
|
+
.replace(/</g, "<")
|
|
54
|
+
.replace(/>/g, ">")
|
|
55
|
+
.replace(/"/g, """)
|
|
56
|
+
.replace(/'/g, "'");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* True when a failure means "this org does not have that surface".
|
|
60
|
+
*
|
|
61
|
+
* A missing entitlement is a normal answer for most orgs, not an error — a
|
|
62
|
+
* plumber has no storefront. Anything else (a network fault, a bad key) is also
|
|
63
|
+
* swallowed per-section, because a sitemap that renders four of five sections
|
|
64
|
+
* is far better than one that 500s: a crawler retries a partial sitemap and
|
|
65
|
+
* gives up on an error page.
|
|
66
|
+
*/
|
|
67
|
+
function isExpectedAbsence(cause) {
|
|
68
|
+
return cause instanceof BiabAccessRejectedError;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Collect every URL for the site, deduplicated and ordered.
|
|
72
|
+
*
|
|
73
|
+
* Sections fail independently — one unreachable surface never takes the
|
|
74
|
+
* sitemap down with it.
|
|
75
|
+
*/
|
|
76
|
+
export async function collectSitemapEntries(options) {
|
|
77
|
+
const { client, baseUrl, routes = {} } = options;
|
|
78
|
+
const seen = new Map();
|
|
79
|
+
function add(path, lastmod) {
|
|
80
|
+
// The customer dashboard and the other token-gated surfaces never enter
|
|
81
|
+
// a sitemap — `/portal`, `/quotes/accept`, `/contracts/sign`,
|
|
82
|
+
// `/invoices/pay`. Each is per-customer and behind a token, so a crawler
|
|
83
|
+
// following one lands on a login redirect. That reads as a soft 404 and
|
|
84
|
+
// drags on the trust of every other URL in the file, quite apart from
|
|
85
|
+
// publishing the shape of a private area.
|
|
86
|
+
//
|
|
87
|
+
// Filtered here rather than only on the platform side because a
|
|
88
|
+
// consumer can pass `staticPaths: ['/portal']` by hand, and this is the
|
|
89
|
+
// last place to catch it.
|
|
90
|
+
if (isReservedPagePath(path))
|
|
91
|
+
return;
|
|
92
|
+
const loc = joinUrl(baseUrl, path);
|
|
93
|
+
// First writer wins: a hand-declared static path outranks the same URL
|
|
94
|
+
// discovered from content, because the consumer said it explicitly.
|
|
95
|
+
if (seen.has(loc))
|
|
96
|
+
return;
|
|
97
|
+
seen.set(loc, lastmod ? { loc, lastmod } : { loc });
|
|
98
|
+
}
|
|
99
|
+
// 1. Your own routes, first, so they take precedence on collision.
|
|
100
|
+
for (const path of options.staticPaths ?? [])
|
|
101
|
+
add(path);
|
|
102
|
+
// 2. What the platform owns the shape of: site-builder pages, legal
|
|
103
|
+
// documents, programmatic pages. These arrive as full paths.
|
|
104
|
+
try {
|
|
105
|
+
const { entries } = await client.site(options.siteId).sitemapEntries();
|
|
106
|
+
for (const entry of entries) {
|
|
107
|
+
// Already absolute from the platform — re-join so a consumer serving
|
|
108
|
+
// under a different origin than the org's primary domain still gets
|
|
109
|
+
// their own host rather than the platform's idea of it.
|
|
110
|
+
const path = entry.loc.replace(/^https?:\/\/[^/]+/, "");
|
|
111
|
+
add(path || "/", entry.lastmod);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (cause) {
|
|
115
|
+
options.onSkip?.("platform", isExpectedAbsence(cause)
|
|
116
|
+
? "org is not entitled to programmatic pages"
|
|
117
|
+
: "platform sitemap was unreachable");
|
|
118
|
+
}
|
|
119
|
+
// 3. Blog — only when you told us where it lives.
|
|
120
|
+
if (routes.blog) {
|
|
121
|
+
try {
|
|
122
|
+
const { posts } = await client.blog.listPosts({
|
|
123
|
+
limit: options.blogLimit ?? 1000,
|
|
124
|
+
});
|
|
125
|
+
for (const post of posts) {
|
|
126
|
+
add(`${routes.blog}/${post.slug}`, post.updatedAt ?? null);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (cause) {
|
|
130
|
+
options.onSkip?.("blog", isExpectedAbsence(cause)
|
|
131
|
+
? "org has no blog.public entitlement"
|
|
132
|
+
: "blog posts were unreachable");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
options.onSkip?.("blog", "no routes.blog declared");
|
|
137
|
+
}
|
|
138
|
+
// 4. Products — same rule.
|
|
139
|
+
if (routes.product) {
|
|
140
|
+
try {
|
|
141
|
+
const { products } = await client.storefront.listProducts({
|
|
142
|
+
limit: options.productLimit ?? 1000,
|
|
143
|
+
});
|
|
144
|
+
for (const product of products) {
|
|
145
|
+
add(`${routes.product}/${product.id}`, product.updatedAt ?? null);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (cause) {
|
|
149
|
+
options.onSkip?.("products", isExpectedAbsence(cause)
|
|
150
|
+
? "org has no ecommerce.storefront entitlement"
|
|
151
|
+
: "products were unreachable");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
options.onSkip?.("products", "no routes.product declared");
|
|
156
|
+
}
|
|
157
|
+
return [...seen.values()];
|
|
158
|
+
}
|
|
159
|
+
/** Serialise entries as a sitemap document. */
|
|
160
|
+
export function renderSitemapXml(entries) {
|
|
161
|
+
const body = entries
|
|
162
|
+
.map((entry) => {
|
|
163
|
+
const lastmod = entry.lastmod
|
|
164
|
+
? `\n <lastmod>${escapeXml(entry.lastmod)}</lastmod>`
|
|
165
|
+
: "";
|
|
166
|
+
return ` <url>\n <loc>${escapeXml(entry.loc)}</loc>${lastmod}\n </url>`;
|
|
167
|
+
})
|
|
168
|
+
.join("\n");
|
|
169
|
+
return ('<?xml version="1.0" encoding="UTF-8"?>\n' +
|
|
170
|
+
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' +
|
|
171
|
+
(body ? `${body}\n` : "") +
|
|
172
|
+
"</urlset>\n");
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The whole thing: collect, then serialise.
|
|
176
|
+
*
|
|
177
|
+
* Never throws. A sitemap route that 500s is worse than one that returns fewer
|
|
178
|
+
* URLs — crawlers retry a thin sitemap and back off from an error page.
|
|
179
|
+
*/
|
|
180
|
+
export async function buildSitemap(options) {
|
|
181
|
+
const entries = await collectSitemapEntries(options);
|
|
182
|
+
return renderSitemapXml(entries);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* A sitemap with only the homepage in it.
|
|
186
|
+
*
|
|
187
|
+
* The fallback when BusinessDash is unconfigured or unreachable. Deliberately
|
|
188
|
+
* NOT an empty `<urlset>`: an empty sitemap affirmatively tells a crawler the
|
|
189
|
+
* site has no pages, which is a worse claim than saying nothing. One honest URL
|
|
190
|
+
* is the smallest truthful document.
|
|
191
|
+
*/
|
|
192
|
+
export function minimalSitemapXml(baseUrl) {
|
|
193
|
+
return renderSitemapXml([{ loc: joinUrl(baseUrl, "/") }]);
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sitemap-core/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@businessdash/sdk/social` — everything needed to render social links,
|
|
3
|
+
* without any framework.
|
|
4
|
+
*
|
|
5
|
+
* Social links were React-and-Solid-only, and unlike every other gap this one
|
|
6
|
+
* was never about logic: `resolveSocialProfiles` already gave all eight
|
|
7
|
+
* bindings the data. What was missing was MARKUP, which cannot be shared
|
|
8
|
+
* between frameworks the way a controller can.
|
|
9
|
+
*
|
|
10
|
+
* So this module shares everything up to the markup — the resolved rows, the
|
|
11
|
+
* icon URL, and the handful of layout styles the list needs to work at all —
|
|
12
|
+
* and each binding writes the six elements around it. That keeps the part that
|
|
13
|
+
* can drift (which platforms exist, how a handle becomes a URL, where the icon
|
|
14
|
+
* comes from) in one place, and leaves each framework only the part that
|
|
15
|
+
* genuinely differs.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
export type SocialLinkRow = {
|
|
20
|
+
/** Stable platform key — usable as a list key. */
|
|
21
|
+
key: string;
|
|
22
|
+
/** Human label, e.g. "Instagram". Used for `aria-label` and `title`. */
|
|
23
|
+
label: string;
|
|
24
|
+
/** Fully-qualified profile URL. */
|
|
25
|
+
url: string;
|
|
26
|
+
/**
|
|
27
|
+
* Icon URL on the simple-icons CDN, or `null` for a platform with no brand
|
|
28
|
+
* icon — render the generic globe glyph in that case.
|
|
29
|
+
*/
|
|
30
|
+
iconUrl: string | null;
|
|
31
|
+
};
|
|
32
|
+
export type SocialLinksOptions = {
|
|
33
|
+
/**
|
|
34
|
+
* Icon colour for branded glyphs — a hex WITHOUT `#`, or a CSS colour
|
|
35
|
+
* keyword. Omit to use each brand's official colour.
|
|
36
|
+
*/
|
|
37
|
+
color?: string | undefined;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a company's `socials` record into render-ready rows.
|
|
41
|
+
*
|
|
42
|
+
* The icon URL is built here rather than in each binding because it encodes a
|
|
43
|
+
* CDN path and a colour convention — two things that should change in one
|
|
44
|
+
* place, not eight.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveSocialLinks(socials: unknown, options?: SocialLinksOptions): SocialLinkRow[];
|
|
47
|
+
/**
|
|
48
|
+
* The inline styles the list needs to lay out at all.
|
|
49
|
+
*
|
|
50
|
+
* Deliberately minimal — flex, wrap, gap, and resetting the list defaults. No
|
|
51
|
+
* colour, no borders, no sizing beyond the gap: everything visual is left to
|
|
52
|
+
* the consumer's own CSS via the class props each binding accepts. A component
|
|
53
|
+
* that ships opinions here is one the consumer has to fight.
|
|
54
|
+
*/
|
|
55
|
+
export declare const SOCIAL_LIST_STYLE: Readonly<Record<string, string>>;
|
|
56
|
+
/** The same, as a `style="…"` string for bindings that take one. */
|
|
57
|
+
export declare const SOCIAL_LIST_STYLE_STRING: string;
|
|
58
|
+
/**
|
|
59
|
+
* The fallback glyph for a platform with no brand icon, as an SVG path set.
|
|
60
|
+
*
|
|
61
|
+
* Shared so a consumer sees the same generic mark whichever framework they
|
|
62
|
+
* chose, rather than eight subtly different circles.
|
|
63
|
+
*/
|
|
64
|
+
export declare const SOCIAL_FALLBACK_GLYPH: {
|
|
65
|
+
readonly viewBox: "0 0 24 24";
|
|
66
|
+
readonly strokeWidth: 1.8;
|
|
67
|
+
readonly circle: {
|
|
68
|
+
readonly cx: 12;
|
|
69
|
+
readonly cy: 12;
|
|
70
|
+
readonly r: 9;
|
|
71
|
+
};
|
|
72
|
+
readonly path: "M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18";
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/social-core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,MAAM,aAAa,GAAG;IAC3B,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAChC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,kBAAuB,GAC9B,aAAa,EAAE,CAWjB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ9D,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,wBAAwB,EAAE,MAI5B,CAAC;AAEZ;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;CAKxB,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@businessdash/sdk/social` — everything needed to render social links,
|
|
3
|
+
* without any framework.
|
|
4
|
+
*
|
|
5
|
+
* Social links were React-and-Solid-only, and unlike every other gap this one
|
|
6
|
+
* was never about logic: `resolveSocialProfiles` already gave all eight
|
|
7
|
+
* bindings the data. What was missing was MARKUP, which cannot be shared
|
|
8
|
+
* between frameworks the way a controller can.
|
|
9
|
+
*
|
|
10
|
+
* So this module shares everything up to the markup — the resolved rows, the
|
|
11
|
+
* icon URL, and the handful of layout styles the list needs to work at all —
|
|
12
|
+
* and each binding writes the six elements around it. That keeps the part that
|
|
13
|
+
* can drift (which platforms exist, how a handle becomes a URL, where the icon
|
|
14
|
+
* comes from) in one place, and leaves each framework only the part that
|
|
15
|
+
* genuinely differs.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { resolveSocialProfiles } from "../socials.js";
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a company's `socials` record into render-ready rows.
|
|
22
|
+
*
|
|
23
|
+
* The icon URL is built here rather than in each binding because it encodes a
|
|
24
|
+
* CDN path and a colour convention — two things that should change in one
|
|
25
|
+
* place, not eight.
|
|
26
|
+
*/
|
|
27
|
+
export function resolveSocialLinks(socials, options = {}) {
|
|
28
|
+
return resolveSocialProfiles(socials).map((row) => ({
|
|
29
|
+
key: row.key,
|
|
30
|
+
label: row.label,
|
|
31
|
+
url: row.url,
|
|
32
|
+
iconUrl: row.iconSlug
|
|
33
|
+
? options.color
|
|
34
|
+
? `https://cdn.simpleicons.org/${row.iconSlug}/${encodeURIComponent(options.color)}`
|
|
35
|
+
: `https://cdn.simpleicons.org/${row.iconSlug}`
|
|
36
|
+
: null,
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The inline styles the list needs to lay out at all.
|
|
41
|
+
*
|
|
42
|
+
* Deliberately minimal — flex, wrap, gap, and resetting the list defaults. No
|
|
43
|
+
* colour, no borders, no sizing beyond the gap: everything visual is left to
|
|
44
|
+
* the consumer's own CSS via the class props each binding accepts. A component
|
|
45
|
+
* that ships opinions here is one the consumer has to fight.
|
|
46
|
+
*/
|
|
47
|
+
export const SOCIAL_LIST_STYLE = {
|
|
48
|
+
display: "flex",
|
|
49
|
+
"flex-wrap": "wrap",
|
|
50
|
+
"align-items": "center",
|
|
51
|
+
gap: "0.75rem",
|
|
52
|
+
"list-style": "none",
|
|
53
|
+
margin: "0",
|
|
54
|
+
padding: "0",
|
|
55
|
+
};
|
|
56
|
+
/** The same, as a `style="…"` string for bindings that take one. */
|
|
57
|
+
export const SOCIAL_LIST_STYLE_STRING = Object.entries(SOCIAL_LIST_STYLE)
|
|
58
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
59
|
+
.join(";");
|
|
60
|
+
/**
|
|
61
|
+
* The fallback glyph for a platform with no brand icon, as an SVG path set.
|
|
62
|
+
*
|
|
63
|
+
* Shared so a consumer sees the same generic mark whichever framework they
|
|
64
|
+
* chose, rather than eight subtly different circles.
|
|
65
|
+
*/
|
|
66
|
+
export const SOCIAL_FALLBACK_GLYPH = {
|
|
67
|
+
viewBox: "0 0 24 24",
|
|
68
|
+
strokeWidth: 1.8,
|
|
69
|
+
circle: { cx: 12, cy: 12, r: 9 },
|
|
70
|
+
path: "M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18",
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/social-core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAwBtD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CACjC,OAAgB,EAChB,UAA8B,EAAE;IAEhC,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnD,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,OAAO,EAAE,GAAG,CAAC,QAAQ;YACpB,CAAC,CAAC,OAAO,CAAC,KAAK;gBACd,CAAC,CAAC,+BAA+B,GAAG,CAAC,QAAQ,IAAI,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBACpF,CAAC,CAAC,+BAA+B,GAAG,CAAC,QAAQ,EAAE;YAChD,CAAC,CAAC,IAAI;KACP,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAqC;IAClE,OAAO,EAAE,MAAM;IACf,WAAW,EAAE,MAAM;IACnB,aAAa,EAAE,QAAQ;IACvB,GAAG,EAAE,SAAS;IACd,YAAY,EAAE,MAAM;IACpB,MAAM,EAAE,GAAG;IACX,OAAO,EAAE,GAAG;CACZ,CAAC;AAEF,oEAAoE;AACpE,MAAM,CAAC,MAAM,wBAAwB,GAAW,MAAM,CAAC,OAAO,CAC7D,iBAAiB,CACjB;KACC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;KAC5B,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACpC,OAAO,EAAE,WAAW;IACpB,WAAW,EAAE,GAAG;IAChB,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE;IAChC,IAAI,EAAE,sDAAsD;CACnD,CAAC"}
|
package/dist/social.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social.d.ts","sourceRoot":"","sources":["../src/social.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,wBAAwB,CAAC"}
|
package/dist/social.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social.js","sourceRoot":"","sources":["../src/social.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,wBAAwB,CAAC"}
|