create-snapify-app 0.0.0-stage → 1.1.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 (614) hide show
  1. package/LICENSE.md +24 -0
  2. package/README.md +55 -2
  3. package/bin/create-snapify-app.mjs +174 -0
  4. package/lib/args.mjs +59 -0
  5. package/lib/copy.mjs +44 -0
  6. package/lib/env.mjs +84 -0
  7. package/lib/prompt.mjs +63 -0
  8. package/package.json +33 -4
  9. package/template/.env.example +79 -0
  10. package/template/.github/workflows/ci.yml +23 -0
  11. package/template/.github/workflows/deploy.yml +26 -0
  12. package/template/.github/workflows/ping.yml +8 -0
  13. package/template/.github/workflows/release.yml +67 -0
  14. package/template/.snapify-install.json +5 -0
  15. package/template/CHANGELOG.md +28 -0
  16. package/template/LICENSE +14 -0
  17. package/template/README.md +287 -0
  18. package/template/administrator.html +23 -0
  19. package/template/apps/client/src/App.tsx +765 -0
  20. package/template/apps/client/src/auth.css +400 -0
  21. package/template/apps/client/src/lib/api.ts +22 -0
  22. package/template/apps/client/src/main.tsx +20 -0
  23. package/template/apps/community/src/App.tsx +592 -0
  24. package/template/apps/community/src/main.tsx +20 -0
  25. package/template/apps/community/src/styles.css +24 -0
  26. package/template/apps/developers/src/App.tsx +643 -0
  27. package/template/apps/developers/src/main.tsx +17 -0
  28. package/template/apps/developers/src/pages.tsx +1587 -0
  29. package/template/apps/developers/src/styles.css +98 -0
  30. package/template/apps/developers/src/ui.tsx +179 -0
  31. package/template/apps/landing/src/App.tsx +598 -0
  32. package/template/apps/landing/src/LegalPages.tsx +158 -0
  33. package/template/apps/landing/src/OrderPage.tsx +381 -0
  34. package/template/apps/landing/src/SeoPages.tsx +923 -0
  35. package/template/apps/landing/src/copy.ts +195 -0
  36. package/template/apps/landing/src/main.tsx +20 -0
  37. package/template/apps/landing/src/styles.css +803 -0
  38. package/template/apps/landing/src/types.ts +19 -0
  39. package/template/apps/marketplace/src/App.tsx +1229 -0
  40. package/template/apps/marketplace/src/developer/DeveloperApp.tsx +1266 -0
  41. package/template/apps/marketplace/src/main.tsx +20 -0
  42. package/template/apps/marketplace/src/styles.css +1001 -0
  43. package/template/apps/shared/AuthContext.tsx +65 -0
  44. package/template/apps/shared/Logo.tsx +33 -0
  45. package/template/apps/shared/api.ts +47 -0
  46. package/template/apps/shared/ui.tsx +128 -0
  47. package/template/apps/superadmin/src/App.tsx +1264 -0
  48. package/template/apps/superadmin/src/lib/api.ts +20 -0
  49. package/template/apps/superadmin/src/lib/hooks.ts +20 -0
  50. package/template/apps/superadmin/src/main.tsx +16 -0
  51. package/template/apps/superadmin/src/pages/ClientsPage.tsx +185 -0
  52. package/template/apps/superadmin/src/pages/InvoicesPage.tsx +157 -0
  53. package/template/apps/superadmin/src/pages/NewsletterPage.tsx +212 -0
  54. package/template/apps/superadmin/src/pages/OrdersPage.tsx +195 -0
  55. package/template/apps/superadmin/src/pages/PaymentsPage.tsx +150 -0
  56. package/template/apps/superadmin/src/pages/PayoutsPage.tsx +133 -0
  57. package/template/apps/superadmin/src/pages/PublishersPage.tsx +151 -0
  58. package/template/apps/superadmin/src/pages/SeoControlPage.tsx +692 -0
  59. package/template/apps/superadmin/src/pages/SettingsPage.tsx +199 -0
  60. package/template/apps/superadmin/src/pages/SystemPage.tsx +109 -0
  61. package/template/apps/superadmin/src/pages/TicketsPage.tsx +201 -0
  62. package/template/apps/superadmin/src/pages/UsersPage.tsx +167 -0
  63. package/template/client.html +21 -0
  64. package/template/community/hamdiayari/akhbar/README.md +23 -0
  65. package/template/community/hamdiayari/akhbar/screenshot.jpg +0 -0
  66. package/template/community/hamdiayari/akhbar/snapify.theme.json +76 -0
  67. package/template/community/hamdiayari/akhbar/src/Brand.tsx +26 -0
  68. package/template/community/hamdiayari/akhbar/src/Footer.tsx +182 -0
  69. package/template/community/hamdiayari/akhbar/src/Header.tsx +191 -0
  70. package/template/community/hamdiayari/akhbar/src/Layout.tsx +49 -0
  71. package/template/community/hamdiayari/akhbar/src/Social.tsx +33 -0
  72. package/template/community/hamdiayari/akhbar/src/Ticker.tsx +86 -0
  73. package/template/community/hamdiayari/akhbar/src/Views.tsx +285 -0
  74. package/template/community/hamdiayari/akhbar/src/blocks/CollectionBlocks.tsx +672 -0
  75. package/template/community/hamdiayari/akhbar/src/blocks/ContentBlocks.tsx +305 -0
  76. package/template/community/hamdiayari/akhbar/src/blocks/ConversionBlocks.tsx +569 -0
  77. package/template/community/hamdiayari/akhbar/src/blocks/HeaderBlocks.tsx +287 -0
  78. package/template/community/hamdiayari/akhbar/src/index.tsx +51 -0
  79. package/template/community/hamdiayari/akhbar/src/kit.tsx +357 -0
  80. package/template/community/hamdiayari/akhbar/src/site.ts +96 -0
  81. package/template/community/hamdiayari/akhbar/src/styles.css +566 -0
  82. package/template/community/hamdiayari/akhbar-actualites/README.md +28 -0
  83. package/template/community/hamdiayari/akhbar-actualites/screenshot.jpg +0 -0
  84. package/template/community/hamdiayari/akhbar-actualites/snapify.module.json +107 -0
  85. package/template/community/hamdiayari/akhbar-actualites/src/admin/AudiencePage.tsx +185 -0
  86. package/template/community/hamdiayari/akhbar-actualites/src/admin/index.tsx +11 -0
  87. package/template/community/hamdiayari/akhbar-actualites/src/public/Archive.tsx +142 -0
  88. package/template/community/hamdiayari/akhbar-actualites/src/public/cards.tsx +152 -0
  89. package/template/community/hamdiayari/akhbar-actualites/src/public/index.tsx +71 -0
  90. package/template/community/hamdiayari/akhbar-actualites/src/public/posts.ts +103 -0
  91. package/template/community/hamdiayari/akhbar-actualites/src/public/styles.css +568 -0
  92. package/template/community/hamdiayari/akhbar-actualites/src/public/widgets.tsx +226 -0
  93. package/template/community/hamdiayari/akhbar-actualites/src/server.ts +119 -0
  94. package/template/community/hamdiayari/akhbar-actualites/src/types.ts +25 -0
  95. package/template/community/hamdiayari/akhbar-urgent/README.md +36 -0
  96. package/template/community/hamdiayari/akhbar-urgent/screenshot.jpg +0 -0
  97. package/template/community/hamdiayari/akhbar-urgent/snapify.module.json +64 -0
  98. package/template/community/hamdiayari/akhbar-urgent/src/admin/FlashesPage.tsx +229 -0
  99. package/template/community/hamdiayari/akhbar-urgent/src/admin/index.tsx +11 -0
  100. package/template/community/hamdiayari/akhbar-urgent/src/public/Ticker.tsx +81 -0
  101. package/template/community/hamdiayari/akhbar-urgent/src/public/index.tsx +63 -0
  102. package/template/community/hamdiayari/akhbar-urgent/src/public/styles.css +142 -0
  103. package/template/community/hamdiayari/akhbar-urgent/src/server.ts +101 -0
  104. package/template/community/hamdiayari/akhbar-urgent/src/types.ts +35 -0
  105. package/template/community.html +21 -0
  106. package/template/developers.html +24 -0
  107. package/template/docker-compose.db.yml +24 -0
  108. package/template/docs/BACKOFFICE_SNAPIFY.md +130 -0
  109. package/template/docs/CI_CD.md +66 -0
  110. package/template/docs/MODULES.md +346 -0
  111. package/template/docs/PLATFORM_DEPLOY.md +54 -0
  112. package/template/docs/logo.svg +10 -0
  113. package/template/drizzle/0000_init.sql +147 -0
  114. package/template/drizzle/0001_page_project.sql +5 -0
  115. package/template/drizzle/0002_modules.sql +23 -0
  116. package/template/drizzle/0003_themes.sql +4 -0
  117. package/template/drizzle/0004_security.sql +82 -0
  118. package/template/drizzle/0005_module_records.sql +16 -0
  119. package/template/drizzle/0006_avatars.sql +4 -0
  120. package/template/drizzle/0007_platform.sql +264 -0
  121. package/template/drizzle/0008_mp_validation.sql +3 -0
  122. package/template/drizzle/0009_saas_ops.sql +77 -0
  123. package/template/drizzle/0010_cms_chrome.sql +13 -0
  124. package/template/drizzle/0011_client_portal.sql +26 -0
  125. package/template/drizzle/meta/0000_snapshot.json +998 -0
  126. package/template/drizzle/meta/0001_snapshot.json +1004 -0
  127. package/template/drizzle/meta/_journal.json +90 -0
  128. package/template/drizzle.config.ts +16 -0
  129. package/template/ecosystem.snapify.cjs +24 -0
  130. package/template/for.html +1 -0
  131. package/template/index.html +29 -0
  132. package/template/landing.html +37 -0
  133. package/template/marketplace/catalog.json +373 -0
  134. package/template/marketplace/gallery/hamdiayari.preveris/01-home.jpg +0 -0
  135. package/template/marketplace/gallery/hamdiayari.recaptcha/01-reglages.jpg +0 -0
  136. package/template/marketplace/gallery/hamdiayari.recaptcha/02-logo.jpg +0 -0
  137. package/template/marketplace/gallery/novalabs.ai-articles/01-generer.jpg +0 -0
  138. package/template/marketplace/gallery/novalabs.ai-articles/02-fournisseur-ia.jpg +0 -0
  139. package/template/marketplace/gallery/novalabs.calendar/01-agenda-site.jpg +0 -0
  140. package/template/marketplace/gallery/novalabs.calendar/02-evenements-admin.jpg +0 -0
  141. package/template/marketplace/gallery/novalabs.calendar/03-reglages.jpg +0 -0
  142. package/template/marketplace/screenshots/hamdiayari.preveris-1.0.6.jpg +0 -0
  143. package/template/marketplace/screenshots/hamdiayari.recaptcha-1.0.0.jpg +0 -0
  144. package/template/marketplace/screenshots/hamdiayari.wp-seo-migrator-1.1.1.jpg +0 -0
  145. package/template/marketplace/screenshots/novalabs.ai-articles-1.0.1.jpg +0 -0
  146. package/template/marketplace/screenshots/novalabs.ai-chat-1.0.1.jpg +0 -0
  147. package/template/marketplace/screenshots/novalabs.calendar-1.0.1.jpg +0 -0
  148. package/template/marketplace/screenshots/novalabs.cart-1.0.0.jpg +0 -0
  149. package/template/marketplace/screenshots/novalabs.checkout-1.0.0.jpg +0 -0
  150. package/template/marketplace/screenshots/novalabs.customers-1.1.0.jpg +0 -0
  151. package/template/marketplace/screenshots/novalabs.dogga-1.0.0.jpg +0 -0
  152. package/template/marketplace/screenshots/novalabs.mahdia-1.0.0.jpg +0 -0
  153. package/template/marketplace/screenshots/novalabs.shop-1.0.0.jpg +0 -0
  154. package/template/marketplace/screenshots/novalabs.sidibou-1.0.0.jpg +0 -0
  155. package/template/marketplace/screenshots/novalabs.whatsapp-1.0.1.jpg +0 -0
  156. package/template/marketplace.html +21 -0
  157. package/template/metadata.json +7 -0
  158. package/template/modules/ai-articles/screenshot.jpg +0 -0
  159. package/template/modules/ai-articles/snapify.module.json +74 -0
  160. package/template/modules/ai-articles/src/admin/ArticlesPage.tsx +162 -0
  161. package/template/modules/ai-articles/src/admin/GeneratePage.tsx +118 -0
  162. package/template/modules/ai-articles/src/admin/index.tsx +12 -0
  163. package/template/modules/ai-articles/src/public/index.tsx +119 -0
  164. package/template/modules/ai-articles/src/server.ts +287 -0
  165. package/template/modules/ai-articles/src/types.ts +30 -0
  166. package/template/modules/ai-chat/screenshot.jpg +0 -0
  167. package/template/modules/ai-chat/snapify.module.json +217 -0
  168. package/template/modules/ai-chat/src/public.tsx +198 -0
  169. package/template/modules/ai-chat/src/server.ts +142 -0
  170. package/template/modules/ai-theme-studio/README.md +15 -0
  171. package/template/modules/ai-theme-studio/screenshot.jpg +0 -0
  172. package/template/modules/ai-theme-studio/snapify.module.json +175 -0
  173. package/template/modules/ai-theme-studio/src/admin/HistoryPage.tsx +91 -0
  174. package/template/modules/ai-theme-studio/src/admin/StudioPage.tsx +414 -0
  175. package/template/modules/ai-theme-studio/src/admin/index.tsx +11 -0
  176. package/template/modules/ai-theme-studio/src/lib/images.ts +240 -0
  177. package/template/modules/ai-theme-studio/src/lib/llm.ts +123 -0
  178. package/template/modules/ai-theme-studio/src/lib/normalize.ts +714 -0
  179. package/template/modules/ai-theme-studio/src/lib/prompts.ts +198 -0
  180. package/template/modules/ai-theme-studio/src/server.ts +137 -0
  181. package/template/modules/ai-theme-studio/src/types.ts +112 -0
  182. package/template/modules/calendar/screenshot.jpg +0 -0
  183. package/template/modules/calendar/snapify.module.json +45 -0
  184. package/template/modules/calendar/src/admin/EventsPage.tsx +217 -0
  185. package/template/modules/calendar/src/admin/index.tsx +11 -0
  186. package/template/modules/calendar/src/public/index.tsx +231 -0
  187. package/template/modules/calendar/src/server.ts +143 -0
  188. package/template/modules/calendar/src/types.ts +25 -0
  189. package/template/modules/cart/screenshot.jpg +0 -0
  190. package/template/modules/cart/snapify.module.json +90 -0
  191. package/template/modules/cart/src/admin/index.tsx +265 -0
  192. package/template/modules/cart/src/public/CartPage.tsx +198 -0
  193. package/template/modules/cart/src/public/index.tsx +261 -0
  194. package/template/modules/cart/src/public/useQuote.ts +67 -0
  195. package/template/modules/cart/src/server.ts +148 -0
  196. package/template/modules/cart/src/types.ts +31 -0
  197. package/template/modules/checkout/screenshot.jpg +0 -0
  198. package/template/modules/checkout/snapify.module.json +264 -0
  199. package/template/modules/checkout/src/admin/OrderDetailPage.tsx +304 -0
  200. package/template/modules/checkout/src/admin/badges.tsx +28 -0
  201. package/template/modules/checkout/src/admin/index.tsx +236 -0
  202. package/template/modules/checkout/src/public/CheckoutPage.tsx +461 -0
  203. package/template/modules/checkout/src/public/OrderPages.tsx +153 -0
  204. package/template/modules/checkout/src/public/index.tsx +23 -0
  205. package/template/modules/checkout/src/server.ts +383 -0
  206. package/template/modules/checkout/src/types.ts +70 -0
  207. package/template/modules/customers/screenshot.jpg +0 -0
  208. package/template/modules/customers/snapify.module.json +115 -0
  209. package/template/modules/customers/src/admin/CustomerDetailPage.tsx +274 -0
  210. package/template/modules/customers/src/admin/index.tsx +194 -0
  211. package/template/modules/customers/src/public/AccountPages.tsx +470 -0
  212. package/template/modules/customers/src/public/AddressForm.tsx +115 -0
  213. package/template/modules/customers/src/public/AuthPages.tsx +349 -0
  214. package/template/modules/customers/src/public/Avatar.tsx +29 -0
  215. package/template/modules/customers/src/public/ProfileSection.tsx +291 -0
  216. package/template/modules/customers/src/public/index.tsx +137 -0
  217. package/template/modules/customers/src/public/session.ts +51 -0
  218. package/template/modules/customers/src/server.ts +421 -0
  219. package/template/modules/customers/src/types.ts +53 -0
  220. package/template/modules/recaptcha/logo.jpg +0 -0
  221. package/template/modules/recaptcha/screenshot.jpg +0 -0
  222. package/template/modules/recaptcha/snapify.module.json +99 -0
  223. package/template/modules/recaptcha/src/public/index.tsx +94 -0
  224. package/template/modules/recaptcha/src/server.ts +65 -0
  225. package/template/modules/recaptcha/src/types.ts +18 -0
  226. package/template/modules/shop/screenshot.jpg +0 -0
  227. package/template/modules/shop/snapify.module.json +340 -0
  228. package/template/modules/shop/src/admin/CategoriesPage.tsx +224 -0
  229. package/template/modules/shop/src/admin/ProductEditor.tsx +313 -0
  230. package/template/modules/shop/src/admin/ProductsPage.tsx +307 -0
  231. package/template/modules/shop/src/admin/index.tsx +14 -0
  232. package/template/modules/shop/src/public/Catalog.tsx +244 -0
  233. package/template/modules/shop/src/public/NotFound.tsx +22 -0
  234. package/template/modules/shop/src/public/ProductPage.tsx +195 -0
  235. package/template/modules/shop/src/public/index.tsx +134 -0
  236. package/template/modules/shop/src/public/useFetch.ts +26 -0
  237. package/template/modules/shop/src/server.ts +493 -0
  238. package/template/modules/shop/src/shared.ts +41 -0
  239. package/template/modules/shop/src/types.ts +60 -0
  240. package/template/modules/whatsapp/screenshot.jpg +0 -0
  241. package/template/modules/whatsapp/snapify.module.json +121 -0
  242. package/template/modules/whatsapp/src/public.tsx +119 -0
  243. package/template/modules/wp-seo-migrator/ARCHITECTURE.md +113 -0
  244. package/template/modules/wp-seo-migrator/README.md +21 -0
  245. package/template/modules/wp-seo-migrator/fixtures/aioseo-sample.csv +3 -0
  246. package/template/modules/wp-seo-migrator/fixtures/sample-exporter.json +39 -0
  247. package/template/modules/wp-seo-migrator/fixtures/sample-page.html +12 -0
  248. package/template/modules/wp-seo-migrator/fixtures/sample.htaccess +3 -0
  249. package/template/modules/wp-seo-migrator/screenshot.jpg +0 -0
  250. package/template/modules/wp-seo-migrator/snapify.module.json +87 -0
  251. package/template/modules/wp-seo-migrator/src/admin/HistoryPage.tsx +64 -0
  252. package/template/modules/wp-seo-migrator/src/admin/WizardPage.tsx +788 -0
  253. package/template/modules/wp-seo-migrator/src/admin/i18n.ts +156 -0
  254. package/template/modules/wp-seo-migrator/src/admin/index.tsx +11 -0
  255. package/template/modules/wp-seo-migrator/src/connectors/CUSTOM_CONNECTOR.md +31 -0
  256. package/template/modules/wp-seo-migrator/src/connectors/csvSeoFactory.ts +106 -0
  257. package/template/modules/wp-seo-migrator/src/connectors/exporter.ts +96 -0
  258. package/template/modules/wp-seo-migrator/src/connectors/gscCsv.ts +53 -0
  259. package/template/modules/wp-seo-migrator/src/connectors/htaccess.ts +65 -0
  260. package/template/modules/wp-seo-migrator/src/connectors/htmlCrawler.ts +90 -0
  261. package/template/modules/wp-seo-migrator/src/connectors/index.ts +113 -0
  262. package/template/modules/wp-seo-migrator/src/connectors/pluginCsv.ts +77 -0
  263. package/template/modules/wp-seo-migrator/src/connectors/rankMathCsv.ts +77 -0
  264. package/template/modules/wp-seo-migrator/src/connectors/redirection.ts +62 -0
  265. package/template/modules/wp-seo-migrator/src/connectors/sitemap.ts +44 -0
  266. package/template/modules/wp-seo-migrator/src/connectors/utils.ts +111 -0
  267. package/template/modules/wp-seo-migrator/src/connectors/wxr.ts +103 -0
  268. package/template/modules/wp-seo-migrator/src/connectors/yoastCsv.ts +56 -0
  269. package/template/modules/wp-seo-migrator/src/pipeline/analyze.ts +158 -0
  270. package/template/modules/wp-seo-migrator/src/pipeline/htmlParse.ts +58 -0
  271. package/template/modules/wp-seo-migrator/src/pipeline/remoteAuto.ts +328 -0
  272. package/template/modules/wp-seo-migrator/src/server.ts +492 -0
  273. package/template/modules/wp-seo-migrator/src/types.ts +151 -0
  274. package/template/modules/wp-seo-migrator/tests/connectors-extra.test.ts +39 -0
  275. package/template/modules/wp-seo-migrator/tests/merge.test.ts +25 -0
  276. package/template/package-lock.json +6016 -0
  277. package/template/package.json +74 -0
  278. package/template/public/images/photos/caravane-chameaux-desert.webp +0 -0
  279. package/template/public/images/photos/hammamet-medina-plage.jpg +0 -0
  280. package/template/public/images/photos/maison-campagne-collines.webp +0 -0
  281. package/template/public/images/photos/maisons-troglodytes-desert.jpg +0 -0
  282. package/template/public/images/photos/panorama-ville.jpg +0 -0
  283. package/template/public/images/photos/preveris-accessibilite-erp.jpg +0 -0
  284. package/template/public/images/photos/preveris-collectivites.jpg +0 -0
  285. package/template/public/images/photos/preveris-etudes-plans.jpg +0 -0
  286. package/template/public/images/photos/preveris-hero-erp.jpg +0 -0
  287. package/template/public/images/photos/preveris-ssi-incendie.jpg +0 -0
  288. package/template/public/images/photos/preveris-suivi-hotel.jpg +0 -0
  289. package/template/public/images/photos/ruelle-bleue-medina.jpg +0 -0
  290. package/template/public/images/photos/sidi-bou-said-port.webp +0 -0
  291. package/template/public/images/photos/terrasse-blanche-mer-voilier.jpg +0 -0
  292. package/template/public/landing/hero-ai-cms.jpg +0 -0
  293. package/template/public/landing/shot-dogga.jpg +0 -0
  294. package/template/public/landing/shot-mahdia.jpg +0 -0
  295. package/template/public/landing/shot-sidibou.jpg +0 -0
  296. package/template/public/llms.txt +35 -0
  297. package/template/public/logo.svg +10 -0
  298. package/template/scripts/app-pack.ts +155 -0
  299. package/template/scripts/app-publish.ts +100 -0
  300. package/template/scripts/apply-ecommerce-home.ts +196 -0
  301. package/template/scripts/auto-deploy-poll.sh +13 -0
  302. package/template/scripts/db-backup.sh +16 -0
  303. package/template/scripts/db-restore.sh +11 -0
  304. package/template/scripts/deploy.sh +34 -0
  305. package/template/scripts/github-webhook-deploy.sh +7 -0
  306. package/template/scripts/install-new-modules.ts +96 -0
  307. package/template/scripts/refresh-demo-baseline.ts +9 -0
  308. package/template/scripts/reinstall-marketplace-packs.ts +51 -0
  309. package/template/scripts/restore-classic-home.ts +13 -0
  310. package/template/scripts/sdk-pack.ts +289 -0
  311. package/template/scripts/sdk-publish.ts +75 -0
  312. package/template/scripts/seed-demo-products.ts +120 -0
  313. package/template/scripts/seed-theme-content-packs.ts +42 -0
  314. package/template/scripts/snapify-module.ts +207 -0
  315. package/template/scripts/test-theme-switch.ts +24 -0
  316. package/template/sdk/admin.css +18 -0
  317. package/template/sdk/admin.ts +95 -0
  318. package/template/sdk/build.ts +249 -0
  319. package/template/sdk/commerce.ts +512 -0
  320. package/template/sdk/content.ts +76 -0
  321. package/template/sdk/icons.ts +101 -0
  322. package/template/sdk/image.ts +60 -0
  323. package/template/sdk/index.ts +500 -0
  324. package/template/sdk/package.ts +298 -0
  325. package/template/sdk/recaptcha.tsx +122 -0
  326. package/template/sdk/settings.ts +84 -0
  327. package/template/sdk/theme.css +29 -0
  328. package/template/sdk/theme.ts +100 -0
  329. package/template/sdk/ui/commerce.tsx +385 -0
  330. package/template/sdk/ui/orders.tsx +136 -0
  331. package/template/sdk-kit/CHANGELOG.md +17 -0
  332. package/template/sdk-kit/LICENSE.md +47 -0
  333. package/template/sdk-kit/README.md +81 -0
  334. package/template/sdk-kit/cli.ts +339 -0
  335. package/template/sdk-kit/create-snapify/README.md +28 -0
  336. package/template/sdk-kit/create-snapify/create-snapify.mjs +11 -0
  337. package/template/sdk-kit/create-snapify/package.template.json +16 -0
  338. package/template/sdk-kit/package.template.json +95 -0
  339. package/template/sdk-kit/templates/common/README.md.tpl +27 -0
  340. package/template/sdk-kit/templates/common/_gitignore +3 -0
  341. package/template/sdk-kit/templates/common/package.json.tpl +19 -0
  342. package/template/sdk-kit/templates/common/src/snapify-env.d.ts +2 -0
  343. package/template/sdk-kit/templates/common/tsconfig.json +15 -0
  344. package/template/sdk-kit/templates/module/snapify.module.json.tpl +33 -0
  345. package/template/sdk-kit/templates/module/src/admin.tsx +53 -0
  346. package/template/sdk-kit/templates/module/src/public.tsx +49 -0
  347. package/template/sdk-kit/templates/module/src/server.ts +30 -0
  348. package/template/sdk-kit/templates/module/src/types.ts +19 -0
  349. package/template/sdk-kit/templates/theme/snapify.theme.json.tpl +22 -0
  350. package/template/sdk-kit/templates/theme/src/Footer.tsx +40 -0
  351. package/template/sdk-kit/templates/theme/src/Header.tsx +47 -0
  352. package/template/sdk-kit/templates/theme/src/Views.tsx +36 -0
  353. package/template/sdk-kit/templates/theme/src/blocks.tsx +93 -0
  354. package/template/sdk-kit/templates/theme/src/index.tsx +30 -0
  355. package/template/sdk-kit/templates/theme/src/site.tsx +59 -0
  356. package/template/sdk-kit/templates/theme/src/styles.css +71 -0
  357. package/template/server/client/routes.ts +252 -0
  358. package/template/server/cms/analyticsStore.ts +180 -0
  359. package/template/server/cms/auth.ts +155 -0
  360. package/template/server/cms/blockCatalog.ts +342 -0
  361. package/template/server/cms/blocks.ts +521 -0
  362. package/template/server/cms/contentMigration.ts +1119 -0
  363. package/template/server/cms/defaults.ts +303 -0
  364. package/template/server/cms/permissions.ts +154 -0
  365. package/template/server/cms/restoreClassicHome.ts +183 -0
  366. package/template/server/cms/revisions.ts +99 -0
  367. package/template/server/cms/scheduler.ts +78 -0
  368. package/template/server/cms/seed.ts +72 -0
  369. package/template/server/cms/seoAnalyzer.ts +213 -0
  370. package/template/server/cms/store.ts +122 -0
  371. package/template/server/cms/themeContent.ts +1386 -0
  372. package/template/server/cms/themePacks/sidibou-branding.json +1 -0
  373. package/template/server/cms/themePacks/sidibou-home.json +1 -0
  374. package/template/server/cms/themePacks/sidibou-menus.json +1 -0
  375. package/template/server/cms/types.ts +432 -0
  376. package/template/server/community/routes.ts +410 -0
  377. package/template/server/db/client.ts +43 -0
  378. package/template/server/db/repository.ts +389 -0
  379. package/template/server/db/schema.ts +726 -0
  380. package/template/server/demo/cmsReset.ts +196 -0
  381. package/template/server/developers/sdk.ts +85 -0
  382. package/template/server/geoip.ts +15 -0
  383. package/template/server/http.ts +53 -0
  384. package/template/server/mail.ts +216 -0
  385. package/template/server/marketplace/catalog.ts +74 -0
  386. package/template/server/marketplace/packageValidate.ts +475 -0
  387. package/template/server/marketplace/payments.ts +193 -0
  388. package/template/server/marketplace/routes.ts +850 -0
  389. package/template/server/marketplace/signing.ts +116 -0
  390. package/template/server/marketplace/syncOfficial.ts +282 -0
  391. package/template/server/media/images.ts +63 -0
  392. package/template/server/middleware/adminAuth.ts +134 -0
  393. package/template/server/modules/legacy.ts +44 -0
  394. package/template/server/modules/manager.ts +1122 -0
  395. package/template/server/modules/marketplace.ts +178 -0
  396. package/template/server/modules/outbound.ts +178 -0
  397. package/template/server/modules/purchases.ts +149 -0
  398. package/template/server/modules/records.ts +168 -0
  399. package/template/server/modules/themeHtml.ts +32 -0
  400. package/template/server/modules/trust.ts +16 -0
  401. package/template/server/modules/types.ts +147 -0
  402. package/template/server/platform/auth.ts +223 -0
  403. package/template/server/platform/clientWelcome.ts +168 -0
  404. package/template/server/platform/clients.ts +139 -0
  405. package/template/server/platform/dailyImprove.ts +356 -0
  406. package/template/server/platform/flouci.ts +126 -0
  407. package/template/server/platform/host.ts +69 -0
  408. package/template/server/platform/hostingProviders.ts +143 -0
  409. package/template/server/platform/licenseOrders.ts +291 -0
  410. package/template/server/platform/money.ts +42 -0
  411. package/template/server/platform/passwords.ts +41 -0
  412. package/template/server/platform/region.ts +86 -0
  413. package/template/server/platform/routes.ts +225 -0
  414. package/template/server/platform/seed.ts +82 -0
  415. package/template/server/platform/settings.ts +72 -0
  416. package/template/server/routes/adminAccount.ts +403 -0
  417. package/template/server/routes/adminCms.ts +808 -0
  418. package/template/server/routes/adminSystem.ts +243 -0
  419. package/template/server/routes/adminUsers.ts +449 -0
  420. package/template/server/routes/googleOAuth.ts +327 -0
  421. package/template/server/routes/modules.ts +323 -0
  422. package/template/server/routes/publicCms.ts +313 -0
  423. package/template/server/routes/seoPublic.ts +158 -0
  424. package/template/server/security/accounts.ts +121 -0
  425. package/template/server/security/audit.ts +143 -0
  426. package/template/server/security/authTokens.ts +74 -0
  427. package/template/server/security/ip.ts +68 -0
  428. package/template/server/security/rateLimit.ts +85 -0
  429. package/template/server/security/retention.ts +46 -0
  430. package/template/server/security/secrets.ts +44 -0
  431. package/template/server/security/sessions.ts +140 -0
  432. package/template/server/security/totp.ts +101 -0
  433. package/template/server/superadmin/analytics.ts +109 -0
  434. package/template/server/superadmin/auth.ts +92 -0
  435. package/template/server/superadmin/backlinksCatalog.ts +210 -0
  436. package/template/server/superadmin/frSeoContent.ts +165 -0
  437. package/template/server/superadmin/landingSeo.ts +675 -0
  438. package/template/server/superadmin/ops.ts +238 -0
  439. package/template/server/superadmin/routes.ts +1095 -0
  440. package/template/server/superadmin/tnSeoContent.ts +130 -0
  441. package/template/server.ts +522 -0
  442. package/template/src/App.tsx +263 -0
  443. package/template/src/admin/AdminApp.tsx +162 -0
  444. package/template/src/admin/account/AuthLayout.tsx +57 -0
  445. package/template/src/admin/account/SecurityForms.tsx +276 -0
  446. package/template/src/admin/admin.css +127 -0
  447. package/template/src/admin/context/AuthContext.tsx +147 -0
  448. package/template/src/admin/context/SiteContext.tsx +50 -0
  449. package/template/src/admin/editor/BlockLibrary.tsx +173 -0
  450. package/template/src/admin/editor/BlocksPanel.tsx +396 -0
  451. package/template/src/admin/editor/EditorBits.tsx +106 -0
  452. package/template/src/admin/editor/PreviewFrame.tsx +145 -0
  453. package/template/src/admin/editor/RichTextEditor.tsx +276 -0
  454. package/template/src/admin/editor/SeoPanel.tsx +349 -0
  455. package/template/src/admin/editor/StyleEditor.tsx +114 -0
  456. package/template/src/admin/editor/blockSchemas.ts +699 -0
  457. package/template/src/admin/editor/fields.tsx +486 -0
  458. package/template/src/admin/layout/AdminShell.tsx +418 -0
  459. package/template/src/admin/layout/nav.ts +95 -0
  460. package/template/src/admin/lib/api.ts +408 -0
  461. package/template/src/admin/lib/audit.ts +141 -0
  462. package/template/src/admin/lib/format.ts +84 -0
  463. package/template/src/admin/lib/hooks.ts +125 -0
  464. package/template/src/admin/main.tsx +16 -0
  465. package/template/src/admin/modules/InstallDialog.tsx +160 -0
  466. package/template/src/admin/modules/SettingsForm.tsx +145 -0
  467. package/template/src/admin/modules/kit.tsx +127 -0
  468. package/template/src/admin/modules/labels.tsx +226 -0
  469. package/template/src/admin/pages/AccountSetupPage.tsx +62 -0
  470. package/template/src/admin/pages/AnalyticsPage.tsx +206 -0
  471. package/template/src/admin/pages/BrandingPage.tsx +154 -0
  472. package/template/src/admin/pages/DashboardPage.tsx +239 -0
  473. package/template/src/admin/pages/EngagementPage.tsx +168 -0
  474. package/template/src/admin/pages/FormsPage.tsx +435 -0
  475. package/template/src/admin/pages/GeneralPage.tsx +120 -0
  476. package/template/src/admin/pages/LoginPage.tsx +249 -0
  477. package/template/src/admin/pages/MaintenancePage.tsx +125 -0
  478. package/template/src/admin/pages/MarketplacePage.tsx +426 -0
  479. package/template/src/admin/pages/MediaPage.tsx +251 -0
  480. package/template/src/admin/pages/MenusPage.tsx +446 -0
  481. package/template/src/admin/pages/ModuleAdminPage.tsx +113 -0
  482. package/template/src/admin/pages/ModuleDetailPage.tsx +293 -0
  483. package/template/src/admin/pages/ModulesPage.tsx +135 -0
  484. package/template/src/admin/pages/NewsletterPage.tsx +193 -0
  485. package/template/src/admin/pages/PageEditorPage.tsx +322 -0
  486. package/template/src/admin/pages/PagesListPage.tsx +277 -0
  487. package/template/src/admin/pages/PostEditorPage.tsx +292 -0
  488. package/template/src/admin/pages/PostsListPage.tsx +187 -0
  489. package/template/src/admin/pages/ProfilePage.tsx +489 -0
  490. package/template/src/admin/pages/ResetPasswordPage.tsx +110 -0
  491. package/template/src/admin/pages/SeoPage.tsx +670 -0
  492. package/template/src/admin/pages/SettingsPage.tsx +189 -0
  493. package/template/src/admin/pages/ThemeCustomizePage.tsx +170 -0
  494. package/template/src/admin/pages/ThemesPage.tsx +292 -0
  495. package/template/src/admin/pages/UsersPage.tsx +57 -0
  496. package/template/src/admin/pages/WidgetsPage.tsx +200 -0
  497. package/template/src/admin/seo/GoogleSetup.tsx +529 -0
  498. package/template/src/admin/settings/EmailTab.tsx +293 -0
  499. package/template/src/admin/settings/OtherTabs.tsx +270 -0
  500. package/template/src/admin/settings/SecurityTab.tsx +172 -0
  501. package/template/src/admin/settings/controls.tsx +133 -0
  502. package/template/src/admin/ui/Pagination.tsx +170 -0
  503. package/template/src/admin/ui/SaveBar.tsx +77 -0
  504. package/template/src/admin/ui/TagInput.tsx +54 -0
  505. package/template/src/admin/ui/charts.tsx +108 -0
  506. package/template/src/admin/ui/media.tsx +265 -0
  507. package/template/src/admin/ui/overlays.tsx +239 -0
  508. package/template/src/admin/ui/primitives.tsx +544 -0
  509. package/template/src/admin/users/AuditTab.tsx +104 -0
  510. package/template/src/admin/users/RolesTab.tsx +368 -0
  511. package/template/src/admin/users/UsersTab.tsx +723 -0
  512. package/template/src/admin/users/shared.tsx +278 -0
  513. package/template/src/cms/icons.ts +7 -0
  514. package/template/src/components/CookieBanner.tsx +166 -0
  515. package/template/src/components/MaintenanceGate.tsx +66 -0
  516. package/template/src/components/SiteAnalytics.tsx +64 -0
  517. package/template/src/components/SnapifyLogo.tsx +44 -0
  518. package/template/src/components/cms/BlockRenderer.tsx +154 -0
  519. package/template/src/components/cms/WidgetArea.tsx +193 -0
  520. package/template/src/context/SiteConfigContext.tsx +130 -0
  521. package/template/src/demoBase.ts +23 -0
  522. package/template/src/index.css +90 -0
  523. package/template/src/main.tsx +16 -0
  524. package/template/src/modules/ModuleHost.tsx +197 -0
  525. package/template/src/preview.ts +63 -0
  526. package/template/src/runtime.ts +38 -0
  527. package/template/src/themes/ThemeHost.tsx +168 -0
  528. package/template/src/themes/fallback.tsx +71 -0
  529. package/template/src/types.ts +94 -0
  530. package/template/src/views/BlogPostView.tsx +68 -0
  531. package/template/src/views/CmsPageView.tsx +34 -0
  532. package/template/start-pm2.sh +3 -0
  533. package/template/superadmin.html +20 -0
  534. package/template/themes/ai-canvas/screenshot.jpg +0 -0
  535. package/template/themes/ai-canvas/snapify.theme.json +96 -0
  536. package/template/themes/ai-canvas/src/CeeSimulator.tsx +247 -0
  537. package/template/themes/ai-canvas/src/Footer.tsx +190 -0
  538. package/template/themes/ai-canvas/src/Header.tsx +324 -0
  539. package/template/themes/ai-canvas/src/Layout.tsx +56 -0
  540. package/template/themes/ai-canvas/src/NotFound.tsx +58 -0
  541. package/template/themes/ai-canvas/src/Post.tsx +26 -0
  542. package/template/themes/ai-canvas/src/SnapifyLogo.tsx +44 -0
  543. package/template/themes/ai-canvas/src/blocks/CollectionBlocks.tsx +711 -0
  544. package/template/themes/ai-canvas/src/blocks/ContentBlocks.tsx +318 -0
  545. package/template/themes/ai-canvas/src/blocks/ConversionBlocks.tsx +559 -0
  546. package/template/themes/ai-canvas/src/blocks/HeaderBlocks.tsx +341 -0
  547. package/template/themes/ai-canvas/src/index.tsx +54 -0
  548. package/template/themes/ai-canvas/src/kit.tsx +398 -0
  549. package/template/themes/ai-canvas/src/site.ts +29 -0
  550. package/template/themes/ai-canvas/src/styles.css +317 -0
  551. package/template/themes/dogga/screenshot.jpg +0 -0
  552. package/template/themes/dogga/snapify.theme.json +55 -0
  553. package/template/themes/dogga/src/Brand.tsx +41 -0
  554. package/template/themes/dogga/src/Footer.tsx +202 -0
  555. package/template/themes/dogga/src/Header.tsx +239 -0
  556. package/template/themes/dogga/src/Layout.tsx +43 -0
  557. package/template/themes/dogga/src/Views.tsx +71 -0
  558. package/template/themes/dogga/src/blocks/CollectionBlocks.tsx +674 -0
  559. package/template/themes/dogga/src/blocks/ContentBlocks.tsx +307 -0
  560. package/template/themes/dogga/src/blocks/ConversionBlocks.tsx +571 -0
  561. package/template/themes/dogga/src/blocks/HeaderBlocks.tsx +289 -0
  562. package/template/themes/dogga/src/index.tsx +53 -0
  563. package/template/themes/dogga/src/kit.tsx +362 -0
  564. package/template/themes/dogga/src/site.ts +56 -0
  565. package/template/themes/dogga/src/styles.css +396 -0
  566. package/template/themes/mahdia/screenshot.jpg +0 -0
  567. package/template/themes/mahdia/snapify.theme.json +65 -0
  568. package/template/themes/mahdia/src/Brand.tsx +39 -0
  569. package/template/themes/mahdia/src/Footer.tsx +210 -0
  570. package/template/themes/mahdia/src/Header.tsx +291 -0
  571. package/template/themes/mahdia/src/Layout.tsx +44 -0
  572. package/template/themes/mahdia/src/Views.tsx +79 -0
  573. package/template/themes/mahdia/src/blocks/CollectionBlocks.tsx +674 -0
  574. package/template/themes/mahdia/src/blocks/ContentBlocks.tsx +307 -0
  575. package/template/themes/mahdia/src/blocks/ConversionBlocks.tsx +571 -0
  576. package/template/themes/mahdia/src/blocks/HeaderBlocks.tsx +289 -0
  577. package/template/themes/mahdia/src/index.tsx +53 -0
  578. package/template/themes/mahdia/src/kit.tsx +362 -0
  579. package/template/themes/mahdia/src/site.ts +75 -0
  580. package/template/themes/mahdia/src/styles.css +446 -0
  581. package/template/themes/preveris/screenshot.jpg +0 -0
  582. package/template/themes/preveris/snapify.theme.json +126 -0
  583. package/template/themes/preveris/src/Brand.tsx +44 -0
  584. package/template/themes/preveris/src/Footer.tsx +202 -0
  585. package/template/themes/preveris/src/Header.tsx +239 -0
  586. package/template/themes/preveris/src/Layout.tsx +42 -0
  587. package/template/themes/preveris/src/Views.tsx +71 -0
  588. package/template/themes/preveris/src/blocks/CollectionBlocks.tsx +678 -0
  589. package/template/themes/preveris/src/blocks/ContentBlocks.tsx +307 -0
  590. package/template/themes/preveris/src/blocks/ConversionBlocks.tsx +571 -0
  591. package/template/themes/preveris/src/blocks/HeaderBlocks.tsx +299 -0
  592. package/template/themes/preveris/src/index.tsx +53 -0
  593. package/template/themes/preveris/src/kit.tsx +365 -0
  594. package/template/themes/preveris/src/site.ts +79 -0
  595. package/template/themes/preveris/src/styles.css +446 -0
  596. package/template/themes/sidibou/screenshot.jpg +0 -0
  597. package/template/themes/sidibou/snapify.theme.json +21 -0
  598. package/template/themes/sidibou/src/CeeSimulator.tsx +247 -0
  599. package/template/themes/sidibou/src/Footer.tsx +203 -0
  600. package/template/themes/sidibou/src/Header.tsx +324 -0
  601. package/template/themes/sidibou/src/Layout.tsx +53 -0
  602. package/template/themes/sidibou/src/NotFound.tsx +58 -0
  603. package/template/themes/sidibou/src/Post.tsx +26 -0
  604. package/template/themes/sidibou/src/SnapifyLogo.tsx +44 -0
  605. package/template/themes/sidibou/src/blocks/CollectionBlocks.tsx +711 -0
  606. package/template/themes/sidibou/src/blocks/ContentBlocks.tsx +318 -0
  607. package/template/themes/sidibou/src/blocks/ConversionBlocks.tsx +559 -0
  608. package/template/themes/sidibou/src/blocks/HeaderBlocks.tsx +341 -0
  609. package/template/themes/sidibou/src/index.tsx +54 -0
  610. package/template/themes/sidibou/src/kit.tsx +398 -0
  611. package/template/themes/sidibou/src/site.ts +28 -0
  612. package/template/themes/sidibou/src/styles.css +317 -0
  613. package/template/tsconfig.json +33 -0
  614. package/template/vite.config.ts +42 -0
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Snapify
3
+ * © 2026 NOVALABS WEB DESIGN — Tunisie
4
+ * Contact : contact@novalabs.tn · +216 24 734 647
5
+ * Tous droits réservés. Toute reproduction, modification ou diffusion sans autorisation écrite est interdite.
6
+ */
7
+ /** Préparation des images dans le navigateur avant envoi (photos de profil). */
8
+
9
+ export const AVATAR_ACCEPT = 'image/jpeg,image/png,image/webp';
10
+ const MAX_SOURCE_BYTES = 15 * 1024 * 1024;
11
+
12
+ export interface PreparedImage {
13
+ dataBase64: string;
14
+ mimeType: string;
15
+ /** URL `data:` utilisable comme aperçu immédiat. */
16
+ preview: string;
17
+ }
18
+
19
+ function loadImage(file: File): Promise<HTMLImageElement> {
20
+ return new Promise((resolve, reject) => {
21
+ const url = URL.createObjectURL(file);
22
+ const img = new Image();
23
+ img.onload = () => {
24
+ URL.revokeObjectURL(url);
25
+ resolve(img);
26
+ };
27
+ img.onerror = () => {
28
+ URL.revokeObjectURL(url);
29
+ reject(new Error('Image illisible : choisissez un fichier JPG, PNG ou WebP.'));
30
+ };
31
+ img.src = url;
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Recadre au centre en carré et réduit à `size` px : quelques dizaines de Ko,
37
+ * quel que soit le poids de la photo d'origine (les métadonnées EXIF disparaissent au passage).
38
+ */
39
+ export async function prepareAvatar(file: File, size = 320): Promise<PreparedImage> {
40
+ if (!AVATAR_ACCEPT.split(',').includes(file.type)) throw new Error('Format non pris en charge : JPG, PNG ou WebP uniquement.');
41
+ if (file.size > MAX_SOURCE_BYTES) throw new Error('Photo trop lourde (15 Mo max.).');
42
+ const img = await loadImage(file);
43
+ const side = Math.min(img.naturalWidth, img.naturalHeight);
44
+ if (side < 32) throw new Error('Photo trop petite.');
45
+ const out = Math.min(size, side);
46
+ const canvas = document.createElement('canvas');
47
+ canvas.width = out;
48
+ canvas.height = out;
49
+ const g = canvas.getContext('2d');
50
+ if (!g) throw new Error('Votre navigateur ne permet pas de préparer la photo.');
51
+ g.imageSmoothingQuality = 'high';
52
+ g.drawImage(img, (img.naturalWidth - side) / 2, (img.naturalHeight - side) / 2, side, side, 0, 0, out, out);
53
+ let preview = canvas.toDataURL('image/webp', 0.86);
54
+ let mimeType = 'image/webp';
55
+ if (!preview.startsWith('data:image/webp')) {
56
+ preview = canvas.toDataURL('image/jpeg', 0.88);
57
+ mimeType = 'image/jpeg';
58
+ }
59
+ return { dataBase64: preview.slice(preview.indexOf(',') + 1), mimeType, preview };
60
+ }
@@ -0,0 +1,500 @@
1
+ /**
2
+ * Snapify
3
+ * © 2026 NOVALABS WEB DESIGN — Tunisie
4
+ * Contact : contact@novalabs.tn · +216 24 734 647
5
+ * Tous droits réservés. Toute reproduction, modification ou diffusion sans autorisation écrite est interdite.
6
+ */
7
+ /**
8
+ * SDK des modules Snapify : contrat entre un module et le CMS.
9
+ * Importé par les modules (`@snapify/sdk`) et par l'hôte ; aucune dépendance Node ici,
10
+ * ce fichier est inclus dans les bundles navigateur.
11
+ *
12
+ * Pas d'import `react` ici : Rolldown/Vite SSR peut traiter un `import type` comme une
13
+ * valeur et embarquer React (+ `process.env`) dans `server.mjs`, rejeté par la marketplace.
14
+ */
15
+ // Compatible avec React.ComponentType sans dépendre du paquet `react` côté serveur.
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ export type ComponentType<P = any> = (props: P) => any;
18
+
19
+ /** Version de l'API modules et thèmes exposée par ce CMS (contrôlée par `engines.snapify`). */
20
+ export const SNAPIFY_MODULE_API_VERSION = '1.3.0';
21
+
22
+ export const MODULE_ID_PATTERN = /^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$/;
23
+ export const SEMVER_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
24
+
25
+ /* ------------------------------------------------------------------ */
26
+ /* Manifeste */
27
+ /* ------------------------------------------------------------------ */
28
+
29
+ /**
30
+ * Permissions accordées au module, affichées à l'administrateur avant installation.
31
+ * - `site:read` lecture des informations publiques du site (nom, coordonnées, couleurs)
32
+ * - `storage` stockage clé/valeur propre au module
33
+ * - `database` collections d'enregistrements propres au module (produits, commandes…)
34
+ * - `files` images publiques propres au module (photos de profil…), sous /uploads/modules/<id>/
35
+ * - `http:routes` exposition de points d'API publics sous /api/modules/<id>/
36
+ * - `http:cookies` lecture et dépôt de cookies `sm_*` (sessions de visiteurs)
37
+ * - `admin:routes` points d'API réservés à l'administration (/api/admin/modules/<id>/api/)
38
+ * - `mail:send` envoi d'e-mails via le serveur SMTP du site
39
+ * - `env:<NOM>` lecture d'une variable d'environnement serveur précise
40
+ * - `net:<hôte>` requêtes HTTPS sortantes vers cet hôte uniquement
41
+ * - `net:outbound` HTTPS/HTTP sortant vers des hôtes publics (anti-SSRF) — migrations, crawlers
42
+ * - `net:ftp` lecture FTP/FTPS contrôlée via `ctx.ftp` (pas de socket brut dans le module)
43
+ */
44
+ export type ModulePermission =
45
+ | 'site:read'
46
+ | 'storage'
47
+ | 'database'
48
+ | 'files'
49
+ | 'http:routes'
50
+ | 'http:cookies'
51
+ | 'admin:routes'
52
+ | 'mail:send'
53
+ | 'net:outbound'
54
+ | 'net:ftp'
55
+ | `env:${string}`
56
+ | `net:${string}`;
57
+
58
+ export const PERMISSION_PATTERN =
59
+ /^(site:read|storage|database|files|http:routes|http:cookies|admin:routes|mail:send|net:outbound|net:ftp|env:[A-Z][A-Z0-9_]{1,63}|net:[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+)$/;
60
+
61
+ /**
62
+ * Emplacements d'affichage :
63
+ * - `floating` éléments fixés à l'écran (bulle de chat, bouton WhatsApp…)
64
+ * - `header-actions` icônes de l'en-tête (panier, compte, recherche), placées par le thème
65
+ */
66
+ export type ModuleSlot = 'floating' | 'header-actions';
67
+ export const MODULE_SLOTS: readonly ModuleSlot[] = ['floating', 'header-actions'];
68
+
69
+ /** Adresse publique prise en charge par un module : `/panier/` (exacte) ou `/boutique/*` (sous-pages incluses). */
70
+ export const ROUTE_PATTERN_PUBLIC = /^\/([a-z0-9][a-z0-9-]*\/)*(\*)?$/;
71
+
72
+ /** Widget insérable dans une page via le bloc « Module » de l'éditeur. */
73
+ export interface WidgetDefinition {
74
+ /** Identifiant unique dans le module, ex. `products`. */
75
+ id: string;
76
+ label: string;
77
+ description?: string;
78
+ /** Options du widget, saisies dans l'éditeur de pages (mêmes types que les réglages). */
79
+ fields: SettingField[];
80
+ }
81
+
82
+ /** Page ajoutée au menu de l'administration ; son rendu est fourni par l'entrée `admin`. */
83
+ export interface AdminPageDefinition {
84
+ id: string;
85
+ label: string;
86
+ /** Icône : mêmes noms que `icon` (ex. `package`, `receipt`, `users`, `ticket`). */
87
+ icon?: string;
88
+ }
89
+
90
+ /** `module` : fonctionnalité (widgets, API) ; `theme` : présentation complète du site. */
91
+ export type PackageKind = 'module' | 'theme';
92
+ export const SCREENSHOT_FILES = ['screenshot.jpg', 'screenshot.png', 'screenshot.webp'] as const;
93
+ export type ScreenshotFile = (typeof SCREENSHOT_FILES)[number];
94
+
95
+ export type SettingFieldType = 'boolean' | 'text' | 'textarea' | 'number' | 'select' | 'phone' | 'paths';
96
+
97
+ export interface SettingField {
98
+ key: string;
99
+ type: SettingFieldType;
100
+ label: string;
101
+ help?: string;
102
+ /** Titre de section : les champs consécutifs partageant le même groupe sont regroupés. */
103
+ group?: string;
104
+ default: unknown;
105
+ required?: boolean;
106
+ /** Valeur transmise au navigateur des visiteurs. Par défaut, un réglage reste côté serveur. */
107
+ public?: boolean;
108
+ placeholder?: string;
109
+ min?: number;
110
+ max?: number;
111
+ step?: number;
112
+ maxLength?: number;
113
+ rows?: number;
114
+ monospace?: boolean;
115
+ /** Affiche un curseur pour un champ `number`. */
116
+ slider?: boolean;
117
+ options?: { value: string; label: string }[];
118
+ }
119
+
120
+ export interface ModuleManifest {
121
+ /** Identifiant unique « éditeur.module », ex. `novalabs.whatsapp`. */
122
+ id: string;
123
+ /** Absent : `module`. */
124
+ kind?: PackageKind;
125
+ name: string;
126
+ version: string;
127
+ description: string;
128
+ author: { name: string; email?: string; url?: string };
129
+ /** `free` : licence gratuite fournie avec le paquet ; `paid` : clé de licence à saisir. */
130
+ pricing: 'free' | 'paid';
131
+ category?: string;
132
+ /** Nom d'icône Lucide (kebab-case), ex. `message-circle`. */
133
+ icon?: string;
134
+ engines: { snapify: string };
135
+ permissions: ModulePermission[];
136
+ slots: ModuleSlot[];
137
+ settings: SettingField[];
138
+ /** Fichiers sources (manifeste de développement) ou bundles (manifeste empaqueté). */
139
+ entries: { public?: string; server?: string; admin?: string };
140
+ /** Thèmes : capture d'écran 4:3 (JPEG, PNG ou WebP) présentée dans l'administration. */
141
+ screenshot?: string;
142
+ /** Adresses du site affichées par le module (composant `page`), ex. `/boutique/*`. */
143
+ routes?: string[];
144
+ /** Widgets proposés dans le bloc « Module » de l'éditeur de pages. */
145
+ widgets?: WidgetDefinition[];
146
+ /** Pages d'administration (composants de l'entrée `admin`). */
147
+ adminPages?: AdminPageDefinition[];
148
+ /** Modules indispensables et version attendue : sans eux, ce module reste bloqué. */
149
+ requires?: Record<string, string>;
150
+ /** Modules facultatifs dont ce module utilise les services s'ils sont actifs. */
151
+ uses?: string[];
152
+ }
153
+
154
+ export const packageKind = (m: Pick<ModuleManifest, 'kind'>): PackageKind => (m.kind === 'theme' ? 'theme' : 'module');
155
+
156
+ /** Manifeste tel qu'il figure dans un paquet : entrées compilées + empreinte de chaque fichier. */
157
+ export interface PackagedManifest extends ModuleManifest {
158
+ entries: { public?: 'public.js'; server?: 'server.mjs'; admin?: 'admin.js' };
159
+ styles?: 'public.css';
160
+ adminStyles?: 'admin.css';
161
+ screenshot?: ScreenshotFile;
162
+ files: Record<string, { sha256: string; size: number }>;
163
+ builtAt: string;
164
+ }
165
+
166
+ /* ------------------------------------------------------------------ */
167
+ /* Côté navigateur */
168
+ /* ------------------------------------------------------------------ */
169
+
170
+ export interface PublicSiteInfo {
171
+ name: string;
172
+ legalName: string;
173
+ phone: string;
174
+ phoneClean: string;
175
+ email: string;
176
+ slaHours: string;
177
+ address: string;
178
+ }
179
+
180
+ export interface PublicModuleProps<S = Record<string, unknown>> {
181
+ /** Réglages marqués `public: true` uniquement. */
182
+ settings: S;
183
+ site: PublicSiteInfo;
184
+ path: string;
185
+ /** Aperçu de l'éditeur de pages : les widgets interactifs peuvent choisir de se masquer. */
186
+ isPreview: boolean;
187
+ navigate: (path: string) => void;
188
+ /** Appels vers les routes déclarées par le module (`/api/modules/<id>/…`). */
189
+ api: ModuleApi;
190
+ module: { id: string; version: string };
191
+ }
192
+
193
+ export interface ModuleApi {
194
+ get: <T = unknown>(path: string) => Promise<T>;
195
+ post: <T = unknown>(path: string, body?: unknown) => Promise<T>;
196
+ }
197
+
198
+ /** Page affichée pour une adresse déclarée dans `routes`, entre l'en-tête et le pied de page du thème. */
199
+ export interface PublicPageProps<S = Record<string, unknown>> extends PublicModuleProps<S> {
200
+ /** Paramètres de l'adresse (`?page=2&tri=prix`), chaîne vide sinon. `navigate('/boutique/?page=2')` les modifie. */
201
+ search: string;
202
+ /** Titre de l'onglet et description pour les moteurs de recherche. */
203
+ setMeta: (meta: { title?: string; description?: string }) => void;
204
+ }
205
+
206
+ /** Widget inséré dans une page par le bloc « Module ». */
207
+ export interface WidgetProps<S = Record<string, unknown>, O = Record<string, unknown>> extends PublicModuleProps<S> {
208
+ widget: string;
209
+ /** Options saisies dans l'éditeur, complétées par les valeurs par défaut. */
210
+ options: O;
211
+ }
212
+
213
+ export interface PublicModule<S = Record<string, unknown>> {
214
+ slots?: Partial<Record<ModuleSlot, ComponentType<PublicModuleProps<S>>>>;
215
+ page?: ComponentType<PublicPageProps<S>>;
216
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
217
+ widgets?: Record<string, ComponentType<WidgetProps<S, any>>>;
218
+ }
219
+
220
+ export function definePublicModule<S = Record<string, unknown>>(mod: PublicModule<S>): PublicModule<S> {
221
+ return mod;
222
+ }
223
+
224
+ /** Client des routes publiques d'un module (le sien ou celui d'un autre module actif). */
225
+ export function createModuleApi(id: string): ModuleApi {
226
+ const call = async <T,>(method: 'GET' | 'POST', path: string, body?: unknown): Promise<T> => {
227
+ const res = await fetch(`/api/modules/${id}${path.startsWith('/') ? path : `/${path}`}`, {
228
+ method,
229
+ credentials: 'same-origin',
230
+ headers: body === undefined ? undefined : { 'Content-Type': 'application/json' },
231
+ body: body === undefined ? undefined : JSON.stringify(body),
232
+ });
233
+ const data = await res.json().catch(() => null);
234
+ if (!res.ok) throw Object.assign(new Error(data?.error || `Erreur ${res.status}`), { status: res.status, fields: data?.fields });
235
+ return data as T;
236
+ };
237
+ return { get: (p) => call('GET', p), post: (p, b) => call('POST', p, b ?? {}) };
238
+ }
239
+
240
+ /** Modules actifs sur le site (identifiants), fournis par l'hôte. */
241
+ export function isModuleActive(id: string): boolean {
242
+ const rt = (globalThis as { __SNAPIFY_RUNTIME__?: { activeModules?: string[] } }).__SNAPIFY_RUNTIME__;
243
+ return !!rt?.activeModules?.includes(id);
244
+ }
245
+
246
+ /**
247
+ * Liste vide = toutes les pages. Une adresse terminée par `*` inclut ses sous-pages
248
+ * (`/blog/*`), sinon la correspondance est exacte, au slash final près.
249
+ */
250
+ export function matchesPaths(patterns: string[] | undefined, path: string): boolean {
251
+ if (!patterns || patterns.length === 0) return true;
252
+ const norm = (p: string) => (p.endsWith('/') ? p : `${p}/`);
253
+ return patterns.some((pat) => (pat.endsWith('*') ? norm(path).startsWith(pat.slice(0, -1)) : norm(pat) === norm(path)));
254
+ }
255
+
256
+ /** Erreur renvoyée par `api.get/post` : `status` HTTP et message de l'API. */
257
+ export interface ModuleApiError extends Error {
258
+ status: number;
259
+ }
260
+
261
+ /* ------------------------------------------------------------------ */
262
+ /* Côté serveur */
263
+ /* ------------------------------------------------------------------ */
264
+
265
+ export type ModuleHttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
266
+
267
+ export interface ModuleRequest {
268
+ method: ModuleHttpMethod;
269
+ path: string;
270
+ /** Segments variables de la route (`/products/:id` → `params.id`). */
271
+ params: Record<string, string>;
272
+ query: Record<string, string>;
273
+ body: unknown;
274
+ ip: string;
275
+ userAgent: string;
276
+ /** `http:cookies` — cookies `sm_*` uniquement. */
277
+ cookies: Record<string, string>;
278
+ /** Routes d'administration : utilisateur connecté. */
279
+ admin?: { id: string; email: string; name: string };
280
+ }
281
+
282
+ export type ModuleRouteHandler = (req: ModuleRequest) => unknown | Promise<unknown>;
283
+
284
+ /** Cookie déposé par une réponse : toujours HttpOnly, SameSite=Lax, Path=/ (Secure en HTTPS). */
285
+ export interface ModuleCookie {
286
+ /** Doit commencer par `sm_`, ex. `sm_session`. */
287
+ name: string;
288
+ value: string;
289
+ /** Durée de vie en secondes ; 0 supprime le cookie ; absent = cookie de session. */
290
+ maxAgeSec?: number;
291
+ }
292
+
293
+ export interface ModuleReply {
294
+ readonly __snapifyReply: true;
295
+ body: unknown;
296
+ status: number;
297
+ cookies: ModuleCookie[];
298
+ }
299
+
300
+ /* -------- Collections (`database`) -------- */
301
+
302
+ export interface RecordMeta {
303
+ id: string;
304
+ createdAt: string;
305
+ updatedAt: string;
306
+ }
307
+
308
+ export type StoredRecord<T> = T & RecordMeta;
309
+
310
+ export type FilterOp = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'contains' | 'exists';
311
+
312
+ /** `field` : champ de premier niveau, ou `id`, `createdAt`, `updatedAt`. */
313
+ export interface RecordFilter {
314
+ field: string;
315
+ op: FilterOp;
316
+ value?: unknown;
317
+ }
318
+
319
+ export interface FindQuery {
320
+ /** Égalités simples sur des champs de premier niveau (un tableau doit contenir les valeurs données). */
321
+ where?: Record<string, unknown>;
322
+ filters?: RecordFilter[];
323
+ /** Recherche insensible à la casse et aux accents dans ces champs texte. */
324
+ search?: { fields: string[]; text: string };
325
+ orderBy?: { field: string; dir?: 'asc' | 'desc'; numeric?: boolean }[];
326
+ /** 500 maximum (100 par défaut). */
327
+ limit?: number;
328
+ offset?: number;
329
+ }
330
+
331
+ export interface Collection<T> {
332
+ get: (id: string) => Promise<StoredRecord<T> | null>;
333
+ getMany: (ids: string[]) => Promise<StoredRecord<T>[]>;
334
+ find: (q?: FindQuery) => Promise<{ items: StoredRecord<T>[]; total: number }>;
335
+ findOne: (where: Record<string, unknown>) => Promise<StoredRecord<T> | null>;
336
+ count: (q?: Pick<FindQuery, 'where' | 'filters' | 'search'>) => Promise<number>;
337
+ /** `id` facultatif : un identifiant aléatoire est généré. */
338
+ insert: (data: T, opts?: { id?: string }) => Promise<StoredRecord<T>>;
339
+ /** Fusion superficielle ; `null` si l'enregistrement n'existe pas. */
340
+ update: (id: string, patch: Partial<T>) => Promise<StoredRecord<T> | null>;
341
+ delete: (id: string) => Promise<boolean>;
342
+ }
343
+
344
+ export interface ModuleStatusReport {
345
+ stats?: { label: string; value: string | number; hint?: string }[];
346
+ alerts?: { tone: 'info' | 'warning' | 'danger' | 'success'; title?: string; text: string }[];
347
+ }
348
+
349
+ export interface ServerSiteInfo extends PublicSiteInfo {
350
+ publicUrl: string;
351
+ colors: Record<string, string>;
352
+ }
353
+
354
+ export interface ModuleLogger {
355
+ info: (...args: unknown[]) => void;
356
+ warn: (...args: unknown[]) => void;
357
+ error: (...args: unknown[]) => void;
358
+ }
359
+
360
+ /**
361
+ * Capacités offertes au module. Chaque méthode vérifie la permission correspondante
362
+ * déclarée dans le manifeste ; un appel non autorisé lève une erreur.
363
+ */
364
+ export interface ServerContext<S = Record<string, unknown>> {
365
+ module: { id: string; version: string };
366
+ /** Réglages complets (publics et serveur), validés selon le manifeste. */
367
+ settings: () => S;
368
+ log: ModuleLogger;
369
+ /**
370
+ * `http:routes` — chemins relatifs à /api/modules/<id>, segments variables `:nom` acceptés.
371
+ * Le retour est sérialisé en JSON ; `reply()` permet de choisir le statut et de déposer des cookies.
372
+ */
373
+ http: {
374
+ get: (path: string, handler: ModuleRouteHandler) => void;
375
+ post: (path: string, handler: ModuleRouteHandler) => void;
376
+ /** `http:cookies` pour déposer des cookies. */
377
+ reply: (body: unknown, opts?: { status?: number; cookies?: ModuleCookie[] }) => ModuleReply;
378
+ };
379
+ /** `database` — collections d'enregistrements JSON (256 Ko max. par enregistrement). */
380
+ db: {
381
+ collection: <T = Record<string, unknown>>(name: string) => Collection<T>;
382
+ };
383
+ /** Exécute `fn` sans concurrence pour une même clé (stock, numérotation…). */
384
+ lock: <T>(key: string, fn: () => Promise<T>) => Promise<T>;
385
+ /** `mail:send` — via le SMTP configuré dans les paramètres ; n'échoue jamais (voir `sent`). */
386
+ mail: {
387
+ send: (msg: { to: string | string[]; subject: string; html: string; text?: string; replyTo?: string }) => Promise<{ sent: boolean; reason?: string }>;
388
+ /** Gabarit aux couleurs du site. */
389
+ render: (content: { title: string; intro: string; lines?: string[]; button?: { label: string; url: string }; outro?: string; html?: string }) => { html: string; text: string };
390
+ };
391
+ /** Publie les services de ce module pour les modules qui le déclarent dans `requires` ou `uses`. */
392
+ provide: (services: object) => void;
393
+ /** Services d'un module déclaré dans `requires` ou `uses` ; `null` s'il n'est pas actif. */
394
+ use: <T = Record<string, unknown>>(moduleId: string) => T | null;
395
+ /** Construit une erreur dont le statut et le message sont renvoyés tels quels au client. */
396
+ error: (status: number, message: string) => Error;
397
+ /** `env:<NOM>` */
398
+ env: (name: string) => string | undefined;
399
+ /**
400
+ * `net:<hôte>` — HTTPS vers cet hôte, 30 s.
401
+ * `net:outbound` — HTTP/HTTPS vers un hôte public (anti-SSRF, redirections limitées).
402
+ */
403
+ fetch: (url: string, init?: RequestInit) => Promise<Response>;
404
+ /**
405
+ * `net:ftp` — lit des fichiers texte via FTP/FTPS (exports SEO, .htaccess…).
406
+ * Identifiants jamais journalisés ; à purger après usage côté module.
407
+ */
408
+ ftp: {
409
+ list: (opts: {
410
+ host: string;
411
+ port?: number;
412
+ user: string;
413
+ password: string;
414
+ secure?: boolean;
415
+ path?: string;
416
+ }) => Promise<string[]>;
417
+ readText: (opts: {
418
+ host: string;
419
+ port?: number;
420
+ user: string;
421
+ password: string;
422
+ secure?: boolean;
423
+ path: string;
424
+ maxBytes?: number;
425
+ }) => Promise<string>;
426
+ };
427
+ /** `site:read` */
428
+ site: () => ServerSiteInfo;
429
+ /**
430
+ * `files` (API 1.3) — images JPG, PNG ou WebP envoyées en base64 (voir `prepareAvatar` de
431
+ * `@snapify/sdk/image`), contrôlées puis servies publiquement. 2 Mo maximum par image.
432
+ */
433
+ files: {
434
+ /** Enregistre l'image et renvoie son URL publique (/uploads/modules/<id>/…). */
435
+ saveImage: (image: { dataBase64: string; mimeType: string }, opts?: { prefix?: string; maxBytes?: number }) => Promise<string>;
436
+ /** Supprime une image de ce module ; les autres URL sont ignorées. */
437
+ delete: (url: string | undefined | null) => Promise<void>;
438
+ };
439
+ /** `storage` — valeurs JSON de 64 Ko maximum. */
440
+ storage: {
441
+ get: <T = unknown>(key: string) => Promise<T | undefined>;
442
+ set: (key: string, value: unknown) => Promise<void>;
443
+ delete: (key: string) => Promise<void>;
444
+ };
445
+ /**
446
+ * Administration : indicateurs de la page du module et, avec `admin:routes`, routes réservées
447
+ * aux utilisateurs autorisés à gérer les données des modules (/api/admin/modules/<id>/api/…).
448
+ */
449
+ admin: {
450
+ status: (provider: () => ModuleStatusReport | Promise<ModuleStatusReport>) => void;
451
+ get: (path: string, handler: ModuleRouteHandler) => void;
452
+ post: (path: string, handler: ModuleRouteHandler) => void;
453
+ put: (path: string, handler: ModuleRouteHandler) => void;
454
+ delete: (path: string, handler: ModuleRouteHandler) => void;
455
+ };
456
+ }
457
+
458
+ export interface ServerModule<S = Record<string, unknown>> {
459
+ /** Appelé à l'activation ; la fonction renvoyée est appelée à la désactivation. */
460
+ activate: (ctx: ServerContext<S>) => void | (() => void) | Promise<void | (() => void)>;
461
+ }
462
+
463
+ export function defineServerModule<S = Record<string, unknown>>(mod: ServerModule<S>): ServerModule<S> {
464
+ return mod;
465
+ }
466
+
467
+ /* ------------------------------------------------------------------ */
468
+ /* Licences */
469
+ /* ------------------------------------------------------------------ */
470
+
471
+ export interface LicensePayload {
472
+ v: 1;
473
+ licenseId: string;
474
+ moduleId: string;
475
+ licensee: string;
476
+ plan: 'free' | 'standard' | 'pro' | 'enterprise';
477
+ /** Domaines autorisés : `*` (tous), `exemple.fr`, `*.exemple.fr`. */
478
+ domains: string[];
479
+ issuedAt: string;
480
+ expiresAt: string | null;
481
+ }
482
+
483
+ export interface Signature {
484
+ alg: 'ed25519';
485
+ kid: string;
486
+ value: string;
487
+ }
488
+
489
+ export interface SignedLicense {
490
+ payload: LicensePayload;
491
+ signature: Signature;
492
+ }
493
+
494
+ /**
495
+ * reCAPTCHA : importer depuis `@snapify/sdk/recaptcha` (pas depuis l’entrée principale).
496
+ * Un re-export ici forçait React dans tous les `server.mjs` (Rolldown ne tree-shake pas
497
+ * correctement ce barrel), ce que la marketplace refuse (`process.env` / import externe).
498
+ */
499
+
500
+ export const LICENSE_KEY_PREFIX = 'SNAPIFY-LIC-';