@wix/agent-skills 1.20.0 → 1.21.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.
Files changed (183) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +14 -112
  3. package/skills/wix-app/references/APP_TOOLS.md +2 -1
  4. package/skills/wix-app/references/BACKEND_EVENT.md +3 -3
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +41 -152
  6. package/skills/wix-app/references/DASHBOARD_MODAL.md +4 -4
  7. package/skills/wix-app/references/SDK_MODULE_MAP.md +44 -0
  8. package/skills/wix-app/references/SITE_PLUGIN.md +36 -190
  9. package/skills/wix-app/references/app-tools/TOOLS.md +3 -1
  10. package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +21 -0
  11. package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +17 -0
  12. package/skills/wix-app/references/dashboard-plugin/SLOTS.md +4 -18
  13. package/skills/wix-app/references/site-plugin/EXAMPLES.md +1 -1
  14. package/skills/wix-headless-fast/SKILL.md +302 -51
  15. package/skills/wix-headless-fast/entry/skill.md +11 -2
  16. package/skills/wix-headless-fast/install/AGENTS.md +32 -0
  17. package/skills/wix-headless-fast/install/agents-md.mjs +39 -0
  18. package/skills/wix-headless-fast/install/attach.mjs +360 -0
  19. package/skills/wix-headless-fast/install/deploy.mjs +109 -9
  20. package/skills/wix-headless-fast/install/setup.mjs +239 -0
  21. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +226 -60
  22. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +2 -3
  23. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +2 -3
  24. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +24 -116
  25. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +16 -64
  26. package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +137 -0
  27. package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +78 -0
  28. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +117 -0
  29. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +13 -60
  30. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +47 -0
  31. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +10 -28
  32. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +2 -4
  33. package/skills/wix-headless-fast/references/blog/rest/posts.ts +42 -0
  34. package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +62 -0
  35. package/skills/wix-headless-fast/references/blog/seed/SEED.md +9 -0
  36. package/skills/wix-headless-fast/references/blog/seed/read-site.mjs +22 -0
  37. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +181 -33
  38. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +2 -1
  39. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +26 -132
  40. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +18 -49
  41. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +218 -0
  42. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +169 -0
  43. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +57 -142
  44. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +92 -0
  45. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +90 -0
  46. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +22 -61
  47. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +3 -1
  48. package/skills/wix-headless-fast/references/bookings/rest/booking.ts +113 -0
  49. package/skills/wix-headless-fast/references/bookings/rest/services.ts +55 -0
  50. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +10 -0
  51. package/skills/wix-headless-fast/references/bookings/seed/read-site.mjs +28 -0
  52. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +238 -62
  53. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +19 -52
  54. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +16 -36
  55. package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +158 -0
  56. package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +93 -0
  57. package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +177 -0
  58. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +13 -41
  59. package/skills/wix-headless-fast/references/cms/rest/items.ts +125 -0
  60. package/skills/wix-headless-fast/references/cms/seed/SEED.md +9 -0
  61. package/skills/wix-headless-fast/references/cms/seed/read-site.mjs +20 -0
  62. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +241 -83
  63. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +1 -1
  64. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +7 -5
  65. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +2 -2
  66. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +28 -110
  67. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +19 -54
  68. package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +130 -0
  69. package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +97 -0
  70. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +13 -94
  71. package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +113 -0
  72. package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +156 -0
  73. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +38 -69
  74. package/skills/wix-headless-fast/references/events/rest/events.ts +57 -0
  75. package/skills/wix-headless-fast/references/events/rest/registration.ts +83 -0
  76. package/skills/wix-headless-fast/references/events/seed/SEED.md +9 -0
  77. package/skills/wix-headless-fast/references/events/seed/read-site.mjs +26 -0
  78. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +216 -26
  79. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +35 -267
  80. package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +332 -0
  81. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +238 -0
  82. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +28 -243
  83. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +216 -0
  84. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +32 -204
  85. package/skills/wix-headless-fast/references/forms/rest/forms.ts +34 -0
  86. package/skills/wix-headless-fast/references/forms/rest/submissions.ts +56 -0
  87. package/skills/wix-headless-fast/references/forms/seed/SEED.md +8 -0
  88. package/skills/wix-headless-fast/references/forms/seed/read-site.mjs +20 -0
  89. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +15 -8
  90. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +316 -63
  91. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +1 -1
  92. package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +105 -0
  93. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +36 -65
  94. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +1 -1
  95. package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +43 -0
  96. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +11 -32
  97. package/skills/wix-headless-fast/references/members/rest/auth.ts +215 -0
  98. package/skills/wix-headless-fast/references/members/rest/members.ts +26 -0
  99. package/skills/wix-headless-fast/references/members/seed/read-site.mjs +15 -0
  100. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +240 -59
  101. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +2 -2
  102. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +2 -2
  103. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +35 -0
  104. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +8 -38
  105. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +23 -50
  106. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +16 -34
  107. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +22 -49
  108. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +82 -0
  109. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +58 -0
  110. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +177 -0
  111. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +31 -118
  112. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +81 -0
  113. package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +75 -0
  114. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +8 -0
  115. package/skills/wix-headless-fast/references/portfolio/seed/read-site.mjs +20 -0
  116. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +19 -21
  117. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +214 -51
  118. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +9 -20
  119. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +7 -32
  120. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +41 -0
  121. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +12 -33
  122. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +17 -34
  123. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +54 -0
  124. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +106 -0
  125. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +64 -0
  126. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +7 -55
  127. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +43 -0
  128. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +11 -34
  129. package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +31 -0
  130. package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +20 -0
  131. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +8 -0
  132. package/skills/wix-headless-fast/references/pricing-plans/seed/read-site.mjs +21 -0
  133. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +242 -47
  134. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +2 -2
  135. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +2 -2
  136. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +14 -35
  137. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +28 -171
  138. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +155 -0
  139. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +89 -0
  140. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +23 -117
  141. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +124 -0
  142. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +45 -114
  143. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +193 -0
  144. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +94 -0
  145. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +15 -87
  146. package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +60 -0
  147. package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +169 -0
  148. package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +68 -0
  149. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +8 -0
  150. package/skills/wix-headless-fast/references/restaurants/seed/read-site.mjs +25 -0
  151. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +25 -5
  152. package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +23 -0
  153. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +45 -4
  154. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +13 -0
  155. package/skills/wix-headless-fast/references/shared/rest/client.ts +155 -0
  156. package/skills/wix-headless-fast/references/shared/rest/config.ts +3 -0
  157. package/skills/wix-headless-fast/references/shared/rest/media.ts +65 -0
  158. package/skills/wix-headless-fast/references/shared/seed/read-site.mjs +99 -0
  159. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +186 -63
  160. package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +95 -0
  161. package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +29 -58
  162. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +29 -163
  163. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +26 -300
  164. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +121 -0
  165. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +49 -162
  166. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +314 -0
  167. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +47 -370
  168. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +147 -0
  169. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +289 -0
  170. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +2 -0
  171. package/skills/wix-headless-fast/references/storefront/rest/cart.ts +132 -0
  172. package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +123 -0
  173. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +31 -9
  174. package/skills/wix-headless-fast/references/storefront/seed/read-site.mjs +38 -0
  175. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +57 -50
  176. package/skills/wix-manage/references/ecommerce/ecom-shipping.md +1 -1
  177. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md +10 -19
  178. package/skills/wix-manage/references/events/create-wix-event.md +5 -1
  179. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +0 -40
  180. package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +3 -0
  181. package/skills/wix-vibe-headless/references/storefront/seed/seed-store.cjs +6 -0
  182. package/skills/wix-headless-fast/install/fast-path.mjs +0 -186
  183. package/skills/wix-headless-fast/install/pin-agents-md.mjs +0 -57
