webspresso 0.0.93 → 0.0.95
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/bin/commands/polar-migrate.js +50 -0
- package/bin/webspresso.js +2 -0
- package/core/auth/tokens.js +16 -0
- package/core/orm/cache/layer.js +1 -1
- package/core/orm/index.js +4 -1
- package/core/orm/transaction.js +3 -1
- package/core/ssr/stream.js +58 -14
- package/package.json +15 -4
- package/plugins/admin-panel/auth.js +10 -0
- package/plugins/content/index.js +5 -3
- package/plugins/data-exchange/import.js +76 -39
- package/plugins/index.js +2 -0
- package/plugins/mcp/transports/sse.js +23 -6
- package/plugins/polar/.env.example +12 -0
- package/plugins/polar/CHANGELOG.md +56 -0
- package/plugins/polar/README.md +181 -0
- package/plugins/polar/index.js +149 -0
- package/plugins/polar/src/api.js +54 -0
- package/plugins/polar/src/billing-hooks.js +51 -0
- package/plugins/polar/src/checkout.js +111 -0
- package/plugins/polar/src/config.js +90 -0
- package/plugins/polar/src/env.schema.js +36 -0
- package/plugins/polar/src/middleware.js +37 -0
- package/plugins/polar/src/migration.js +58 -0
- package/plugins/polar/src/nunjucks-filters.js +56 -0
- package/plugins/polar/src/portal.js +51 -0
- package/plugins/polar/src/rate-limit.js +138 -0
- package/plugins/polar/src/routes.js +213 -0
- package/plugins/polar/src/sync.js +138 -0
- package/plugins/polar/src/urls.js +141 -0
- package/plugins/polar/src/user-resolver.js +199 -0
- package/plugins/polar/src/webhooks.js +248 -0
- package/plugins/rate-limit/index.js +5 -1
- package/src/file-router.js +19 -2
- package/src/helpers.js +60 -13
- package/templates/skills/webspresso-usage/REFERENCE-framework.md +1 -0
package/src/helpers.js
CHANGED
|
@@ -616,31 +616,54 @@ function createHelpers(ctx) {
|
|
|
616
616
|
// ============================================
|
|
617
617
|
|
|
618
618
|
/**
|
|
619
|
-
* Get
|
|
619
|
+
* Get CSP nonce if available from request context
|
|
620
|
+
* @returns {string} Nonce string or empty string
|
|
621
|
+
*/
|
|
622
|
+
nonce() {
|
|
623
|
+
return (
|
|
624
|
+
req?.res?.locals?.cspNonce ||
|
|
625
|
+
req?.res?.locals?.nonce ||
|
|
626
|
+
res?.locals?.cspNonce ||
|
|
627
|
+
res?.locals?.nonce ||
|
|
628
|
+
req?.cspNonce ||
|
|
629
|
+
req?.nonce ||
|
|
630
|
+
''
|
|
631
|
+
);
|
|
632
|
+
},
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Get injected head content (CSS, scripts)
|
|
636
|
+
* @param {Object|string} [options] - Optional { nonce: string } or nonce string
|
|
620
637
|
* @returns {string} HTML content for head section
|
|
621
638
|
*/
|
|
622
|
-
injectHead() {
|
|
639
|
+
injectHead(options) {
|
|
640
|
+
const explicitNonce = typeof options === 'string' ? options : options?.nonce;
|
|
641
|
+
const nonce = explicitNonce || this.nonce();
|
|
623
642
|
const injector = getScriptInjector();
|
|
624
643
|
let content = '';
|
|
625
644
|
|
|
626
645
|
// Add styles
|
|
627
|
-
const styles = injector.getStylesContent();
|
|
646
|
+
const styles = injector.getStylesContent(nonce ? { nonce } : options);
|
|
628
647
|
if (styles) {
|
|
629
|
-
|
|
648
|
+
const nonceAttr = nonce ? ` nonce="${nonce}"` : '';
|
|
649
|
+
content += `<style id="webspresso-injected-styles"${nonceAttr}>\n${styles}\n</style>\n`;
|
|
630
650
|
}
|
|
631
651
|
|
|
632
652
|
// Add head scripts
|
|
633
|
-
content += injector.getHeadContent();
|
|
653
|
+
content += injector.getHeadContent(nonce ? { nonce } : options);
|
|
634
654
|
|
|
635
655
|
return content;
|
|
636
656
|
},
|
|
637
657
|
|
|
638
658
|
/**
|
|
639
659
|
* Get injected body content (for end of body)
|
|
660
|
+
* @param {Object|string} [options] - Optional { nonce: string } or nonce string
|
|
640
661
|
* @returns {string} HTML content for body end
|
|
641
662
|
*/
|
|
642
|
-
injectBody() {
|
|
643
|
-
|
|
663
|
+
injectBody(options) {
|
|
664
|
+
const explicitNonce = typeof options === 'string' ? options : options?.nonce;
|
|
665
|
+
const nonce = explicitNonce || this.nonce();
|
|
666
|
+
return getScriptInjector().getBodyContent(nonce ? { nonce } : options);
|
|
644
667
|
},
|
|
645
668
|
|
|
646
669
|
/**
|
|
@@ -726,25 +749,49 @@ class ScriptInjector {
|
|
|
726
749
|
|
|
727
750
|
/**
|
|
728
751
|
* Get head content sorted by priority
|
|
752
|
+
* @param {Object|string} [options] - Optional { nonce: string } or nonce string
|
|
729
753
|
*/
|
|
730
|
-
getHeadContent() {
|
|
754
|
+
getHeadContent(options = {}) {
|
|
755
|
+
const nonce = typeof options === 'string' ? options : (options?.nonce || '');
|
|
731
756
|
const sorted = [...this.headScripts].sort((a, b) => b.priority - a.priority);
|
|
732
|
-
return sorted.map(s =>
|
|
757
|
+
return sorted.map(s => {
|
|
758
|
+
let content = typeof s.content === 'function' ? s.content(options) : s.content;
|
|
759
|
+
if (nonce && typeof content === 'string') {
|
|
760
|
+
content = content.replace(/<script(?![^>]*\bnonce=)/gi, `<script nonce="${nonce}"`);
|
|
761
|
+
}
|
|
762
|
+
return content;
|
|
763
|
+
}).join('\n');
|
|
733
764
|
}
|
|
734
765
|
|
|
735
766
|
/**
|
|
736
767
|
* Get body content sorted by priority
|
|
768
|
+
* @param {Object|string} [options] - Optional { nonce: string } or nonce string
|
|
737
769
|
*/
|
|
738
|
-
getBodyContent() {
|
|
770
|
+
getBodyContent(options = {}) {
|
|
771
|
+
const nonce = typeof options === 'string' ? options : (options?.nonce || '');
|
|
739
772
|
const sorted = [...this.bodyScripts].sort((a, b) => b.priority - a.priority);
|
|
740
|
-
return sorted.map(s =>
|
|
773
|
+
return sorted.map(s => {
|
|
774
|
+
let content = typeof s.content === 'function' ? s.content(options) : s.content;
|
|
775
|
+
if (nonce && typeof content === 'string') {
|
|
776
|
+
content = content.replace(/<script(?![^>]*\bnonce=)/gi, `<script nonce="${nonce}"`);
|
|
777
|
+
}
|
|
778
|
+
return content;
|
|
779
|
+
}).join('\n');
|
|
741
780
|
}
|
|
742
781
|
|
|
743
782
|
/**
|
|
744
783
|
* Get styles content
|
|
784
|
+
* @param {Object|string} [options] - Optional { nonce: string } or nonce string
|
|
745
785
|
*/
|
|
746
|
-
getStylesContent() {
|
|
747
|
-
|
|
786
|
+
getStylesContent(options = {}) {
|
|
787
|
+
const nonce = typeof options === 'string' ? options : (options?.nonce || '');
|
|
788
|
+
return this.styles.map(s => {
|
|
789
|
+
let content = typeof s.content === 'function' ? s.content(options) : s.content;
|
|
790
|
+
if (nonce && typeof content === 'string') {
|
|
791
|
+
content = content.replace(/<style(?![^>]*\bnonce=)/gi, `<style nonce="${nonce}"`);
|
|
792
|
+
}
|
|
793
|
+
return content;
|
|
794
|
+
}).join('\n');
|
|
748
795
|
}
|
|
749
796
|
|
|
750
797
|
/**
|
|
@@ -213,6 +213,7 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
|
|
|
213
213
|
| `auditLogPlugin` | Admin mutation audit trail |
|
|
214
214
|
| `recaptchaPlugin` | v2/v3 + middleware |
|
|
215
215
|
| `emailPlugin` | MJML + Nodemailer sending with optional admin UI and auth bridge |
|
|
216
|
+
| `polarPlugin` | Polar.sh billing: checkout, portal, webhooks, tier sync (`webspresso polar:migrate`) |
|
|
216
217
|
| `seoCheckerPlugin` | Dev SEO panel |
|
|
217
218
|
| `restResourcePlugin` | Opt-in REST CRUD from models; `?include=` uses ORM eager load (single-level relations only) |
|
|
218
219
|
| `ormCacheAdminPlugin` | Admin page for ORM cache metrics / purge / invalidate (`db.cache` required) |
|