@geekity/cms 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +870 -0
- package/admin/layouts/_flash.njk +5 -0
- package/admin/layouts/base.njk +27 -0
- package/admin/layouts/dashboard.njk +78 -0
- package/admin/layouts/document-conflict.njk +49 -0
- package/admin/layouts/document-editor.njk +167 -0
- package/admin/layouts/document-list.njk +92 -0
- package/admin/layouts/federation.njk +145 -0
- package/admin/layouts/login.njk +23 -0
- package/admin/layouts/placeholder.njk +10 -0
- package/admin/layouts/settings.njk +116 -0
- package/admin/layouts/setup.njk +27 -0
- package/admin/layouts/shell.njk +37 -0
- package/admin/layouts/users.njk +91 -0
- package/admin/static/admin.css +726 -0
- package/admin/static/editor.js +30 -0
- package/dist/admin/assets.d.ts +26 -0
- package/dist/admin/assets.d.ts.map +1 -0
- package/dist/admin/assets.js +38 -0
- package/dist/admin/assets.js.map +1 -0
- package/dist/admin/credentials.d.ts +28 -0
- package/dist/admin/credentials.d.ts.map +1 -0
- package/dist/admin/credentials.js +39 -0
- package/dist/admin/credentials.js.map +1 -0
- package/dist/admin/documents.d.ts +134 -0
- package/dist/admin/documents.d.ts.map +1 -0
- package/dist/admin/documents.js +613 -0
- package/dist/admin/documents.js.map +1 -0
- package/dist/admin/federation.d.ts +194 -0
- package/dist/admin/federation.d.ts.map +1 -0
- package/dist/admin/federation.js +299 -0
- package/dist/admin/federation.js.map +1 -0
- package/dist/admin/flash.d.ts +24 -0
- package/dist/admin/flash.d.ts.map +1 -0
- package/dist/admin/flash.js +31 -0
- package/dist/admin/flash.js.map +1 -0
- package/dist/admin/index.d.ts +23 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +15 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/passwords.d.ts +49 -0
- package/dist/admin/passwords.d.ts.map +1 -0
- package/dist/admin/passwords.js +122 -0
- package/dist/admin/passwords.js.map +1 -0
- package/dist/admin/preview.d.ts +18 -0
- package/dist/admin/preview.d.ts.map +1 -0
- package/dist/admin/preview.js +83 -0
- package/dist/admin/preview.js.map +1 -0
- package/dist/admin/routes.d.ts +54 -0
- package/dist/admin/routes.d.ts.map +1 -0
- package/dist/admin/routes.js +383 -0
- package/dist/admin/routes.js.map +1 -0
- package/dist/admin/session.d.ts +44 -0
- package/dist/admin/session.d.ts.map +1 -0
- package/dist/admin/session.js +69 -0
- package/dist/admin/session.js.map +1 -0
- package/dist/admin/settings.d.ts +194 -0
- package/dist/admin/settings.d.ts.map +1 -0
- package/dist/admin/settings.js +470 -0
- package/dist/admin/settings.js.map +1 -0
- package/dist/admin/store.d.ts +407 -0
- package/dist/admin/store.d.ts.map +1 -0
- package/dist/admin/store.js +704 -0
- package/dist/admin/store.js.map +1 -0
- package/dist/admin/templates.d.ts +36 -0
- package/dist/admin/templates.d.ts.map +1 -0
- package/dist/admin/templates.js +43 -0
- package/dist/admin/templates.js.map +1 -0
- package/dist/admin/uploads.d.ts +96 -0
- package/dist/admin/uploads.d.ts.map +1 -0
- package/dist/admin/uploads.js +179 -0
- package/dist/admin/uploads.js.map +1 -0
- package/dist/admin/users.d.ts +95 -0
- package/dist/admin/users.d.ts.map +1 -0
- package/dist/admin/users.js +233 -0
- package/dist/admin/users.js.map +1 -0
- package/dist/cli.d.ts +85 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +424 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +172 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +184 -0
- package/dist/config.js.map +1 -0
- package/dist/content/document.d.ts +66 -0
- package/dist/content/document.d.ts.map +1 -0
- package/dist/content/document.js +13 -0
- package/dist/content/document.js.map +1 -0
- package/dist/content/index.d.ts +17 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/index.js +10 -0
- package/dist/content/index.js.map +1 -0
- package/dist/content/markdown.d.ts +3 -0
- package/dist/content/markdown.d.ts.map +1 -0
- package/dist/content/markdown.js +39 -0
- package/dist/content/markdown.js.map +1 -0
- package/dist/content/media.d.ts +65 -0
- package/dist/content/media.d.ts.map +1 -0
- package/dist/content/media.js +143 -0
- package/dist/content/media.js.map +1 -0
- package/dist/content/parser.d.ts +24 -0
- package/dist/content/parser.d.ts.map +1 -0
- package/dist/content/parser.js +165 -0
- package/dist/content/parser.js.map +1 -0
- package/dist/content/save.d.ts +60 -0
- package/dist/content/save.d.ts.map +1 -0
- package/dist/content/save.js +103 -0
- package/dist/content/save.js.map +1 -0
- package/dist/content/slug.d.ts +25 -0
- package/dist/content/slug.d.ts.map +1 -0
- package/dist/content/slug.js +75 -0
- package/dist/content/slug.js.map +1 -0
- package/dist/content/store.d.ts +133 -0
- package/dist/content/store.d.ts.map +1 -0
- package/dist/content/store.js +411 -0
- package/dist/content/store.js.map +1 -0
- package/dist/content/sync.d.ts +146 -0
- package/dist/content/sync.d.ts.map +1 -0
- package/dist/content/sync.js +421 -0
- package/dist/content/sync.js.map +1 -0
- package/dist/content/writer.d.ts +37 -0
- package/dist/content/writer.d.ts.map +1 -0
- package/dist/content/writer.js +97 -0
- package/dist/content/writer.js.map +1 -0
- package/dist/env.d.ts +48 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +2 -0
- package/dist/env.js.map +1 -0
- package/dist/federation/actor.d.ts +55 -0
- package/dist/federation/actor.d.ts.map +1 -0
- package/dist/federation/actor.js +101 -0
- package/dist/federation/actor.js.map +1 -0
- package/dist/federation/article.d.ts +83 -0
- package/dist/federation/article.d.ts.map +1 -0
- package/dist/federation/article.js +169 -0
- package/dist/federation/article.js.map +1 -0
- package/dist/federation/delivery.d.ts +90 -0
- package/dist/federation/delivery.d.ts.map +1 -0
- package/dist/federation/delivery.js +289 -0
- package/dist/federation/delivery.js.map +1 -0
- package/dist/federation/federation.d.ts +75 -0
- package/dist/federation/federation.d.ts.map +1 -0
- package/dist/federation/federation.js +190 -0
- package/dist/federation/federation.js.map +1 -0
- package/dist/federation/followers.d.ts +43 -0
- package/dist/federation/followers.d.ts.map +1 -0
- package/dist/federation/followers.js +69 -0
- package/dist/federation/followers.js.map +1 -0
- package/dist/federation/inbox.d.ts +68 -0
- package/dist/federation/inbox.d.ts.map +1 -0
- package/dist/federation/inbox.js +171 -0
- package/dist/federation/inbox.js.map +1 -0
- package/dist/federation/index.d.ts +14 -0
- package/dist/federation/index.d.ts.map +1 -0
- package/dist/federation/index.js +10 -0
- package/dist/federation/index.js.map +1 -0
- package/dist/federation/keys.d.ts +27 -0
- package/dist/federation/keys.d.ts.map +1 -0
- package/dist/federation/keys.js +60 -0
- package/dist/federation/keys.js.map +1 -0
- package/dist/federation/mount.d.ts +23 -0
- package/dist/federation/mount.d.ts.map +1 -0
- package/dist/federation/mount.js +71 -0
- package/dist/federation/mount.js.map +1 -0
- package/dist/federation/paths.d.ts +85 -0
- package/dist/federation/paths.d.ts.map +1 -0
- package/dist/federation/paths.js +97 -0
- package/dist/federation/paths.js.map +1 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +148 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +71 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +125 -0
- package/dist/init.js.map +1 -0
- package/dist/web/assets.d.ts +65 -0
- package/dist/web/assets.d.ts.map +1 -0
- package/dist/web/assets.js +152 -0
- package/dist/web/assets.js.map +1 -0
- package/dist/web/context.d.ts +121 -0
- package/dist/web/context.d.ts.map +1 -0
- package/dist/web/context.js +112 -0
- package/dist/web/context.js.map +1 -0
- package/dist/web/documents.d.ts +28 -0
- package/dist/web/documents.d.ts.map +1 -0
- package/dist/web/documents.js +39 -0
- package/dist/web/documents.js.map +1 -0
- package/dist/web/feeds.d.ts +122 -0
- package/dist/web/feeds.d.ts.map +1 -0
- package/dist/web/feeds.js +229 -0
- package/dist/web/feeds.js.map +1 -0
- package/dist/web/index.d.ts +17 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +10 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/negotiate.d.ts +219 -0
- package/dist/web/negotiate.d.ts.map +1 -0
- package/dist/web/negotiate.js +409 -0
- package/dist/web/negotiate.js.map +1 -0
- package/dist/web/pagination.d.ts +48 -0
- package/dist/web/pagination.d.ts.map +1 -0
- package/dist/web/pagination.js +30 -0
- package/dist/web/pagination.js.map +1 -0
- package/dist/web/render.d.ts +72 -0
- package/dist/web/render.d.ts.map +1 -0
- package/dist/web/render.js +73 -0
- package/dist/web/render.js.map +1 -0
- package/dist/web/routes.d.ts +31 -0
- package/dist/web/routes.d.ts.map +1 -0
- package/dist/web/routes.js +366 -0
- package/dist/web/routes.js.map +1 -0
- package/dist/web/templates.d.ts +34 -0
- package/dist/web/templates.d.ts.map +1 -0
- package/dist/web/templates.js +106 -0
- package/dist/web/templates.js.map +1 -0
- package/package.json +68 -0
- package/templates/site/content/_data/site.json +8 -0
- package/templates/site/content/pages/about.md +11 -0
- package/templates/site/content/pages/pages.json +3 -0
- package/templates/site/content/posts/2026-01-01-hello-world.md +34 -0
- package/templates/site/content/posts/posts.json +4 -0
- package/templates/site/geekity.config.ts +11 -0
- package/templates/site/gitignore +3 -0
- package/templates/site/server.ts +20 -0
- package/templates/site/tsconfig.json +18 -0
- package/themes/default/README.md +148 -0
- package/themes/default/layouts/404.njk +9 -0
- package/themes/default/layouts/base.njk +59 -0
- package/themes/default/layouts/home.njk +9 -0
- package/themes/default/layouts/page.njk +13 -0
- package/themes/default/layouts/post.njk +30 -0
- package/themes/default/layouts/tag.njk +19 -0
- package/themes/default/partials/pagination.njk +14 -0
- package/themes/default/partials/post-list.njk +24 -0
- package/themes/default/partials/tags.njk +12 -0
- package/themes/default/static/style.css +327 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/admin/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AA+ElE,6EAA6E;AAC7E,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAEnC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,mBAAmB,EAAE,SAAS,CAAU,CAAC;AAuI9E,8DAA8D;AAC9D,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AA8LvE,4EAA4E;AAC5E,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC7B,IAAI,GAAG,wBAAwB,CAAC;IAClD,wCAAwC;IAC/B,QAAQ,CAAS;IAE1B,YAAY,QAAgB;QAC1B,KAAK,CAAC,iBAAiB,QAAQ,mBAAmB,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACvD,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhD,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACrC,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,UAAU,GAAG;QACjB,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC;QAC7D,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,8DAA8D,CAAC;QACrF,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC;QAChE,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,yDAAyD,CAAC;QAC/E,UAAU,EAAE,EAAE,CAAC,OAAO,CACpB,0EAA0E,CAC3E;QACD,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC,iDAAiD,CAAC;QAC1E,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC,gCAAgC,CAAC;QACxD,qBAAqB,EAAE,EAAE,CAAC,OAAO,CAAC,wDAAwD,CAAC;QAC3F,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC;;;KAGzB,CAAC;QACF,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC,qCAAqC,CAAC;QAC9D,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,mCAAmC,CAAC;QAC9D,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC;QACvE,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,yCAAyC,CAAC;QAChE,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC;QACpE,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC;QACnE,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC;QAC1D,UAAU,EAAE,EAAE,CAAC,OAAO,CAAC;;;KAGtB,CAAC;QACF,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,+CAA+C,CAAC;QACtE,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC;;;;;;;KAOvB,CAAC;QACF,cAAc,EAAE,EAAE,CAAC,OAAO,CAAC,yCAAyC,CAAC;QACrE,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC;;;;KAIzB,CAAC;QACF,YAAY,EAAE,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC;QACtE,WAAW,EAAE,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;KAWvB,CAAC;QACF,cAAc,EAAE,EAAE,CAAC,OAAO,CAAC,0CAA0C,CAAC;QACtE,oBAAoB,EAAE,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC;QAC1E,mBAAmB,EAAE,EAAE,CAAC,OAAO,CAAC;;;;KAI/B,CAAC;QACF,gBAAgB,EAAE,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;KAU5B,CAAC;QACF,uBAAuB,EAAE,EAAE,CAAC,OAAO,CAAC,2CAA2C,CAAC;QAChF,sBAAsB,EAAE,EAAE,CAAC,OAAO,CAAC;;;;KAIlC,CAAC;QACF,oBAAoB,EAAE,EAAE,CAAC,OAAO,CAAC,iDAAiD,CAAC;QACnF,mBAAmB,EAAE,EAAE,CAAC,OAAO,CAAC;;;;;;;;;KAS/B,CAAC;QACF,cAAc,EAAE,EAAE,CAAC,OAAO,CAAC;;;;;;;;;KAS1B,CAAC;QACF,cAAc,EAAE,EAAE,CAAC,OAAO,CAAC;;KAE1B,CAAC;QACF,uBAAuB,EAAE,EAAE,CAAC,OAAO,CAAC;;KAEnC,CAAC;KACH,CAAC;IAEF,IAAI,IAAI,GAAG,IAAI,CAAC;IAEhB;;;;OAIG;IACH,SAAS,SAAS,CAAC,SAAiB;QAClC,MAAM,GAAG,GAAG,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAwC,CAAC;QACvF,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QAErD,IAAI,CAAC;YACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACxC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,SAAS,UAAU,CAAC,QAAgB;QAClC,MAAM,GAAG,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAwC,CAAC;QACvF,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACxC,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACrB,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACjC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC1C,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;SACrC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI;QAEJ,UAAU;YACR,MAAM,GAAG,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,EAAyC,CAAC;YAC/E,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,CAAC;QAED,SAAS;YACP,OAAQ,UAAU,CAAC,SAAS,CAAC,GAAG,EAAgC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC7E,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACrB,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACjC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;aACrC,CAAC,CAAC,CAAC;QACN,CAAC;QAED,OAAO,CAAC,QAAQ;YACd,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QAED,WAAW,CAAC,EAAE;YACZ,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAwC,CAAC;YAC/E,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YACxC,OAAO;gBACL,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACrB,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACjC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;aACrC,CAAC;QACJ,CAAC;QAED,UAAU,CAAC,KAAK;YACd,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC1C,IAAI,CAAC;gBACH,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;YAC7D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,iBAAiB,CAAC,KAAK,CAAC;oBAAE,MAAM,IAAI,sBAAsB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC/E,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC3C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,aAAa,KAAK,CAAC,QAAQ,qCAAqC,CAAC,CAAC;YACpF,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;QACtF,CAAC;QAED,cAAc,CAAC,QAAQ,EAAE,QAAQ;YAC/B,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;YAClC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,oEAAoE;gBACpE,6DAA6D;gBAC7D,kBAAkB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;gBACzC,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC;gBAAE,OAAO,SAAS,CAAC;YACvE,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7E,CAAC;QAED,WAAW,CAAC,MAAM,EAAE,QAAQ;YAC1B,wEAAwE;YACxE,+BAA+B;YAC/B,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YACpC,OAAO,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;QAC9D,CAAC;QAED,UAAU,CAAC,MAAM;YACf,OAAO,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;QACvD,CAAC;QAED,aAAa,CAAC,KAAK;YACjB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;YACpC,MAAM,OAAO,GAAY;gBACvB,EAAE,EAAE,WAAW,EAAE;gBACjB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,SAAS,EAAE,WAAW,EAAE;gBACxB,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;gBAC5B,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;aAChF,CAAC;YACF,UAAU,CAAC,aAAa,CAAC,GAAG,CAC1B,OAAO,CAAC,EAAE,EACV,OAAO,CAAC,MAAM,EACd,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,SAAS,EACjB,OAAO,CAAC,SAAS,CAClB,CAAC;YACF,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,UAAU,CAAC,EAAE,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;YAC7B,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAwC,CAAC;YAClF,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YAExC,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YAC/B,0EAA0E;YAC1E,IAAI,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;gBAC3C,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACjC,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,aAAa,CAAC,EAAE;YACd,OAAO,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;QACtD,CAAC;QAED,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,EAAE;YACxC,yEAAyE;YACzE,kDAAkD;YAClD,OAAO,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;QAC9F,CAAC;QAED,aAAa,CAAC,UAAU;YACtB,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAA8B,CAAC;YAC/E,MAAM,IAAI,GAAG,IAAI;iBACd,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBACb,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACrC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAsB;gBACxD,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBACtC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACpC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;aACrC,CAAC,CAAC;gBACH,gEAAgE;gBAChE,oEAAoE;gBACpE,iBAAiB;iBAChB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,oBAAoB,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;YAEjE,OAAO,IAAI,CAAC,IAAI,CACd,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CACxF,CAAC;QACJ,CAAC;QAED,WAAW,CAAC,GAAG;YACb,MAAM,MAAM,GAAa,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;YACzE,UAAU,CAAC,WAAW,CAAC,GAAG,CACxB,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,SAAS,CACjB,CAAC;YACF,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,cAAc;YACZ,MAAM,GAAG,GAAG,UAAU,CAAC,cAAc,CAAC,GAAG,EAAyC,CAAC;YACnF,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,CAAC;QAED,aAAa,CAAC,OAAO,GAAG,EAAE;YACxB,MAAM,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC,GAAG,CACvC,OAAO,CAAC,KAAK,IAAI,QAAQ,EACzB,OAAO,CAAC,MAAM,IAAI,CAAC,CACS,CAAC;YAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC9B,CAAC;QAED,WAAW,CAAC,OAAO;YACjB,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAwC,CAAC;YACxF,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACzD,CAAC;QAED,WAAW,CAAC,QAAQ;YAClB,UAAU,CAAC,WAAW,CAAC,GAAG,CACxB,QAAQ,CAAC,OAAO,EAChB,QAAQ,CAAC,OAAO,EAChB,QAAQ,CAAC,aAAa,EACtB,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,OAAO,EAChB,QAAQ,CAAC,GAAG,EACZ,QAAQ,CAAC,UAAU,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAChD,CAAC;YACF,yEAAyE;YACzE,wEAAwE;YACxE,gCAAgC;YAChC,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CACnB,CAAC;YACtC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,iBAAiB,QAAQ,CAAC,OAAO,qCAAqC,CAAC,CAAC;YAC1F,CAAC;YACD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAED,cAAc,CAAC,OAAO;YACpB,OAAO,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;QAC5D,CAAC;QAED,oBAAoB;YAClB,MAAM,GAAG,GAAG,UAAU,CAAC,oBAAoB,CAAC,GAAG,EAAyC,CAAC;YACzF,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,CAAC;QAED,mBAAmB,CAAC,OAAO,GAAG,EAAE;YAC9B,MAAM,IAAI,GAAG,UAAU,CAAC,mBAAmB,CAAC,GAAG,CAC7C,OAAO,CAAC,KAAK,IAAI,QAAQ,EACzB,OAAO,CAAC,MAAM,IAAI,CAAC,CACS,CAAC;YAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACnC,CAAC;QAED,gBAAgB,CAAC,QAAQ;YACvB,MAAM,GAAG,GAAG,UAAU,CAAC,gBAAgB,CAAC,GAAG,CACzC,QAAQ,CAAC,UAAU,EACnB,QAAQ,CAAC,YAAY,EACrB,QAAQ,CAAC,OAAO,EAChB,QAAQ,CAAC,QAAQ,EACjB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EACxB,QAAQ,CAAC,IAAI,CACyB,CAAC;YACzC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,iBAAiB,QAAQ,CAAC,YAAY,+BAA+B,CAAC,CAAC;YACzF,CAAC;YACD,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;QAED,uBAAuB;YACrB,MAAM,GAAG,GAAG,UAAU,CAAC,uBAAuB,CAAC,GAAG,EAAyC,CAAC;YAC5F,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,CAAC;QAED,sBAAsB,CAAC,OAAO,GAAG,EAAE;YACjC,MAAM,IAAI,GAAG,UAAU,CAAC,sBAAsB,CAAC,GAAG,CAChD,OAAO,CAAC,KAAK,IAAI,QAAQ,EACzB,OAAO,CAAC,MAAM,IAAI,CAAC,CACS,CAAC;YAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACtC,CAAC;QAED,mBAAmB,CAAC,UAAU;YAC5B,MAAM,GAAG,GAAG,UAAU,CAAC,oBAAoB,CAAC,GAAG,CAAC,UAAU,CACrB,CAAC;YACtC,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACjE,CAAC;QAED,mBAAmB,CAAC,QAAQ;YAC1B,MAAM,GAAG,GAAG,UAAU,CAAC,mBAAmB,CAAC,GAAG,CAC5C,QAAQ,CAAC,UAAU,EACnB,QAAQ,CAAC,YAAY,EACrB,QAAQ,CAAC,QAAQ,EACjB,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAC9C,QAAQ,CAAC,IAAI,CACyB,CAAC;YACzC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,iBAAiB,QAAQ,CAAC,UAAU,sCAAsC,CAAC,CAAC;YAC9F,CAAC;YACD,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QAED,cAAc,CAAC,QAAQ;YACrB,MAAM,GAAG,GAAG,UAAU,CAAC,cAAc,CAAC,GAAG,CACvC,QAAQ,CAAC,UAAU,EACnB,QAAQ,CAAC,OAAO,EAChB,QAAQ,CAAC,OAAO,EAChB,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,WAAW,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CACV,CAAC;YACzC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CACb,oBAAoB,QAAQ,CAAC,UAAU,SAAS,QAAQ,CAAC,OAAO,qBAAqB,CACtF,CAAC;YACJ,CAAC;YACD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAED,cAAc,CAAC,UAAU;YACvB,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAA8B,CAAC;YACpF,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC9B,CAAC;QAED,uBAAuB,CAAC,UAAU;YAChC,MAAM,MAAM,GAAmC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YACjF,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,uBAAuB,CAAC,GAAG,CAAC,UAAU,CAGhE,EAAE,CAAC;gBACJ,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9C,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,aAAa,CAAC,GAAG,GAAG,IAAI,IAAI,EAAE;YAC5B,OAAO,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QACzE,CAAC;QAED,aAAa;YACX,MAAM,GAAG,GAAG,UAAU,CAAC,aAAa,CAAC,GAAG,EAAyC,CAAC;YAClF,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,CAAC;QAED,WAAW;YACT,MAAM,QAAQ,GAA2B,EAAE,CAAC;YAC5C,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,GAAG,EAA+B,EAAE,CAAC;gBAC5E,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YACtD,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,WAAW,CAAC,MAAM;YAChB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC3C,oEAAoE;YACpE,yEAAyE;YACzE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACjB,IAAI,CAAC;gBACH,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;oBAClD,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;gBACnD,CAAC;gBACD,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBACpB,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAED,SAAS,CAAC,SAAS,EAAE,KAAK;YACxB,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;YAChD,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC;QAC/D,CAAC;QAED,SAAS,CAAC,SAAS;YACjB,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;YACpC,wEAAwE;YACxE,oDAAoD;YACpD,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC3C,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,KAAK;YACH,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,IAAI,GAAG,KAAK,CAAC;YACb,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,GAAG,YAAY,CAC7B,2EAA2E,CAC5E,CAAC;AAEF,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,KAAK,GAAG,KAAgC,CAAC;IAC/C,OAAO,CACL,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC;QACzD,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,QAAQ,CACrC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC;AAEpB;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED,SAAS,UAAU,CAAC,GAA4B;IAC9C,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAChC,aAAa,EAAE,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QACnD,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/B,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACtC,GAAG,EAAE,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7B,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;KACvC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAA4B;IACnD,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrB,UAAU,EAAE,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC5C,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC1C,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAChC,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACxC,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACtC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,GAA4B;IACtD,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACtC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC1C,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAClC,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACpC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,GAA4B;IAC9C,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACtC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAChC,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,KAAK,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACjC,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;KACzC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,iBAAiB,CAAC,QAAQ,CAAC,KAAuB,CAAC,CAAC,CAAC,CAAE,KAAwB,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpG,CAAC;AAED,SAAS,SAAS,CAAC,GAA4B;IAC7C,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9B,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrB,MAAM,EAAE,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;QACvE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;KACrC,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,SAAS,WAAW;IAClB,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,OAAO,KAAK,YAAY,KAAK,IAAI,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACnF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,GAAoD;IAClE;QACE,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;KAoBJ;KACF;IACD;QACE,yEAAyE;QACzE,yEAAyE;QACzE,yEAAyE;QACzE,wCAAwC;QACxC,OAAO,EAAE,CAAC;QACV,GAAG,EAAE,4CAA4C;KAClD;IACD;QACE,uEAAuE;QACvE,uEAAuE;QACvE,0EAA0E;QAC1E,oBAAoB;QACpB,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;KAMJ;KACF;IACD;QACE,yEAAyE;QACzE,wEAAwE;QACxE,yEAAyE;QACzE,yEAAyE;QACzE,yEAAyE;QACzE,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;;;;KASJ;KACF;IACD;QACE,wEAAwE;QACxE,0EAA0E;QAC1E,yEAAyE;QACzE,wEAAwE;QACxE,wCAAwC;QACxC,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;;;;;;;;KAaJ;KACF;IACD;QACE,oEAAoE;QACpE,uEAAuE;QACvE,wEAAwE;QACxE,yEAAyE;QACzE,wEAAwE;QACxE,gEAAgE;QAChE,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;;;;;;;;;KAcJ;KACF;IACD;QACE,yEAAyE;QACzE,qEAAqE;QACrE,2EAA2E;QAC3E,2EAA2E;QAC3E,4DAA4D;QAC5D,EAAE;QACF,yEAAyE;QACzE,yEAAyE;QACzE,uEAAuE;QACvE,uCAAuC;QACvC,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;KAyBJ;KACF;CACF,CAAC;AAEF,SAAS,OAAO,CAAC,EAAgB;IAC/B,EAAE,CAAC,IAAI,CAAC;;;;;GAKP,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,EAAE;SACC,OAAO,CAAC,sCAAsC,CAAC;SAC/C,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CACxC,CAAC;IAEF,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,kEAAkE,CAAC,CAAC;IAE9F,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC;YAAE,SAAS;QAE7C,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjB,IAAI,CAAC;YACH,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACvB,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;YACxD,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACpB,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Environment } from 'nunjucks';
|
|
2
|
+
/**
|
|
3
|
+
* The admin's templates, resolved from this module rather than the working
|
|
4
|
+
* directory so they are found whether the CMS runs from `src/` under tsx or
|
|
5
|
+
* from `dist/` as an installed dependency.
|
|
6
|
+
*
|
|
7
|
+
* They are a set of their own, not part of the theme search path: a site's
|
|
8
|
+
* `theme/` may override any public template, and must not be able to shadow
|
|
9
|
+
* the login form or the CSRF field inside it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const PACKAGED_ADMIN_DIR: string;
|
|
12
|
+
/** Templates {@link mountAdmin} asks for by name. */
|
|
13
|
+
export declare const ADMIN_TEMPLATES: {
|
|
14
|
+
readonly login: 'layouts/login.njk';
|
|
15
|
+
readonly setup: 'layouts/setup.njk';
|
|
16
|
+
readonly dashboard: 'layouts/dashboard.njk';
|
|
17
|
+
readonly placeholder: 'layouts/placeholder.njk';
|
|
18
|
+
readonly documentList: 'layouts/document-list.njk';
|
|
19
|
+
readonly documentEditor: 'layouts/document-editor.njk';
|
|
20
|
+
readonly documentConflict: 'layouts/document-conflict.njk';
|
|
21
|
+
readonly settings: 'layouts/settings.njk';
|
|
22
|
+
readonly users: 'layouts/users.njk';
|
|
23
|
+
readonly federation: 'layouts/federation.njk';
|
|
24
|
+
};
|
|
25
|
+
/** How to build an {@link createAdminTemplateEnvironment}. */
|
|
26
|
+
export interface CreateAdminTemplateEnvironmentOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Recompile a template on every render instead of caching it, so editing an
|
|
29
|
+
* admin template in development shows up without a restart. On while the
|
|
30
|
+
* content watcher is on, which is the same switch as "this is a dev server".
|
|
31
|
+
*/
|
|
32
|
+
noCache?: boolean | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** A Nunjucks environment over {@link PACKAGED_ADMIN_DIR} and nothing else. */
|
|
35
|
+
export declare function createAdminTemplateEnvironment(options?: CreateAdminTemplateEnvironmentOptions): Environment;
|
|
36
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/admin/templates.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAoB,MAAM,UAAU,CAAC;AAIzD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAgE,CAAC;AAElG,qDAAqD;AACrD,eAAO,MAAM,eAAe;aAC1B,KAAK,EAAE,mBAAmB;aAC1B,KAAK,EAAE,mBAAmB;aAC1B,SAAS,EAAE,uBAAuB;aAClC,WAAW,EAAE,yBAAyB;aACtC,YAAY,EAAE,2BAA2B;aACzC,cAAc,EAAE,6BAA6B;aAC7C,gBAAgB,EAAE,+BAA+B;aACjD,QAAQ,EAAE,sBAAsB;aAChC,KAAK,EAAE,mBAAmB;aAC1B,UAAU,EAAE,wBAAwB;CAC5B,CAAC;AAEX,8DAA8D;AAC9D,MAAM,WAAW,qCAAqC;IACpD;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B;AAED,+EAA+E;AAC/E,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE,qCAA0C,GAClD,WAAW,CAmBb"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { Environment, FileSystemLoader } from 'nunjucks';
|
|
3
|
+
import { formatDate } from '../web/templates.js';
|
|
4
|
+
/**
|
|
5
|
+
* The admin's templates, resolved from this module rather than the working
|
|
6
|
+
* directory so they are found whether the CMS runs from `src/` under tsx or
|
|
7
|
+
* from `dist/` as an installed dependency.
|
|
8
|
+
*
|
|
9
|
+
* They are a set of their own, not part of the theme search path: a site's
|
|
10
|
+
* `theme/` may override any public template, and must not be able to shadow
|
|
11
|
+
* the login form or the CSRF field inside it.
|
|
12
|
+
*/
|
|
13
|
+
export const PACKAGED_ADMIN_DIR = fileURLToPath(new URL('../../admin/', import.meta.url));
|
|
14
|
+
/** Templates {@link mountAdmin} asks for by name. */
|
|
15
|
+
export const ADMIN_TEMPLATES = {
|
|
16
|
+
login: 'layouts/login.njk',
|
|
17
|
+
setup: 'layouts/setup.njk',
|
|
18
|
+
dashboard: 'layouts/dashboard.njk',
|
|
19
|
+
placeholder: 'layouts/placeholder.njk',
|
|
20
|
+
documentList: 'layouts/document-list.njk',
|
|
21
|
+
documentEditor: 'layouts/document-editor.njk',
|
|
22
|
+
documentConflict: 'layouts/document-conflict.njk',
|
|
23
|
+
settings: 'layouts/settings.njk',
|
|
24
|
+
users: 'layouts/users.njk',
|
|
25
|
+
federation: 'layouts/federation.njk',
|
|
26
|
+
};
|
|
27
|
+
/** A Nunjucks environment over {@link PACKAGED_ADMIN_DIR} and nothing else. */
|
|
28
|
+
export function createAdminTemplateEnvironment(options = {}) {
|
|
29
|
+
const loader = new FileSystemLoader([PACKAGED_ADMIN_DIR], {
|
|
30
|
+
noCache: options.noCache === true,
|
|
31
|
+
});
|
|
32
|
+
const environment = new Environment(loader, {
|
|
33
|
+
autoescape: true,
|
|
34
|
+
throwOnUndefined: false,
|
|
35
|
+
trimBlocks: true,
|
|
36
|
+
lstripBlocks: true,
|
|
37
|
+
});
|
|
38
|
+
// The same `date` filter the theme has, and formatted the same way, so a
|
|
39
|
+
// date reads identically on the public site and in the admin listing.
|
|
40
|
+
environment.addFilter('date', (value, format = 'readable') => formatDate(value, typeof format === 'string' ? format : 'readable'));
|
|
41
|
+
return environment;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/admin/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAW,aAAa,CAAC,IAAI,GAAG,CAAC,cAAc,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAElG,qDAAqD;AACrD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,KAAK,EAAE,mBAAmB;IAC1B,KAAK,EAAE,mBAAmB;IAC1B,SAAS,EAAE,uBAAuB;IAClC,WAAW,EAAE,yBAAyB;IACtC,YAAY,EAAE,2BAA2B;IACzC,cAAc,EAAE,6BAA6B;IAC7C,gBAAgB,EAAE,+BAA+B;IACjD,QAAQ,EAAE,sBAAsB;IAChC,KAAK,EAAE,mBAAmB;IAC1B,UAAU,EAAE,wBAAwB;CAC5B,CAAC;AAYX,+EAA+E;AAC/E,MAAM,UAAU,8BAA8B,CAC5C,OAAO,GAA0C,EAAE;IAEnD,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,CAAC,kBAAkB,CAAC,EAAE;QACxD,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,IAAI;KAClC,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE;QAC1C,UAAU,EAAE,IAAI;QAChB,gBAAgB,EAAE,KAAK;QACvB,UAAU,EAAE,IAAI;QAChB,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;IAEH,yEAAyE;IACzE,sEAAsE;IACtE,WAAW,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,KAAc,EAAE,MAAM,GAAY,UAAU,EAAE,EAAE,CAC7E,UAAU,CAAC,KAAK,EAAE,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CACpE,CAAC;IAEF,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Hono, MiddlewareHandler } from 'hono';
|
|
2
|
+
import type { ResolvedConfig } from '../config.ts';
|
|
3
|
+
import type { UploadMediaType } from '../content/media.ts';
|
|
4
|
+
import type { GeekityEnv } from '../env.ts';
|
|
5
|
+
/** Where the editor posts a file it wants stored. */
|
|
6
|
+
export declare const UPLOADS_PATH = "/admin/uploads";
|
|
7
|
+
/** The form field the file arrives in. */
|
|
8
|
+
export declare const UPLOAD_FIELD = "file";
|
|
9
|
+
/**
|
|
10
|
+
* Slack allowed on top of the size limit when a `Content-Length` is checked.
|
|
11
|
+
*
|
|
12
|
+
* A multipart body is the file plus a boundary, a couple of headers and a
|
|
13
|
+
* trailing marker. Nobody wants a 9.99 MiB image refused because its envelope
|
|
14
|
+
* pushed the request over ten, so the header check is deliberately generous
|
|
15
|
+
* and {@link mountUploads} does the exact one on the file itself.
|
|
16
|
+
*/
|
|
17
|
+
export declare const UPLOAD_ENVELOPE_BYTES = 8192;
|
|
18
|
+
/** What the editor gets back when a file has landed. */
|
|
19
|
+
export interface UploadResult {
|
|
20
|
+
/** The public URL of the file, which the site serves straight away. */
|
|
21
|
+
url: string;
|
|
22
|
+
/** Markdown to paste at the cursor: an embed for an image, a link otherwise. */
|
|
23
|
+
markdown: string;
|
|
24
|
+
}
|
|
25
|
+
/** The part of the config the upload rules are read out of. */
|
|
26
|
+
export type UploadConfig = Pick<ResolvedConfig, 'contentDir' | 'uploadTypes' | 'uploadMaxBytes'>;
|
|
27
|
+
/** One file that has landed under `content/uploads/`. */
|
|
28
|
+
export interface StoredUpload {
|
|
29
|
+
/** The public URL of the file, which the site serves straight away. */
|
|
30
|
+
url: string;
|
|
31
|
+
/** What the CMS decided the file is; `media.image` says whether it is one. */
|
|
32
|
+
media: UploadMediaType;
|
|
33
|
+
/** The submitted name without its extension, for a caption or an alt text. */
|
|
34
|
+
label: string;
|
|
35
|
+
}
|
|
36
|
+
/** Why an upload was refused, and the status that refusal answers with. */
|
|
37
|
+
export interface UploadRefusal {
|
|
38
|
+
/** 400 for a request carrying no file, 413 for one too big, 415 for one of the wrong sort. */
|
|
39
|
+
status: 400 | 413 | 415;
|
|
40
|
+
/** What to tell whoever sent it. */
|
|
41
|
+
error: string;
|
|
42
|
+
}
|
|
43
|
+
/** What a caller may ask of an upload beyond the site's own rules. */
|
|
44
|
+
export interface StoreUploadOptions {
|
|
45
|
+
/**
|
|
46
|
+
* Refuse anything that is not an image, whatever else the site's allowlist
|
|
47
|
+
* accepts. The avatar asks for this: a PDF is a fine upload and a hopeless
|
|
48
|
+
* profile picture.
|
|
49
|
+
*/
|
|
50
|
+
imagesOnly?: boolean | undefined;
|
|
51
|
+
}
|
|
52
|
+
/** Whether an upload came to a refusal rather than a stored file. */
|
|
53
|
+
export declare function refusedUpload(outcome: StoredUpload | UploadRefusal): outcome is UploadRefusal;
|
|
54
|
+
/**
|
|
55
|
+
* Validate one submitted file and write it under
|
|
56
|
+
* `content/uploads/{yyyy}/{mm}/{slug}{ext}`, or say why it cannot be.
|
|
57
|
+
*
|
|
58
|
+
* Three things have to agree before anything is written — the extension is on
|
|
59
|
+
* the site's allowlist, the media type the browser declared is one that
|
|
60
|
+
* extension is allowed to have, and the file's first bytes are that format's.
|
|
61
|
+
* A name is never overwritten; a second `photo.png` becomes `photo-2.png`.
|
|
62
|
+
*
|
|
63
|
+
* It is a function rather than part of the endpoint because the editor's
|
|
64
|
+
* uploads and the settings screen's avatar are the same rules over the same
|
|
65
|
+
* directory, and two copies of them would be two chances to disagree about
|
|
66
|
+
* what a site accepts.
|
|
67
|
+
*/
|
|
68
|
+
export declare function storeUpload(file: unknown, config: UploadConfig, options?: StoreUploadOptions): Promise<StoredUpload | UploadRefusal>;
|
|
69
|
+
/**
|
|
70
|
+
* Refuse an oversized upload by its headers, before anything reads it.
|
|
71
|
+
*
|
|
72
|
+
* This is registered in front of the admin guard on purpose. The guard finds
|
|
73
|
+
* the CSRF token by parsing the form, and parsing a multipart form pulls the
|
|
74
|
+
* whole file into the process — so by the time the request has been
|
|
75
|
+
* authenticated, a gigabyte has already been read. Checking the declared
|
|
76
|
+
* length first is the only place a body can be turned away before that
|
|
77
|
+
* happens. It gives nothing away: that `/admin/uploads` exists is in the
|
|
78
|
+
* package's own source.
|
|
79
|
+
*/
|
|
80
|
+
export declare const refuseOversizedUpload: MiddlewareHandler<GeekityEnv>;
|
|
81
|
+
/**
|
|
82
|
+
* Register the editor's upload endpoint.
|
|
83
|
+
*
|
|
84
|
+
* A file goes to `content/uploads/{yyyy}/{mm}/{slug}{ext}`, which is where the
|
|
85
|
+
* documented Eleventy config copies it through to `/uploads/` from, so the
|
|
86
|
+
* Markdown this hands back resolves whether the site is being served by the
|
|
87
|
+
* CMS or built as static files. Uploads are not documents: the index never
|
|
88
|
+
* sees them, and `content/uploads` is one of the directories the sync skips.
|
|
89
|
+
*
|
|
90
|
+
* What may be uploaded, and what happens to it, is {@link storeUpload}; this
|
|
91
|
+
* is that answer as the JSON the editor's upload control reads.
|
|
92
|
+
*/
|
|
93
|
+
export declare function mountUploads(app: Hono<GeekityEnv>): void;
|
|
94
|
+
/** What an upload over the site's limit is told, and the limit it went over. */
|
|
95
|
+
export declare function tooLargeMessage(limit: number): string;
|
|
96
|
+
//# sourceMappingURL=uploads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../../src/admin/uploads.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAI5C,qDAAqD;AACrD,eAAO,MAAM,YAAY,mBAA4B,CAAC;AAEtD,0CAA0C;AAC1C,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,aAAa,GAAG,gBAAgB,CAAC,CAAC;AAEjG,yDAAyD;AACzD,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,KAAK,EAAE,eAAe,CAAC;IACvB,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;CACf;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,8FAA8F;IAC9F,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACxB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,aAAa,GAAG,OAAO,IAAI,aAAa,CAE7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,YAAY,GAAG,aAAa,CAAC,CAyDvC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,EAAE,iBAAiB,CAAC,UAAU,CAU/D,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,CAiBxD;AA2BD,gFAAgF;AAChF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { matchesSignature, UPLOAD_MEDIA_TYPES } from '../content/media.js';
|
|
4
|
+
import { slugify } from '../content/slug.js';
|
|
5
|
+
import { UPLOAD_ASSET_PREFIX, UPLOAD_DIRECTORY } from '../web/assets.js';
|
|
6
|
+
import { ADMIN_PREFIX } from './session.js';
|
|
7
|
+
/** Where the editor posts a file it wants stored. */
|
|
8
|
+
export const UPLOADS_PATH = `${ADMIN_PREFIX}/uploads`;
|
|
9
|
+
/** The form field the file arrives in. */
|
|
10
|
+
export const UPLOAD_FIELD = 'file';
|
|
11
|
+
/**
|
|
12
|
+
* Slack allowed on top of the size limit when a `Content-Length` is checked.
|
|
13
|
+
*
|
|
14
|
+
* A multipart body is the file plus a boundary, a couple of headers and a
|
|
15
|
+
* trailing marker. Nobody wants a 9.99 MiB image refused because its envelope
|
|
16
|
+
* pushed the request over ten, so the header check is deliberately generous
|
|
17
|
+
* and {@link mountUploads} does the exact one on the file itself.
|
|
18
|
+
*/
|
|
19
|
+
export const UPLOAD_ENVELOPE_BYTES = 8192;
|
|
20
|
+
/** Whether an upload came to a refusal rather than a stored file. */
|
|
21
|
+
export function refusedUpload(outcome) {
|
|
22
|
+
return 'error' in outcome;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validate one submitted file and write it under
|
|
26
|
+
* `content/uploads/{yyyy}/{mm}/{slug}{ext}`, or say why it cannot be.
|
|
27
|
+
*
|
|
28
|
+
* Three things have to agree before anything is written — the extension is on
|
|
29
|
+
* the site's allowlist, the media type the browser declared is one that
|
|
30
|
+
* extension is allowed to have, and the file's first bytes are that format's.
|
|
31
|
+
* A name is never overwritten; a second `photo.png` becomes `photo-2.png`.
|
|
32
|
+
*
|
|
33
|
+
* It is a function rather than part of the endpoint because the editor's
|
|
34
|
+
* uploads and the settings screen's avatar are the same rules over the same
|
|
35
|
+
* directory, and two copies of them would be two chances to disagree about
|
|
36
|
+
* what a site accepts.
|
|
37
|
+
*/
|
|
38
|
+
export async function storeUpload(file, config, options = {}) {
|
|
39
|
+
if (!(file instanceof File)) {
|
|
40
|
+
return { status: 400, error: 'That upload carried no file.' };
|
|
41
|
+
}
|
|
42
|
+
const original = baseName(file.name);
|
|
43
|
+
const extension = path.extname(original).toLowerCase();
|
|
44
|
+
if (!config.uploadTypes.includes(extension)) {
|
|
45
|
+
const allowed = config.uploadTypes.join(', ');
|
|
46
|
+
return {
|
|
47
|
+
status: 415,
|
|
48
|
+
error: extension === ''
|
|
49
|
+
? `That file has no extension, so there is no telling what it is. This site accepts ${allowed}.`
|
|
50
|
+
: `Uploads of ${extension} are not allowed here. This site accepts ${allowed}.`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Guaranteed by resolveConfig, which refuses an allowlist naming anything
|
|
54
|
+
// the table has no entry for.
|
|
55
|
+
const media = UPLOAD_MEDIA_TYPES.get(extension);
|
|
56
|
+
if (options.imagesOnly === true && !media.image) {
|
|
57
|
+
return { status: 415, error: `A ${extension} is not an image, and this has to be one.` };
|
|
58
|
+
}
|
|
59
|
+
const declared = declaredType(file.type);
|
|
60
|
+
if (declared !== '' && !media.declared.includes(declared)) {
|
|
61
|
+
return {
|
|
62
|
+
status: 415,
|
|
63
|
+
error: `That file says it is ${declared}, which is not what a ${extension} is.`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (file.size > config.uploadMaxBytes) {
|
|
67
|
+
return { status: 413, error: tooLargeMessage(config.uploadMaxBytes) };
|
|
68
|
+
}
|
|
69
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
70
|
+
if (!matchesSignature(media, bytes)) {
|
|
71
|
+
return { status: 415, error: `That file does not look like a ${extension} inside.` };
|
|
72
|
+
}
|
|
73
|
+
const now = new Date();
|
|
74
|
+
const month = `${String(now.getUTCFullYear()).padStart(4, '0')}/${String(now.getUTCMonth() + 1).padStart(2, '0')}`;
|
|
75
|
+
const directory = path.join(config.contentDir, UPLOAD_DIRECTORY, ...month.split('/'));
|
|
76
|
+
await mkdir(directory, { recursive: true });
|
|
77
|
+
const stem = slugify(original.slice(0, original.length - extension.length)) || 'upload';
|
|
78
|
+
const name = await writeWithoutOverwriting(directory, stem, extension, bytes);
|
|
79
|
+
return {
|
|
80
|
+
url: `${UPLOAD_ASSET_PREFIX}${month}/${name}`,
|
|
81
|
+
media,
|
|
82
|
+
label: original.slice(0, original.length - extension.length).trim() || name,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Refuse an oversized upload by its headers, before anything reads it.
|
|
87
|
+
*
|
|
88
|
+
* This is registered in front of the admin guard on purpose. The guard finds
|
|
89
|
+
* the CSRF token by parsing the form, and parsing a multipart form pulls the
|
|
90
|
+
* whole file into the process — so by the time the request has been
|
|
91
|
+
* authenticated, a gigabyte has already been read. Checking the declared
|
|
92
|
+
* length first is the only place a body can be turned away before that
|
|
93
|
+
* happens. It gives nothing away: that `/admin/uploads` exists is in the
|
|
94
|
+
* package's own source.
|
|
95
|
+
*/
|
|
96
|
+
export const refuseOversizedUpload = async (c, next) => {
|
|
97
|
+
if (c.req.method !== 'POST')
|
|
98
|
+
return next();
|
|
99
|
+
const declared = Number(c.req.header('content-length') ?? '');
|
|
100
|
+
const limit = c.var.config.uploadMaxBytes;
|
|
101
|
+
if (Number.isFinite(declared) && declared > limit + UPLOAD_ENVELOPE_BYTES) {
|
|
102
|
+
return c.json({ error: tooLargeMessage(limit) }, 413);
|
|
103
|
+
}
|
|
104
|
+
await next();
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Register the editor's upload endpoint.
|
|
108
|
+
*
|
|
109
|
+
* A file goes to `content/uploads/{yyyy}/{mm}/{slug}{ext}`, which is where the
|
|
110
|
+
* documented Eleventy config copies it through to `/uploads/` from, so the
|
|
111
|
+
* Markdown this hands back resolves whether the site is being served by the
|
|
112
|
+
* CMS or built as static files. Uploads are not documents: the index never
|
|
113
|
+
* sees them, and `content/uploads` is one of the directories the sync skips.
|
|
114
|
+
*
|
|
115
|
+
* What may be uploaded, and what happens to it, is {@link storeUpload}; this
|
|
116
|
+
* is that answer as the JSON the editor's upload control reads.
|
|
117
|
+
*/
|
|
118
|
+
export function mountUploads(app) {
|
|
119
|
+
app.post(UPLOADS_PATH, async (c) => {
|
|
120
|
+
const body = await c.req.parseBody();
|
|
121
|
+
const outcome = await storeUpload(body[UPLOAD_FIELD], c.var.config);
|
|
122
|
+
if (refusedUpload(outcome)) {
|
|
123
|
+
return c.json({ error: outcome.error }, outcome.status);
|
|
124
|
+
}
|
|
125
|
+
const result = {
|
|
126
|
+
url: outcome.url,
|
|
127
|
+
markdown: outcome.media.image
|
|
128
|
+
? ``
|
|
129
|
+
: `[${escapeLabel(outcome.label)}](${outcome.url})`,
|
|
130
|
+
};
|
|
131
|
+
return c.json(result, 201);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Write the bytes under the first name in the directory that is free.
|
|
136
|
+
*
|
|
137
|
+
* The exclusive flag is what makes "free" true rather than merely true a
|
|
138
|
+
* moment ago: two uploads of `photo.png` racing each other both ask for the
|
|
139
|
+
* same name, one of them gets `EEXIST`, and it moves on to `photo-2.png`
|
|
140
|
+
* instead of overwriting what the other just wrote.
|
|
141
|
+
*/
|
|
142
|
+
async function writeWithoutOverwriting(directory, stem, extension, bytes) {
|
|
143
|
+
for (let suffix = 1;; suffix += 1) {
|
|
144
|
+
const name = suffix === 1 ? `${stem}${extension}` : `${stem}-${String(suffix)}${extension}`;
|
|
145
|
+
try {
|
|
146
|
+
await writeFile(path.join(directory, name), bytes, { flag: 'wx' });
|
|
147
|
+
return name;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (error.code !== 'EEXIST')
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** What an upload over the site's limit is told, and the limit it went over. */
|
|
156
|
+
export function tooLargeMessage(limit) {
|
|
157
|
+
return `That file is too big. This site accepts uploads up to ${String(limit)} bytes.`;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The last segment of a submitted filename.
|
|
161
|
+
*
|
|
162
|
+
* A browser sends a bare name, but a request is not a browser: anything with a
|
|
163
|
+
* path in it is reduced to its final component, so a name cannot be used to
|
|
164
|
+
* choose a directory. Both separators are cut, because a Windows client sends
|
|
165
|
+
* backslashes.
|
|
166
|
+
*/
|
|
167
|
+
function baseName(value) {
|
|
168
|
+
const segments = value.split(/[\\/]/);
|
|
169
|
+
return segments[segments.length - 1] ?? '';
|
|
170
|
+
}
|
|
171
|
+
/** A `Content-Type` header without its parameters, lower case. */
|
|
172
|
+
function declaredType(value) {
|
|
173
|
+
return (value.split(';')[0] ?? '').trim().toLowerCase();
|
|
174
|
+
}
|
|
175
|
+
/** A filename as Markdown link text: the three characters that would break out. */
|
|
176
|
+
function escapeLabel(value) {
|
|
177
|
+
return value.replace(/([\\[\]])/g, '\\$1');
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=uploads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploads.js","sourceRoot":"","sources":["../../src/admin/uploads.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
import type { GeekityEnv } from '../env.ts';
|
|
3
|
+
import type { AdminRender } from './documents.ts';
|
|
4
|
+
import type { User } from './store.ts';
|
|
5
|
+
/** Where the users screen lives. The add form posts here too. */
|
|
6
|
+
export declare const USERS_PATH = "/admin/users";
|
|
7
|
+
/** Where the signed-in admin's change-password form posts. */
|
|
8
|
+
export declare const CHANGE_PASSWORD_PATH = "/admin/users/password";
|
|
9
|
+
/** Where a row's delete button posts. */
|
|
10
|
+
export declare const DELETE_USER_PATH = "/admin/users/delete";
|
|
11
|
+
/** The fields the three forms on the screen submit. */
|
|
12
|
+
export declare const USER_FIELDS: {
|
|
13
|
+
readonly username: 'username';
|
|
14
|
+
readonly password: 'password';
|
|
15
|
+
readonly generate: 'generate';
|
|
16
|
+
readonly currentPassword: 'current_password';
|
|
17
|
+
readonly newPassword: 'new_password';
|
|
18
|
+
readonly newPasswordConfirmation: 'new_password_confirmation';
|
|
19
|
+
readonly userId: 'user_id';
|
|
20
|
+
};
|
|
21
|
+
/** What {@link mountUsers} needs from the admin around it. */
|
|
22
|
+
export interface MountUsersOptions {
|
|
23
|
+
/** The admin's renderer, which injects the chrome, the CSRF token and the flash. */
|
|
24
|
+
render: AdminRender;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Register the users screen: the list, the add form, and the change-password
|
|
28
|
+
* form for whoever is signed in.
|
|
29
|
+
*
|
|
30
|
+
* There is one role, so there is nothing to edit about somebody else: an admin
|
|
31
|
+
* can add a user, delete one, and change their own password. Changing
|
|
32
|
+
* somebody else's is deliberately not offered — resetting a colleague's
|
|
33
|
+
* password from under them is what `geekity user add` and a fresh account are
|
|
34
|
+
* for, and it keeps the current-password check honest.
|
|
35
|
+
*/
|
|
36
|
+
export declare function mountUsers(app: Hono<GeekityEnv>, options: MountUsersOptions): void;
|
|
37
|
+
/**
|
|
38
|
+
* Delete a user.
|
|
39
|
+
*
|
|
40
|
+
* Two refusals, in this order. The last remaining user cannot go, because a
|
|
41
|
+
* site with no users falls back into first-run setup and anybody who reaches
|
|
42
|
+
* it becomes its admin. And nobody may delete their own account: it would end
|
|
43
|
+
* the session doing the deleting, and there is no undo. Both are a flash and a
|
|
44
|
+
* redirect rather than a 400, because nothing was typed to send back.
|
|
45
|
+
*/
|
|
46
|
+
export declare function deleteUserRefusal(input: {
|
|
47
|
+
/** The user the form named, or `undefined` when there is no such row. */
|
|
48
|
+
target: User | undefined;
|
|
49
|
+
/** Who is asking. */
|
|
50
|
+
signedInAs: number | null;
|
|
51
|
+
/** How many users the site has. */
|
|
52
|
+
total: number;
|
|
53
|
+
}): string | undefined;
|
|
54
|
+
/** One message per field of the change-password form that is wrong. */
|
|
55
|
+
export type ChangePasswordProblems = {
|
|
56
|
+
currentPassword?: string;
|
|
57
|
+
newPassword?: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* What is wrong with a proposed password change, one message per field.
|
|
61
|
+
*
|
|
62
|
+
* The current password is taken as already checked, rather than checked here,
|
|
63
|
+
* so this stays a pure function over what the store said.
|
|
64
|
+
*/
|
|
65
|
+
export declare function changePasswordProblems(input: {
|
|
66
|
+
/** Whether the current password the form carried is this user's. */
|
|
67
|
+
correct: boolean;
|
|
68
|
+
next: string;
|
|
69
|
+
confirmation: string;
|
|
70
|
+
}): ChangePasswordProblems;
|
|
71
|
+
/** One message per field of the add form that is wrong. */
|
|
72
|
+
export type AddUserProblems = {
|
|
73
|
+
username?: string;
|
|
74
|
+
password?: string;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* What is wrong with a proposed user, one message per field.
|
|
78
|
+
*
|
|
79
|
+
* The rules are the shared ones, so an account made here is one
|
|
80
|
+
* `/admin/setup` and `geekity user add` would both have accepted. A generated
|
|
81
|
+
* password is not checked against them — it is made to satisfy them — and the
|
|
82
|
+
* password field is not read at all when the box is ticked, so a stale value
|
|
83
|
+
* left in it cannot be what is refused.
|
|
84
|
+
*/
|
|
85
|
+
export declare function addUserProblems(username: string, password: string, generate?: boolean): AddUserProblems;
|
|
86
|
+
/**
|
|
87
|
+
* The alphabet a generated password is drawn from: no `0`/`O` and no `1`/`l`,
|
|
88
|
+
* because a generated password is read off a screen and typed somewhere else.
|
|
89
|
+
*/
|
|
90
|
+
export declare const GENERATED_PASSWORD_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789";
|
|
91
|
+
/** How many characters a generated password has. 20 is about 116 bits here. */
|
|
92
|
+
export declare const GENERATED_PASSWORD_LENGTH = 20;
|
|
93
|
+
/** A password nobody chose, from `randomInt` rather than `Math.random`. */
|
|
94
|
+
export declare function generatePassword(): string;
|
|
95
|
+
//# sourceMappingURL=users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/admin/users.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGvC,iEAAiE;AACjE,eAAO,MAAM,UAAU,iBAA0B,CAAC;AAElD,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,0BAA2B,CAAC;AAE7D,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,wBAAyB,CAAC;AAEvD,uDAAuD;AACvD,eAAO,MAAM,WAAW;aACtB,QAAQ,EAAE,UAAU;aACpB,QAAQ,EAAE,UAAU;aACpB,QAAQ,EAAE,UAAU;aACpB,eAAe,EAAE,kBAAkB;aACnC,WAAW,EAAE,cAAc;aAC3B,uBAAuB,EAAE,2BAA2B;aACpD,MAAM,EAAE,SAAS;CACT,CAAC;AAEX,8DAA8D;AAC9D,MAAM,WAAW,iBAAiB;IAChC,oFAAoF;IACpF,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAiHlF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,yEAAyE;IACzE,MAAM,EAAE,IAAI,GAAG,SAAS,CAAC;IACzB,qBAAqB;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,GAAG,SAAS,CASrB;AAED,uEAAuE;AACvE,MAAM,MAAM,sBAAsB,GAAG;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExF;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,oEAAoE;IACpE,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,sBAAsB,CAYzB;AAOD,2DAA2D;AAC3D,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,UAAQ,GACf,eAAe,CAYjB;AAED;;;GAGG;AACH,eAAO,MAAM,2BAA2B,8DACqB,CAAC;AAE9D,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,2EAA2E;AAC3E,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC"}
|