@@ -1,71 +1,24 @@
1
- // Post reads (Wix Blog V3) — the only file that touches raw post entities. Everything it
2
- // returns is a plain DTO from ./types. Copy as-is; extend by adding functions, not by editing
3
- // these. Blog posts are NOT CMS collections — always @wix/blog, never @wix/data.
1
+ // Post reads (Wix Blog V3) over the SDK — the only file that touches raw post entities on this
2
+ // transport. Everything it returns is a plain DTO from ./types. The rules and mappers live in
3
+ // ./posts-core (shared with the REST twin in references/blog/rest/); this file is the transport
4
+ // only. Copy as-is; extend by adding functions, not by editing these. Blog posts are NOT CMS
5
+ // collections — always @wix/blog, never @wix/data.
4
6
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/query-posts.md
5
7
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/get-post-by-slug.md
6
8
  import { posts as postsModule } from "@wix/blog";
7
9
  import { wixModule } from "../sdk";
8
10
  import { imgSrc } from "../media";
9
- import type { PostDetail, PostPage, PostSummary } from "./types";
11
+ import { BLOG_APP_ID, DETAIL_FIELDSETS, postMetaLine, toDetail, toSummary, type FetchPostsOptions, type Raw } from "./posts-core";
12
+ import type { PostDetail, PostPage } from "./types";
10
13
 
11
- const posts = wixModule(postsModule);
12
-
13
- /** The Wix Blog app id (Astro item-page routing; comments use it as appId). */
14
- export const BLOG_APP_ID = "14bcded7-0066-7c35-14d7-466cb3f09103";
15
-
16
- type Raw = Record<string, any>;
14
+ export { BLOG_APP_ID, postMetaLine, type FetchPostsOptions };
17
15
 
18
- function dateParts(value: unknown): { dateLabel: string; dateISO: string } {
19
- if (!value) return { dateLabel: "", dateISO: "" };
20
- const d = value instanceof Date ? value : new Date(String(value));
21
- if (Number.isNaN(d.getTime())) return { dateLabel: "", dateISO: "" };
22
- return {
23
- dateLabel: d.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" }),
24
- dateISO: d.toISOString(),
25
- };
26
- }
27
-
28
- function toSummary(raw: Raw): PostSummary {
29
- return {
30
- id: raw._id ?? "",
31
- slug: raw.slug ?? "",
32
- title: raw.title ?? "",
33
- excerpt: raw.excerpt ?? "",
34
- ...dateParts(raw.firstPublishedDate),
35
- minutesToRead: raw.minutesToRead ?? 0,
36
- featured: raw.featured === true,
37
- pinned: raw.pinned === true,
38
- // The cover is a media STRING (wix:image:// or https) at media.wixMedia.image.
39
- coverUrl: imgSrc(raw.media?.wixMedia?.image, 1200, 675),
40
- categoryIds: raw.categoryIds ?? [],
41
- tagIds: raw.tagIds ?? [],
42
- };
43
- }
44
-
45
- function toDetail(raw: Raw): PostDetail {
46
- return {
47
- ...toSummary(raw),
48
- richContent: raw.richContent ?? null,
49
- // contentText is plain text — split on newlines for the fallback body.
50
- paragraphs: String(raw.contentText ?? "")
51
- .split("\n")
52
- .map((s: string) => s.trim())
53
- .filter(Boolean),
54
- };
55
- }
56
-
57
- export interface FetchPostsOptions {
58
- limit?: number;
59
- /** `nextCursor` from a previous page. */
60
- cursor?: string | null;
61
- /** Server-side filters (first page only — the cursor carries them on later pages). */
62
- categoryId?: string | null;
63
- tagId?: string | null;
64
- }
16
+ const posts = wixModule(postsModule);
65
17
 
66
18
  /**
67
19
  * One page of published posts, newest first (pinned posts lead). Only published posts come
68
20
  * back to a visitor token — a "missing" post usually wasn't published, not a query bug.
21
+ * The builder below spells posts-core's feedQuery: sort + filters on the first page, the cursor alone after.
69
22
  */
70
23
  export async function fetchPosts({ limit = 20, cursor, categoryId, tagId }: FetchPostsOptions = {}): Promise<PostPage> {
71
24
  let q = posts.queryPosts().limit(limit);
@@ -79,7 +32,7 @@ export async function fetchPosts({ limit = 20, cursor, categoryId, tagId }: Fetc
79
32
  }
80
33
  const res = await q.find();
81
34
  return {
82
- posts: (res.items ?? []).map((p: Raw) => toSummary(p)),
35
+ posts: (res.items ?? []).map((p: Raw) => toSummary(p, imgSrc)),
83
36
  nextCursor: res.hasNext() ? (res.cursors?.next ?? null) : null,
84
37
  };
85
38
  }
@@ -90,10 +43,10 @@ export async function fetchPosts({ limit = 20, cursor, categoryId, tagId }: Fetc
90
43
  */
91
44
  export async function fetchPostBySlug(slug: string): Promise<PostDetail | null> {
92
45
  const res = await posts
93
- .queryPosts({ fieldsets: ["RICH_CONTENT", "CONTENT_TEXT"] })
46
+ .queryPosts({ fieldsets: [...DETAIL_FIELDSETS] as any })
94
47
  .eq("slug", slug)
95
48
  .limit(1)
96
49
  .find();
97
50
  const raw = res.items?.[0];
98
- return raw ? toDetail(raw as Raw) : null;
51
+ return raw ? toDetail(raw as Raw, imgSrc) : null;
99
52
  }
@@ -0,0 +1,47 @@
1
+ // Category + tag rules and DTO mapping — transport-agnostic, imported by both ./taxonomy.ts (SDK)
2
+ // and the REST twin in references/blog/rest/taxonomy.ts (fetch). Raw entities may carry `_id`
3
+ // (SDK) or `id` (REST). Has its own rawId/mediaValue (copies of posts-core's) so it stands alone
4
+ // when stripped; imports are type-only.
5
+ import type { BlogCategory, BlogTag } from "./types";
6
+ import type { ImgSrc, Raw } from "./posts-core";
7
+
8
+ /** Menu order — displayPosition ascending; -1 (unplaced) sorts first, which is also what the SDK path shows. */
9
+ export const CATEGORY_SORT = [{ fieldName: "displayPosition", order: "ASC" }] as const;
10
+ /** Most-published-posts first. */
11
+ export const TAG_SORT = [{ fieldName: "publishedPostCount", order: "DESC" }] as const;
12
+ /** Blog taxonomies are small — one read of up to 100 is the whole list. */
13
+ export const TAXONOMY_LIMIT = 100;
14
+
15
+ const rawId = (raw: Raw | undefined | null): string => raw?._id ?? raw?.id ?? "";
16
+
17
+ // A copy of posts-core's mediaValue: the REST Image object → the wix:image form imgSrc scales.
18
+ function mediaValue(value: unknown): string {
19
+ if (!value) return "";
20
+ if (typeof value === "string") return value;
21
+ const o = value as Raw;
22
+ if (o.id && !String(o.id).startsWith("http")) {
23
+ const size = o.width && o.height ? `#originWidth=${o.width}&originHeight=${o.height}` : "";
24
+ return `wix:image://v1/${o.id}/${o.filename ?? ""}${size}`;
25
+ }
26
+ return o.url ?? o.image ?? "";
27
+ }
28
+
29
+ export function toCategory(raw: Raw, imgSrc: ImgSrc): BlogCategory {
30
+ return {
31
+ id: rawId(raw),
32
+ slug: raw.slug ?? "",
33
+ label: raw.label ?? "", // the API's display name is `label`, never `name`
34
+ description: raw.description ?? "",
35
+ postCount: raw.postCount ?? 0,
36
+ coverUrl: imgSrc(mediaValue(raw.coverImage), 1200, 675),
37
+ };
38
+ }
39
+
40
+ export function toTag(raw: Raw): BlogTag {
41
+ return {
42
+ id: rawId(raw),
43
+ slug: raw.slug ?? "",
44
+ label: raw.label ?? "",
45
+ postCount: raw.publishedPostCount ?? 0, // PUBLISHED posts — postCount also counts drafts
46
+ };
47
+ }
@@ -1,42 +1,24 @@
1
- // Category + tag reads (Wix Blog V3) — the only file that touches raw taxonomy entities.
2
- // Everything it returns is a plain DTO from ./types. Copy as-is; extend by adding functions.
1
+ // Category + tag reads (Wix Blog V3) over the SDK — the only file that touches raw taxonomy
2
+ // entities on this transport. Everything it returns is a plain DTO from ./types. The mappers live
3
+ // in ./taxonomy-core (shared with the REST twin in references/blog/rest/); this file is the
4
+ // transport only. Copy as-is; extend by adding functions.
3
5
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/category/query-categories.md
4
6
  // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/tags/query-tags.md
5
7
  import { categories as categoriesModule, tags as tagsModule } from "@wix/blog";
6
8
  import { wixModule } from "../sdk";
7
9
  import { imgSrc } from "../media";
10
+ import { TAXONOMY_LIMIT, toCategory, toTag } from "./taxonomy-core";
11
+ import type { Raw } from "./posts-core";
8
12
  import type { BlogCategory, BlogTag } from "./types";
9
13
 
10
14
  const categories = wixModule(categoriesModule);
11
15
  const tags = wixModule(tagsModule);
12
16
 
13
- type Raw = Record<string, any>;
14
-
15
- function toCategory(raw: Raw): BlogCategory {
16
- return {
17
- id: raw._id ?? "",
18
- slug: raw.slug ?? "",
19
- label: raw.label ?? "",
20
- description: raw.description ?? "",
21
- postCount: raw.postCount ?? 0,
22
- coverUrl: imgSrc(raw.coverImage, 1200, 675),
23
- };
24
- }
25
-
26
- function toTag(raw: Raw): BlogTag {
27
- return {
28
- id: raw._id ?? "",
29
- slug: raw.slug ?? "",
30
- label: raw.label ?? "",
31
- postCount: raw.publishedPostCount ?? 0,
32
- };
33
- }
34
-
35
17
  /** Categories in menu order (displayPosition) — non-fatal (empty array on failure). */
36
18
  export async function fetchBlogCategories(): Promise<BlogCategory[]> {
37
19
  try {
38
- const res = await categories.queryCategories().ascending("displayPosition").limit(100).find();
39
- return (res.items ?? []).map((c: Raw) => toCategory(c)).filter((c) => c.id);
20
+ const res = await categories.queryCategories().ascending("displayPosition").limit(TAXONOMY_LIMIT).find();
21
+ return (res.items ?? []).map((c: Raw) => toCategory(c, imgSrc)).filter((c) => c.id);
40
22
  } catch {
41
23
  return [];
42
24
  }
@@ -45,7 +27,7 @@ export async function fetchBlogCategories(): Promise<BlogCategory[]> {
45
27
  /** Tags, most-published-posts first — non-fatal (empty array on failure). */
46
28
  export async function fetchBlogTags(): Promise<BlogTag[]> {
47
29
  try {
48
- const res = await tags.queryTags().descending("publishedPostCount").limit(100).find();
30
+ const res = await tags.queryTags().descending("publishedPostCount").limit(TAXONOMY_LIMIT).find();
49
31
  return (res.items ?? []).map((t: Raw) => toTag(t)).filter((t) => t.id);
50
32
  } catch {
51
33
  return [];
@@ -59,7 +41,7 @@ export async function fetchBlogTags(): Promise<BlogTag[]> {
59
41
  export async function fetchCategoryBySlug(slug: string): Promise<BlogCategory | null> {
60
42
  try {
61
43
  const res = await categories.getCategoryBySlug(slug);
62
- return res.category ? toCategory(res.category as Raw) : null;
44
+ return res.category ? toCategory(res.category as Raw, imgSrc) : null;
63
45
  } catch {
64
46
  return null;
65
47
  }
@@ -7,7 +7,7 @@
7
7
  // template below freely. The body island is client:only — the ricos viewer breaks under SSR.
8
8
  import SiteLayout from "../../layouts/SiteLayout.astro";
9
9
  import RichContent from "../../components/blog/RichContent";
10
- import { fetchPostBySlug } from "../../wix/blog/posts";
10
+ import { fetchPostBySlug, postMetaLine } from "../../wix/blog/posts";
11
11
  import { fetchBlogCategories, fetchBlogTags } from "../../wix/blog/taxonomy";
12
12
  import type { BlogCategory, BlogTag } from "../../wix/blog/types";
13
13
  import { WIX_APPS } from "@wix/essentials";
@@ -70,9 +70,7 @@ const postTags = allTags.filter((t) => post!.tagIds.includes(t.id));
70
70
  {postCategories.length > 0 && <p class="eyebrow">{postCategories.map((c) => c.label).join(" · ")}</p>}
71
71
  <h1 class="mt-2 text-3xl font-semibold tracking-tight">{post.title}</h1>
72
72
  <p class="mt-3 text-sm text-muted-foreground">
73
- {post.dateLabel && <time datetime={post.dateISO}>{post.dateLabel}</time>}
74
- {post.dateLabel && post.minutesToRead > 0 ? " · " : ""}
75
- {post.minutesToRead > 0 ? `${post.minutesToRead} min read` : ""}
73
+ <time datetime={post.dateISO}>{postMetaLine(post)}</time>
76
74
  </p>
77
75
  {
78
76
  post.coverUrl && (
@@ -0,0 +1,42 @@
1
+ // Post reads over REST — the twin of app/wix/blog/posts.ts. Same exports, same DTOs; the rules and
2
+ // mappers come from posts-core (the SAME file the SDK transport uses, deployed flat next to this one
3
+ // by deploy.mjs --stack static), so this file is only the transport: one fetch with a literal body
4
+ // per function. Every call here is safe from a browser with a visitor token — only PUBLISHED posts
5
+ // come back to it. Porting: keep the paths, keep the bodies, port the core once.
6
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/query-posts.md
7
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/get-post-by-slug.md
8
+ import { wixRequest } from "./client.js";
9
+ import { imgSrc } from "./media.js";
10
+ import { BLOG_APP_ID, DETAIL_FIELDSETS, feedQuery, postMetaLine, slugQuery, toDetail, toSummary, type FetchPostsOptions, type Raw } from "./posts-core.js";
11
+ import type { PostDetail, PostPage } from "./types.js";
12
+
13
+ export { BLOG_APP_ID, postMetaLine, type FetchPostsOptions };
14
+
15
+ const POSTS_QUERY = "/blog/v3/posts/query";
16
+
17
+ /**
18
+ * One page of published posts, newest first (pinned posts lead); `nextCursor` continues the same
19
+ * query — send it alone, the filters ride inside it.
20
+ * POST /blog/v3/posts/query { query: { filter?, sort, cursorPaging: { limit } } } — first page
21
+ * POST /blog/v3/posts/query { query: { cursorPaging: { limit, cursor } } } — later pages
22
+ */
23
+ export async function fetchPosts(o: FetchPostsOptions = {}): Promise<PostPage> {
24
+ const res = await wixRequest<Raw>(POSTS_QUERY, { body: { query: feedQuery(o) } });
25
+ const paging: Raw = res?.pagingMetadata ?? {};
26
+ return {
27
+ posts: ((res?.posts ?? []) as Raw[]).map((p) => toSummary(p, imgSrc)),
28
+ nextCursor: paging.hasNext ? (paging.cursors?.next ?? null) : null,
29
+ };
30
+ }
31
+
32
+ /**
33
+ * One post by URL slug with the full body (the RICH_CONTENT + CONTENT_TEXT fieldsets — without
34
+ * them richContent and contentText are absent). Null when the slug resolves to nothing — a real
35
+ * 404 for the page, never a fallback to another post.
36
+ * POST /blog/v3/posts/query { fieldsets: ["RICH_CONTENT", "CONTENT_TEXT"], query: { filter: { slug: { $eq } }, cursorPaging: { limit: 1 } } }
37
+ */
38
+ export async function fetchPostBySlug(slug: string): Promise<PostDetail | null> {
39
+ const res = await wixRequest<Raw>(POSTS_QUERY, { body: { fieldsets: DETAIL_FIELDSETS, query: slugQuery(slug) } });
40
+ const raw: Raw | undefined = res?.posts?.[0];
41
+ return raw ? toDetail(raw, imgSrc) : null;
42
+ }
@@ -0,0 +1,62 @@
1
+ // Category + tag reads over REST — the twin of app/wix/blog/taxonomy.ts. Same exports, same DTOs;
2
+ // the mappers come from taxonomy-core (the SAME file the SDK transport uses, deployed flat next to
3
+ // this one). Taxonomy queries page by OFFSET (`paging`), unlike posts (`cursorPaging`); a blog's
4
+ // taxonomy fits in one read of 100. All four calls are visitor-safe.
5
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/category/query-categories.md
6
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/category/get-category-by-slug.md
7
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/tags/query-tags.md
8
+ // docs: https://dev.wix.com/docs/api-reference/business-solutions/blog/tags/get-tag-by-slug.md
9
+ import { wixRequest } from "./client.js";
10
+ import { imgSrc } from "./media.js";
11
+ import { CATEGORY_SORT, TAG_SORT, TAXONOMY_LIMIT, toCategory, toTag } from "./taxonomy-core.js";
12
+ import type { Raw } from "./posts-core.js";
13
+ import type { BlogCategory, BlogTag } from "./types.js";
14
+
15
+ /**
16
+ * Categories in menu order. Non-fatal: [] on failure (the feed renders without its filter row).
17
+ * POST /blog/v3/categories/query { query: { sort: [{ fieldName: "displayPosition", order: "ASC" }], paging: { limit: 100 } } }
18
+ */
19
+ export async function fetchBlogCategories(): Promise<BlogCategory[]> {
20
+ try {
21
+ const res = await wixRequest<Raw>("/blog/v3/categories/query", { body: { query: { sort: CATEGORY_SORT, paging: { limit: TAXONOMY_LIMIT } } } });
22
+ return ((res?.categories ?? []) as Raw[]).map((c) => toCategory(c, imgSrc)).filter((c) => c.id);
23
+ } catch {
24
+ return [];
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Tags, most-published-posts first. Non-fatal: [] on failure.
30
+ * POST /blog/v3/tags/query { query: { sort: [{ fieldName: "publishedPostCount", order: "DESC" }], paging: { limit: 100 } } }
31
+ */
32
+ export async function fetchBlogTags(): Promise<BlogTag[]> {
33
+ try {
34
+ const res = await wixRequest<Raw>("/blog/v3/tags/query", { body: { query: { sort: TAG_SORT, paging: { limit: TAXONOMY_LIMIT } } } });
35
+ return ((res?.tags ?? []) as Raw[]).map(toTag).filter((t) => t.id);
36
+ } catch {
37
+ return [];
38
+ }
39
+ }
40
+
41
+ // The two by-slug getters answer in DIFFERENT envelopes ({ category } and { tag }); a missing slug
42
+ // is a 404 — mapped to null here, as the SDK transport does.
43
+
44
+ /** One category by its URL slug. Null when not found. GET /blog/v3/categories/slugs/{slug} */
45
+ export async function fetchCategoryBySlug(slug: string): Promise<BlogCategory | null> {
46
+ try {
47
+ const res = await wixRequest<Raw>(`/blog/v3/categories/slugs/${encodeURIComponent(slug)}`, { method: "GET" });
48
+ return res?.category ? toCategory(res.category, imgSrc) : null;
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+
54
+ /** One tag by its URL slug. Null when not found. GET /blog/v3/tags/slugs/{slug} */
55
+ export async function fetchTagBySlug(slug: string): Promise<BlogTag | null> {
56
+ try {
57
+ const res = await wixRequest<Raw>(`/blog/v3/tags/slugs/${encodeURIComponent(slug)}`, { method: "GET" });
58
+ return res?.tag ? toTag(res.tag) : null;
59
+ } catch {
60
+ return null;
61
+ }
62
+ }
@@ -62,6 +62,15 @@ feed without covers looks broken.
62
62
  **Seeding is additive — never delete or overwrite existing content**; ask first if a cleanup
63
63
  seems needed.
64
64
 
65
+ ## Supplied content
66
+
67
+ The general rules are in `references/shared/SUPPLIED-CONTENT.md`. For a blog, each post the user
68
+ hands over is one entry. Its title becomes `title`; its body becomes `content` blocks, one block per
69
+ paragraph, heading or list, whether the body arrived as text, HTML or Markdown; a category becomes
70
+ `category` (and joins the `categories` list); tags become `tags`; their cover image becomes
71
+ `coverImageUrl`. A post with no body is a question for the user. Authors and publish dates are
72
+ not seeded — say so.
73
+
65
74
  ## Escape hatch — individual functions
66
75
  `setupBlog` composes exported steps — `installBlogApp`, `getAuthorMemberId`, `createPosts`,
67
76
  `createCategories`, `createTags`, `importImage`, `attachPostCovers`, plus `makeCtx()` —
@@ -0,0 +1,22 @@
1
+ // What the blog holds: posts, categories, tags.
2
+ // node <SKILL_ROOT>/references/blog/seed/read-site.mjs [--site <siteId>] [--limit <n>]
3
+ import { runReader } from "../../shared/seed/read-site.mjs";
4
+
5
+ const BLOG_APP_ID = "14bcded7-0066-7c35-14d7-466cb3f09103";
6
+ const D = "https://dev.wix.com/docs/api-reference/business-solutions/blog";
7
+
8
+ await runReader({
9
+ vertical: "blog",
10
+ appId: BLOG_APP_ID,
11
+ async read(api, { limit }) {
12
+ const posts = await api.call({ path: "/v3/posts/query", body: { fieldsets: ["URL"], query: { paging: { limit } } }, docs: `${D}/posts-stats/query-posts` });
13
+ const cats = await api.tryCall({ path: "/blog/v3/categories/query", body: { query: { paging: { limit: 100 } } }, docs: `${D}/category/query-categories` });
14
+ const tags = await api.tryCall({ path: "/v3/tags/query", body: { query: { paging: { limit: 100 } } }, docs: `${D}/tags/query-tags` });
15
+ return {
16
+ postCount: posts.metaData?.total ?? posts.pagingMetadata?.total ?? (posts.posts ?? []).length,
17
+ posts: (posts.posts ?? []).map((p) => ({ title: p.title, slug: p.slug, published: p.firstPublishedDate ?? null, cover: !!p.coverMedia?.image, categories: (p.categoryIds ?? []).length, tags: (p.tagIds ?? []).length, minutesToRead: p.minutesToRead ?? null })),
18
+ categories: (cats?.categories ?? []).map((c) => ({ id: c.id, label: c.label, slug: c.slug, postCount: c.postCount ?? null })),
19
+ tags: (tags?.tags ?? []).map((t) => ({ id: t.id, label: t.label, postCount: t.postCount ?? null })),
20
+ };
21
+ },
22
+ });