@kywi-software/core 0.14.0 → 0.15.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/AGENT-PATTERNS.md +153 -17
- package/README.md +38 -12
- package/dist/admin/chrome.d.ts.map +1 -1
- package/dist/admin/chrome.js +6 -7
- package/dist/admin/chrome.js.map +1 -1
- package/dist/admin/field-components.d.ts.map +1 -1
- package/dist/admin/field-components.js +27 -1
- package/dist/admin/field-components.js.map +1 -1
- package/dist/admin/form-helpers.d.ts.map +1 -1
- package/dist/admin/form-helpers.js +6 -1
- package/dist/admin/form-helpers.js.map +1 -1
- package/dist/admin/layout-editor/chrome-env.d.ts +35 -0
- package/dist/admin/layout-editor/chrome-env.d.ts.map +1 -0
- package/dist/admin/layout-editor/chrome-env.js +13 -0
- package/dist/admin/layout-editor/chrome-env.js.map +1 -0
- package/dist/admin/layout-editor/component-actions.d.ts +58 -7
- package/dist/admin/layout-editor/component-actions.d.ts.map +1 -1
- package/dist/admin/layout-editor/component-actions.js +131 -5
- package/dist/admin/layout-editor/component-actions.js.map +1 -1
- package/dist/admin/layout-editor/component-fork.d.ts +4 -4
- package/dist/admin/layout-editor/component-fork.d.ts.map +1 -1
- package/dist/admin/layout-editor/component-fork.js +76 -10
- package/dist/admin/layout-editor/component-fork.js.map +1 -1
- package/dist/admin/layout-editor/component-picker-field.d.ts +17 -3
- package/dist/admin/layout-editor/component-picker-field.d.ts.map +1 -1
- package/dist/admin/layout-editor/component-picker-field.js +5 -2
- package/dist/admin/layout-editor/component-picker-field.js.map +1 -1
- package/dist/admin/layout-editor/drag-feedback.d.ts +25 -1
- package/dist/admin/layout-editor/drag-feedback.d.ts.map +1 -1
- package/dist/admin/layout-editor/drag-feedback.js +9 -0
- package/dist/admin/layout-editor/drag-feedback.js.map +1 -1
- package/dist/admin/layout-editor/drag-utils.d.ts +103 -5
- package/dist/admin/layout-editor/drag-utils.d.ts.map +1 -1
- package/dist/admin/layout-editor/drag-utils.js +131 -4
- package/dist/admin/layout-editor/drag-utils.js.map +1 -1
- package/dist/admin/layout-editor/editor-canvas.d.ts +11 -0
- package/dist/admin/layout-editor/editor-canvas.d.ts.map +1 -1
- package/dist/admin/layout-editor/editor-canvas.js +134 -20
- package/dist/admin/layout-editor/editor-canvas.js.map +1 -1
- package/dist/admin/layout-editor/editor-dialog.d.ts +58 -3
- package/dist/admin/layout-editor/editor-dialog.d.ts.map +1 -1
- package/dist/admin/layout-editor/editor-dialog.js +71 -9
- package/dist/admin/layout-editor/editor-dialog.js.map +1 -1
- package/dist/admin/layout-editor/editor-state.d.ts +119 -0
- package/dist/admin/layout-editor/editor-state.d.ts.map +1 -1
- package/dist/admin/layout-editor/editor-state.js +188 -6
- package/dist/admin/layout-editor/editor-state.js.map +1 -1
- package/dist/admin/layout-editor/editor-toolbar.d.ts +10 -1
- package/dist/admin/layout-editor/editor-toolbar.d.ts.map +1 -1
- package/dist/admin/layout-editor/editor-toolbar.js +2 -2
- package/dist/admin/layout-editor/editor-toolbar.js.map +1 -1
- package/dist/admin/layout-editor/editor.css +216 -8
- package/dist/admin/layout-editor/inline-text.d.ts +15 -1
- package/dist/admin/layout-editor/inline-text.d.ts.map +1 -1
- package/dist/admin/layout-editor/inline-text.js +30 -2
- package/dist/admin/layout-editor/inline-text.js.map +1 -1
- package/dist/admin/layout-editor/layout-editor.d.ts +21 -16
- package/dist/admin/layout-editor/layout-editor.d.ts.map +1 -1
- package/dist/admin/layout-editor/layout-editor.js +40 -17
- package/dist/admin/layout-editor/layout-editor.js.map +1 -1
- package/dist/admin/layout-editor/linked-component-notes.d.ts +88 -0
- package/dist/admin/layout-editor/linked-component-notes.d.ts.map +1 -0
- package/dist/admin/layout-editor/linked-component-notes.js +88 -0
- package/dist/admin/layout-editor/linked-component-notes.js.map +1 -0
- package/dist/admin/layout-editor/module-overlay.d.ts +23 -4
- package/dist/admin/layout-editor/module-overlay.d.ts.map +1 -1
- package/dist/admin/layout-editor/module-overlay.js +56 -10
- package/dist/admin/layout-editor/module-overlay.js.map +1 -1
- package/dist/admin/layout-editor/module-variant-container-config.d.ts.map +1 -1
- package/dist/admin/layout-editor/module-variant-container-config.js +9 -2
- package/dist/admin/layout-editor/module-variant-container-config.js.map +1 -1
- package/dist/admin/layout-editor/module-variant-container-panel.d.ts +75 -0
- package/dist/admin/layout-editor/module-variant-container-panel.d.ts.map +1 -0
- package/dist/admin/layout-editor/module-variant-container-panel.js +29 -0
- package/dist/admin/layout-editor/module-variant-container-panel.js.map +1 -0
- package/dist/admin/layout-editor/node-lookup.d.ts.map +1 -1
- package/dist/admin/layout-editor/node-lookup.js +33 -3
- package/dist/admin/layout-editor/node-lookup.js.map +1 -1
- package/dist/admin/layout-editor/overlay-shell.d.ts.map +1 -1
- package/dist/admin/layout-editor/overlay-shell.js +19 -4
- package/dist/admin/layout-editor/overlay-shell.js.map +1 -1
- package/dist/admin/layout-editor/props-panel.d.ts +28 -11
- package/dist/admin/layout-editor/props-panel.d.ts.map +1 -1
- package/dist/admin/layout-editor/props-panel.js +75 -125
- package/dist/admin/layout-editor/props-panel.js.map +1 -1
- package/dist/admin/layout-editor/section-variant-container-config.d.ts.map +1 -1
- package/dist/admin/layout-editor/section-variant-container-config.js +11 -2
- package/dist/admin/layout-editor/section-variant-container-config.js.map +1 -1
- package/dist/admin/layout-editor/use-chrome-flip.d.ts +99 -11
- package/dist/admin/layout-editor/use-chrome-flip.d.ts.map +1 -1
- package/dist/admin/layout-editor/use-chrome-flip.js +268 -97
- package/dist/admin/layout-editor/use-chrome-flip.js.map +1 -1
- package/dist/admin/layout-editor/use-component-connect.d.ts +13 -0
- package/dist/admin/layout-editor/use-component-connect.d.ts.map +1 -1
- package/dist/admin/layout-editor/use-component-connect.js +116 -20
- package/dist/admin/layout-editor/use-component-connect.js.map +1 -1
- package/dist/admin/layout-editor/use-component-fork.d.ts +49 -19
- package/dist/admin/layout-editor/use-component-fork.d.ts.map +1 -1
- package/dist/admin/layout-editor/use-component-fork.js +28 -19
- package/dist/admin/layout-editor/use-component-fork.js.map +1 -1
- package/dist/admin/layout-editor/use-component-library.d.ts +4 -4
- package/dist/admin/layout-editor/use-component-library.d.ts.map +1 -1
- package/dist/admin/layout-editor/use-component-library.js +1 -1
- package/dist/admin/layout-editor/use-component-library.js.map +1 -1
- package/dist/admin/layout-editor/use-editor-dnd.d.ts +10 -0
- package/dist/admin/layout-editor/use-editor-dnd.d.ts.map +1 -1
- package/dist/admin/layout-editor/use-editor-dnd.js +234 -14
- package/dist/admin/layout-editor/use-editor-dnd.js.map +1 -1
- package/dist/admin/layout-editor/variant-container-config.d.ts.map +1 -1
- package/dist/admin/layout-editor/variant-container-config.js +1 -1
- package/dist/admin/layout-editor/variant-container-config.js.map +1 -1
- package/dist/admin/layout-editor/variant-editor.d.ts +16 -15
- package/dist/admin/layout-editor/variant-editor.d.ts.map +1 -1
- package/dist/admin/layout-editor/variant-editor.js +16 -5
- package/dist/admin/layout-editor/variant-editor.js.map +1 -1
- package/dist/admin/primitives.d.ts.map +1 -1
- package/dist/admin/primitives.js +1 -1
- package/dist/admin/primitives.js.map +1 -1
- package/dist/admin/registry.d.ts +12 -0
- package/dist/admin/registry.d.ts.map +1 -1
- package/dist/admin/registry.js +12 -0
- package/dist/admin/registry.js.map +1 -1
- package/dist/admin/server.d.ts +10 -1
- package/dist/admin/server.d.ts.map +1 -1
- package/dist/admin/server.js +4 -1
- package/dist/admin/server.js.map +1 -1
- package/dist/admin/site-switcher.d.ts +16 -3
- package/dist/admin/site-switcher.d.ts.map +1 -1
- package/dist/admin/site-switcher.js +18 -3
- package/dist/admin/site-switcher.js.map +1 -1
- package/dist/admin/styles/admin.css +0 -3
- package/dist/admin/surface-matcher.d.ts +6 -2
- package/dist/admin/surface-matcher.d.ts.map +1 -1
- package/dist/admin/surface-matcher.js +42 -5
- package/dist/admin/surface-matcher.js.map +1 -1
- package/dist/admin/surfaces/components/components-data.d.ts +31 -11
- package/dist/admin/surfaces/components/components-data.d.ts.map +1 -1
- package/dist/admin/surfaces/components/components-data.js +17 -4
- package/dist/admin/surfaces/components/components-data.js.map +1 -1
- package/dist/admin/surfaces/components/components-list.d.ts.map +1 -1
- package/dist/admin/surfaces/components/components-list.js +20 -7
- package/dist/admin/surfaces/components/components-list.js.map +1 -1
- package/dist/admin/surfaces/components/definition-canvas.d.ts +11 -3
- package/dist/admin/surfaces/components/definition-canvas.d.ts.map +1 -1
- package/dist/admin/surfaces/components/definition-canvas.js +138 -17
- package/dist/admin/surfaces/components/definition-canvas.js.map +1 -1
- package/dist/admin/surfaces/dashboard/dashboard-index.d.ts.map +1 -1
- package/dist/admin/surfaces/dashboard/dashboard-index.js +2 -2
- package/dist/admin/surfaces/dashboard/dashboard-index.js.map +1 -1
- package/dist/admin/surfaces/layouts/layout-editor-client.d.ts.map +1 -1
- package/dist/admin/surfaces/layouts/layout-editor-client.js +12 -11
- package/dist/admin/surfaces/layouts/layout-editor-client.js.map +1 -1
- package/dist/admin/surfaces/menus/menu-editor.d.ts.map +1 -1
- package/dist/admin/surfaces/menus/menu-editor.js +17 -4
- package/dist/admin/surfaces/menus/menu-editor.js.map +1 -1
- package/dist/admin/surfaces/menus/menu-tree.d.ts +18 -4
- package/dist/admin/surfaces/menus/menu-tree.d.ts.map +1 -1
- package/dist/admin/surfaces/menus/menu-tree.js +18 -3
- package/dist/admin/surfaces/menus/menu-tree.js.map +1 -1
- package/dist/admin/surfaces/menus/menus-data.d.ts +18 -0
- package/dist/admin/surfaces/menus/menus-data.d.ts.map +1 -1
- package/dist/admin/surfaces/menus/menus-data.js +4 -0
- package/dist/admin/surfaces/menus/menus-data.js.map +1 -1
- package/dist/admin/surfaces/menus/menus-list.d.ts.map +1 -1
- package/dist/admin/surfaces/menus/menus-list.js +2 -12
- package/dist/admin/surfaces/menus/menus-list.js.map +1 -1
- package/dist/admin/surfaces/users/users-data.d.ts +14 -0
- package/dist/admin/surfaces/users/users-data.d.ts.map +1 -1
- package/dist/admin/surfaces/users/users-data.js +19 -0
- package/dist/admin/surfaces/users/users-data.js.map +1 -1
- package/dist/admin/surfaces/users/users-detail.d.ts.map +1 -1
- package/dist/admin/surfaces/users/users-detail.js +40 -4
- package/dist/admin/surfaces/users/users-detail.js.map +1 -1
- package/dist/admin/surfaces/users/users-new.d.ts.map +1 -1
- package/dist/admin/surfaces/users/users-new.js +8 -5
- package/dist/admin/surfaces/users/users-new.js.map +1 -1
- package/dist/admin/user-form.d.ts +10 -1
- package/dist/admin/user-form.d.ts.map +1 -1
- package/dist/admin/user-form.js +2 -2
- package/dist/admin/user-form.js.map +1 -1
- package/dist/api/admin-features-routes.js +2 -2
- package/dist/api/admin-features-routes.js.map +1 -1
- package/dist/api/audience-preview-routes.d.ts +7 -0
- package/dist/api/audience-preview-routes.d.ts.map +1 -1
- package/dist/api/audience-preview-routes.js +4 -4
- package/dist/api/audience-preview-routes.js.map +1 -1
- package/dist/api/audience-routes.d.ts +7 -0
- package/dist/api/audience-routes.d.ts.map +1 -1
- package/dist/api/audience-routes.js +21 -15
- package/dist/api/audience-routes.js.map +1 -1
- package/dist/api/audience-runtime-routes.d.ts +6 -0
- package/dist/api/audience-runtime-routes.d.ts.map +1 -1
- package/dist/api/audience-runtime-routes.js +38 -3
- package/dist/api/audience-runtime-routes.js.map +1 -1
- package/dist/api/auth-routes.d.ts.map +1 -1
- package/dist/api/auth-routes.js +10 -4
- package/dist/api/auth-routes.js.map +1 -1
- package/dist/api/auth.d.ts +1 -0
- package/dist/api/auth.d.ts.map +1 -1
- package/dist/api/auth.js +43 -3
- package/dist/api/auth.js.map +1 -1
- package/dist/api/bulk-routes.d.ts.map +1 -1
- package/dist/api/bulk-routes.js +7 -7
- package/dist/api/bulk-routes.js.map +1 -1
- package/dist/api/category-routes.js +3 -3
- package/dist/api/category-routes.js.map +1 -1
- package/dist/api/comment-routes.js +8 -8
- package/dist/api/comment-routes.js.map +1 -1
- package/dist/api/component-routes.d.ts +25 -0
- package/dist/api/component-routes.d.ts.map +1 -1
- package/dist/api/component-routes.js +41 -16
- package/dist/api/component-routes.js.map +1 -1
- package/dist/api/content-routes.js +13 -13
- package/dist/api/content-routes.js.map +1 -1
- package/dist/api/dashboard-routes.js +1 -1
- package/dist/api/dashboard-routes.js.map +1 -1
- package/dist/api/experiment-routes.d.ts +7 -0
- package/dist/api/experiment-routes.d.ts.map +1 -1
- package/dist/api/experiment-routes.js +8 -8
- package/dist/api/experiment-routes.js.map +1 -1
- package/dist/api/experiment-runtime-routes.d.ts +6 -0
- package/dist/api/experiment-runtime-routes.d.ts.map +1 -1
- package/dist/api/experiment-runtime-routes.js +47 -11
- package/dist/api/experiment-runtime-routes.js.map +1 -1
- package/dist/api/feed-routes.d.ts +2 -2
- package/dist/api/feed-routes.js +3 -3
- package/dist/api/feed-routes.js.map +1 -1
- package/dist/api/form-routes.js +4 -4
- package/dist/api/form-routes.js.map +1 -1
- package/dist/api/graphql/resolvers.d.ts +1 -1
- package/dist/api/graphql/resolvers.d.ts.map +1 -1
- package/dist/api/graphql/resolvers.js +68 -33
- package/dist/api/graphql/resolvers.js.map +1 -1
- package/dist/api/group-routes.js +6 -6
- package/dist/api/group-routes.js.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +39 -6
- package/dist/api/index.js.map +1 -1
- package/dist/api/layout-routes.d.ts.map +1 -1
- package/dist/api/layout-routes.js +27 -3
- package/dist/api/layout-routes.js.map +1 -1
- package/dist/api/media-routes.d.ts.map +1 -1
- package/dist/api/media-routes.js +50 -26
- package/dist/api/media-routes.js.map +1 -1
- package/dist/api/menu-routes.d.ts +9 -1
- package/dist/api/menu-routes.d.ts.map +1 -1
- package/dist/api/menu-routes.js +44 -10
- package/dist/api/menu-routes.js.map +1 -1
- package/dist/api/nav-routes.d.ts +6 -0
- package/dist/api/nav-routes.d.ts.map +1 -1
- package/dist/api/nav-routes.js +24 -3
- package/dist/api/nav-routes.js.map +1 -1
- package/dist/api/openapi.d.ts.map +1 -1
- package/dist/api/openapi.js +68 -33
- package/dist/api/openapi.js.map +1 -1
- package/dist/api/search-routes.js +2 -2
- package/dist/api/search-routes.js.map +1 -1
- package/dist/api/section-template-routes.d.ts.map +1 -1
- package/dist/api/section-template-routes.js +35 -18
- package/dist/api/section-template-routes.js.map +1 -1
- package/dist/api/site-admin-routes.d.ts +10 -1
- package/dist/api/site-admin-routes.d.ts.map +1 -1
- package/dist/api/site-admin-routes.js +21 -1
- package/dist/api/site-admin-routes.js.map +1 -1
- package/dist/api/site-context.d.ts +35 -5
- package/dist/api/site-context.d.ts.map +1 -1
- package/dist/api/site-context.js +21 -6
- package/dist/api/site-context.js.map +1 -1
- package/dist/api/tag-routes.js +3 -3
- package/dist/api/tag-routes.js.map +1 -1
- package/dist/api/translation-routes.js +5 -5
- package/dist/api/translation-routes.js.map +1 -1
- package/dist/api/user-routes.d.ts.map +1 -1
- package/dist/api/user-routes.js +134 -19
- package/dist/api/user-routes.js.map +1 -1
- package/dist/api/webhook-routes.js +5 -5
- package/dist/api/webhook-routes.js.map +1 -1
- package/dist/api/workflow-routes.js +8 -8
- package/dist/api/workflow-routes.js.map +1 -1
- package/dist/audiences/collectors/identity.d.ts +14 -1
- package/dist/audiences/collectors/identity.d.ts.map +1 -1
- package/dist/audiences/collectors/identity.js +16 -3
- package/dist/audiences/collectors/identity.js.map +1 -1
- package/dist/audiences/collectors/index.d.ts +12 -2
- package/dist/audiences/collectors/index.d.ts.map +1 -1
- package/dist/audiences/collectors/index.js +16 -5
- package/dist/audiences/collectors/index.js.map +1 -1
- package/dist/audiences/collectors/pinned-audience.d.ts +28 -2
- package/dist/audiences/collectors/pinned-audience.d.ts.map +1 -1
- package/dist/audiences/collectors/pinned-audience.js +35 -5
- package/dist/audiences/collectors/pinned-audience.js.map +1 -1
- package/dist/audiences/collectors/utm.d.ts +15 -1
- package/dist/audiences/collectors/utm.d.ts.map +1 -1
- package/dist/audiences/collectors/utm.js +16 -2
- package/dist/audiences/collectors/utm.js.map +1 -1
- package/dist/audiences/consent-config.d.ts +21 -0
- package/dist/audiences/consent-config.d.ts.map +1 -0
- package/dist/audiences/consent-config.js +15 -0
- package/dist/audiences/consent-config.js.map +1 -0
- package/dist/audiences/consent-startup.d.ts +39 -0
- package/dist/audiences/consent-startup.d.ts.map +1 -0
- package/dist/audiences/consent-startup.js +105 -0
- package/dist/audiences/consent-startup.js.map +1 -0
- package/dist/audiences/consent.d.ts +192 -0
- package/dist/audiences/consent.d.ts.map +1 -0
- package/dist/audiences/consent.js +322 -0
- package/dist/audiences/consent.js.map +1 -0
- package/dist/audiences/engine.d.ts +7 -0
- package/dist/audiences/engine.d.ts.map +1 -1
- package/dist/audiences/engine.js +6 -2
- package/dist/audiences/engine.js.map +1 -1
- package/dist/audiences/index.d.ts +3 -0
- package/dist/audiences/index.d.ts.map +1 -1
- package/dist/audiences/index.js +6 -0
- package/dist/audiences/index.js.map +1 -1
- package/dist/audiences/server-eval.d.ts +13 -1
- package/dist/audiences/server-eval.d.ts.map +1 -1
- package/dist/audiences/server-eval.js +18 -2
- package/dist/audiences/server-eval.js.map +1 -1
- package/dist/audiences/ssr.d.ts +18 -1
- package/dist/audiences/ssr.d.ts.map +1 -1
- package/dist/audiences/ssr.js +18 -1
- package/dist/audiences/ssr.js.map +1 -1
- package/dist/audiences/utm-persistence.d.ts +20 -7
- package/dist/audiences/utm-persistence.d.ts.map +1 -1
- package/dist/audiences/utm-persistence.js +20 -7
- package/dist/audiences/utm-persistence.js.map +1 -1
- package/dist/auth/roles.d.ts +11 -0
- package/dist/auth/roles.d.ts.map +1 -1
- package/dist/auth/roles.js +13 -0
- package/dist/auth/roles.js.map +1 -1
- package/dist/auth/tokens.d.ts +7 -0
- package/dist/auth/tokens.d.ts.map +1 -1
- package/dist/auth/tokens.js +24 -2
- package/dist/auth/tokens.js.map +1 -1
- package/dist/config/types.d.ts +43 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/config/validate.d.ts.map +1 -1
- package/dist/config/validate.js +3 -0
- package/dist/config/validate.js.map +1 -1
- package/dist/db/apply-snapshot.d.ts +18 -0
- package/dist/db/apply-snapshot.d.ts.map +1 -1
- package/dist/db/apply-snapshot.js +41 -16
- package/dist/db/apply-snapshot.js.map +1 -1
- package/dist/db/component-instance-queries.d.ts +79 -19
- package/dist/db/component-instance-queries.d.ts.map +1 -1
- package/dist/db/component-instance-queries.js +266 -83
- package/dist/db/component-instance-queries.js.map +1 -1
- package/dist/db/component-queries.d.ts +1 -16
- package/dist/db/component-queries.d.ts.map +1 -1
- package/dist/db/component-queries.js +7 -56
- package/dist/db/component-queries.js.map +1 -1
- package/dist/db/content-queries.d.ts.map +1 -1
- package/dist/db/content-queries.js +1 -2
- package/dist/db/content-queries.js.map +1 -1
- package/dist/db/extension-queries.d.ts +2 -2
- package/dist/db/feed-queries.d.ts +3 -3
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/layout-queries.d.ts +2 -1
- package/dist/db/layout-queries.d.ts.map +1 -1
- package/dist/db/layout-queries.js +3 -3
- package/dist/db/layout-queries.js.map +1 -1
- package/dist/db/menu-queries.d.ts +69 -5
- package/dist/db/menu-queries.d.ts.map +1 -1
- package/dist/db/menu-queries.js +120 -13
- package/dist/db/menu-queries.js.map +1 -1
- package/dist/db/section-template-queries.d.ts +62 -0
- package/dist/db/section-template-queries.d.ts.map +1 -0
- package/dist/db/section-template-queries.js +178 -0
- package/dist/db/section-template-queries.js.map +1 -0
- package/dist/db/site-plugin-queries.d.ts +2 -2
- package/dist/db/tree-queries.d.ts.map +1 -1
- package/dist/db/tree-queries.js +5 -0
- package/dist/db/tree-queries.js.map +1 -1
- package/dist/db/webhook-queries.d.ts +3 -3
- package/dist/db/workflow-queries.d.ts.map +1 -1
- package/dist/db/workflow-queries.js +5 -20
- package/dist/db/workflow-queries.js.map +1 -1
- package/dist/experiments/runtime.d.ts +21 -3
- package/dist/experiments/runtime.d.ts.map +1 -1
- package/dist/experiments/runtime.js +21 -3
- package/dist/experiments/runtime.js.map +1 -1
- package/dist/layout/component-refs.d.ts +90 -2
- package/dist/layout/component-refs.d.ts.map +1 -1
- package/dist/layout/component-refs.js +293 -16
- package/dist/layout/component-refs.js.map +1 -1
- package/dist/layout/index.d.ts +4 -3
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +3 -2
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/legacy-variant-container.d.ts +123 -0
- package/dist/layout/legacy-variant-container.d.ts.map +1 -0
- package/dist/layout/legacy-variant-container.js +397 -0
- package/dist/layout/legacy-variant-container.js.map +1 -0
- package/dist/layout/module-permissions.d.ts.map +1 -1
- package/dist/layout/module-permissions.js +25 -1
- package/dist/layout/module-permissions.js.map +1 -1
- package/dist/layout/modules-extended.d.ts +28 -1
- package/dist/layout/modules-extended.d.ts.map +1 -1
- package/dist/layout/modules-extended.js +73 -1
- package/dist/layout/modules-extended.js.map +1 -1
- package/dist/layout/modules.d.ts.map +1 -1
- package/dist/layout/modules.js +9 -1
- package/dist/layout/modules.js.map +1 -1
- package/dist/layout/personalization.d.ts +83 -0
- package/dist/layout/personalization.d.ts.map +1 -1
- package/dist/layout/personalization.js +250 -4
- package/dist/layout/personalization.js.map +1 -1
- package/dist/layout/registry.d.ts.map +1 -1
- package/dist/layout/registry.js +20 -0
- package/dist/layout/registry.js.map +1 -1
- package/dist/layout/renderer.d.ts +29 -2
- package/dist/layout/renderer.d.ts.map +1 -1
- package/dist/layout/renderer.js +23 -6
- package/dist/layout/renderer.js.map +1 -1
- package/dist/layout/types.d.ts +17 -0
- package/dist/layout/types.d.ts.map +1 -1
- package/dist/layout/types.js +7 -0
- package/dist/layout/types.js.map +1 -1
- package/dist/media/inline-risk.d.ts +26 -0
- package/dist/media/inline-risk.d.ts.map +1 -0
- package/dist/media/inline-risk.js +142 -0
- package/dist/media/inline-risk.js.map +1 -0
- package/dist/nav/builder.d.ts.map +1 -1
- package/dist/nav/builder.js +15 -3
- package/dist/nav/builder.js.map +1 -1
- package/dist/nav/index.d.ts +1 -1
- package/dist/nav/index.d.ts.map +1 -1
- package/dist/nav/index.js +1 -1
- package/dist/nav/index.js.map +1 -1
- package/dist/nav/menu-resolver.d.ts +11 -0
- package/dist/nav/menu-resolver.d.ts.map +1 -1
- package/dist/nav/menu-resolver.js +49 -9
- package/dist/nav/menu-resolver.js.map +1 -1
- package/dist/nav/paths.d.ts +37 -0
- package/dist/nav/paths.d.ts.map +1 -0
- package/dist/nav/paths.js +48 -0
- package/dist/nav/paths.js.map +1 -0
- package/dist/nav/types.d.ts +6 -0
- package/dist/nav/types.d.ts.map +1 -1
- package/dist/nav/url-resolver.d.ts +1 -5
- package/dist/nav/url-resolver.d.ts.map +1 -1
- package/dist/nav/url-resolver.js +6 -12
- package/dist/nav/url-resolver.js.map +1 -1
- package/dist/schema/base.d.ts +24 -4
- package/dist/schema/base.d.ts.map +1 -1
- package/dist/schema/base.js +17 -4
- package/dist/schema/base.js.map +1 -1
- package/dist/schema/components.d.ts +90 -9
- package/dist/schema/components.d.ts.map +1 -1
- package/dist/schema/components.js +113 -22
- package/dist/schema/components.js.map +1 -1
- package/dist/schema/mysql-tables.d.ts +5758 -48
- package/dist/schema/mysql-tables.d.ts.map +1 -1
- package/dist/schema/mysql-tables.js +620 -46
- package/dist/schema/mysql-tables.js.map +1 -1
- package/dist/scope/kywi-form.d.ts +11 -0
- package/dist/scope/kywi-form.d.ts.map +1 -1
- package/dist/scope/kywi-form.js +11 -1
- package/dist/scope/kywi-form.js.map +1 -1
- package/dist/scope/kywi-wizard-form.d.ts.map +1 -1
- package/dist/scope/kywi-wizard-form.js +76 -2
- package/dist/scope/kywi-wizard-form.js.map +1 -1
- package/dist/scope/sticky-offset.d.ts +34 -13
- package/dist/scope/sticky-offset.d.ts.map +1 -1
- package/dist/scope/sticky-offset.js +236 -43
- package/dist/scope/sticky-offset.js.map +1 -1
- package/dist/site/styles.css +61 -15
- package/dist/versioning/scheduler.d.ts +28 -0
- package/dist/versioning/scheduler.d.ts.map +1 -1
- package/dist/versioning/scheduler.js +50 -3
- package/dist/versioning/scheduler.js.map +1 -1
- package/package.json +7 -2
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import { COOKIE_NAMES } from '../cookies.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { cookieAllowed, readConsentFromCookieHeader } from '../consent.js';
|
|
3
|
+
/**
|
|
4
|
+
* Read the visitor's stored identity — the `kywi_visitor` id and the
|
|
5
|
+
* adapter-pushed `kywi_known` flag.
|
|
6
|
+
*
|
|
7
|
+
* Both are `personalization` cookies, so both are treated as ABSENT unless the
|
|
8
|
+
* visitor consents (kywi-cms#91): a visitor who rejects must stop being
|
|
9
|
+
* recognised, not merely stop accumulating new cookies. An empty `visitorId` is
|
|
10
|
+
* already the "no identity yet" value every caller handles — the request still
|
|
11
|
+
* resolves and renders, anonymously.
|
|
12
|
+
*/
|
|
13
|
+
export function collectIdentity(cookies, gate = {}) {
|
|
14
|
+
const consent = readConsentFromCookieHeader(gate.cookieHeader);
|
|
15
|
+
const mayRead = (name) => cookieAllowed(name, consent, gate);
|
|
16
|
+
const visitorId = (mayRead(COOKIE_NAMES.VISITOR) ? cookies.get(COOKIE_NAMES.VISITOR) : undefined) ?? '';
|
|
17
|
+
const knownRaw = mayRead(COOKIE_NAMES.KNOWN) ? cookies.get(COOKIE_NAMES.KNOWN) : undefined;
|
|
5
18
|
let isKnown = false;
|
|
6
19
|
let maLeadId = null;
|
|
7
20
|
if (knownRaw) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/audiences/collectors/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/audiences/collectors/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,2BAA2B,EAA2B,MAAM,eAAe,CAAA;AAQnG;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA4B,EAC5B,OAA8D,EAAE;IAEhE,MAAM,OAAO,GAAG,2BAA2B,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IAC9D,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;IACpE,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAA;IACvG,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1F,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,IAAI,QAAQ,GAAkB,IAAI,CAAA;IAClC,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAA0B,CAAA;YAC1D,OAAO,GAAG,IAAI,CAAA;YACd,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAA;QAClC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;AACzC,CAAC"}
|
|
@@ -2,7 +2,17 @@ export { collectUtm, type UtmSignals } from './utm.js';
|
|
|
2
2
|
export { collectReferrer, classifyReferrer, type ReferrerSignals, type ReferrerSourceType } from './referrer.js';
|
|
3
3
|
export { collectIdentity, type IdentitySignals } from './identity.js';
|
|
4
4
|
export { collectOptOut } from './opt-out.js';
|
|
5
|
-
export { collectPinnedAudience } from './pinned-audience.js';
|
|
5
|
+
export { collectPinnedAudience, parseAudiencePin, buildAudiencePinValue, type AudiencePin, } from './pinned-audience.js';
|
|
6
6
|
import type { VisitorSignals } from '../types.js';
|
|
7
|
-
|
|
7
|
+
import type { ConsentGateOptions } from '../consent.js';
|
|
8
|
+
/**
|
|
9
|
+
* Collect every server-resolvable signal off the request.
|
|
10
|
+
*
|
|
11
|
+
* The personalization-category cookies (`kywi_utm`, `kywi_visitor`,
|
|
12
|
+
* `kywi_known`) are read only for a consenting visitor — pass `requireConsent:
|
|
13
|
+
* false` to turn that off for a site whose consent lives in external tooling
|
|
14
|
+
* (kywi-cms#91). Un-stored signals (this URL's `utm_*` params, the referrer) are
|
|
15
|
+
* always collected: they are the request itself, not tracking carried into it.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runServerCollectors(req: Request, gate?: ConsentGateOptions): Partial<VisitorSignals>;
|
|
8
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/audiences/collectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAChH,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/audiences/collectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAChH,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAMjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEvD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EACZ,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAczB"}
|
|
@@ -2,17 +2,28 @@ export { collectUtm } from './utm.js';
|
|
|
2
2
|
export { collectReferrer, classifyReferrer } from './referrer.js';
|
|
3
3
|
export { collectIdentity } from './identity.js';
|
|
4
4
|
export { collectOptOut } from './opt-out.js';
|
|
5
|
-
export { collectPinnedAudience } from './pinned-audience.js';
|
|
5
|
+
export { collectPinnedAudience, parseAudiencePin, buildAudiencePinValue, } from './pinned-audience.js';
|
|
6
6
|
import { parseCookies } from '../cookies.js';
|
|
7
7
|
import { collectUtm } from './utm.js';
|
|
8
8
|
import { collectReferrer } from './referrer.js';
|
|
9
9
|
import { collectIdentity } from './identity.js';
|
|
10
10
|
import { collectOptOut } from './opt-out.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Collect every server-resolvable signal off the request.
|
|
13
|
+
*
|
|
14
|
+
* The personalization-category cookies (`kywi_utm`, `kywi_visitor`,
|
|
15
|
+
* `kywi_known`) are read only for a consenting visitor — pass `requireConsent:
|
|
16
|
+
* false` to turn that off for a site whose consent lives in external tooling
|
|
17
|
+
* (kywi-cms#91). Un-stored signals (this URL's `utm_*` params, the referrer) are
|
|
18
|
+
* always collected: they are the request itself, not tracking carried into it.
|
|
19
|
+
*/
|
|
20
|
+
export function runServerCollectors(req, gate = {}) {
|
|
21
|
+
const cookieHeader = req.headers.get('cookie');
|
|
22
|
+
const cookies = parseCookies(cookieHeader ?? '');
|
|
23
|
+
const readGate = { ...gate, cookieHeader };
|
|
24
|
+
const utm = collectUtm(req, cookies, readGate);
|
|
14
25
|
const referrer = collectReferrer(req, utm.medium);
|
|
15
|
-
const identity = collectIdentity(cookies);
|
|
26
|
+
const identity = collectIdentity(cookies, readGate);
|
|
16
27
|
const isOptedOut = collectOptOut(cookies);
|
|
17
28
|
return {
|
|
18
29
|
utm,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/audiences/collectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAmB,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAiD,MAAM,eAAe,CAAA;AAChH,OAAO,EAAE,eAAe,EAAwB,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/audiences/collectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAmB,MAAM,UAAU,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAiD,MAAM,eAAe,CAAA;AAChH,OAAO,EAAE,eAAe,EAAwB,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,GAEtB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAG5C;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAY,EACZ,OAA2B,EAAE;IAE7B,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC9C,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,IAAI,EAAE,CAAC,CAAA;IAChD,MAAM,QAAQ,GAAG,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,CAAA;IAC1C,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC9C,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACjD,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IACnD,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;IACzC,OAAO;QACL,GAAG;QACH,QAAQ;QACR,QAAQ;QACR,IAAI,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE;KACtF,CAAA;AACH,CAAC"}
|
|
@@ -1,4 +1,27 @@
|
|
|
1
|
+
import { type ConsentGateOptions } from '../consent.js';
|
|
1
2
|
import type { Audience } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The `kywi_audience` cookie's value, which records HOW the pin was made.
|
|
5
|
+
*
|
|
6
|
+
* Two writes share this cookie and they carry different consent weight
|
|
7
|
+
* (kywi-cms#91): the runtime automatically remembering what it resolved is
|
|
8
|
+
* `personalization` tracking, while an audience the visitor picked by hand in
|
|
9
|
+
* the transparency panel is an `essential` preference. The cookie has to say
|
|
10
|
+
* which, or the read side cannot apply the right rule and a hand-picked audience
|
|
11
|
+
* would be stored and then silently ignored.
|
|
12
|
+
*/
|
|
13
|
+
export interface AudiencePin {
|
|
14
|
+
id: string;
|
|
15
|
+
/** The visitor chose this deliberately, so it is an `essential` preference. */
|
|
16
|
+
viaSwitcher: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Encode a pin for the `kywi_audience` cookie. */
|
|
19
|
+
export declare function buildAudiencePinValue(id: string, viaSwitcher: boolean): string;
|
|
20
|
+
/**
|
|
21
|
+
* Decode a `kywi_audience` cookie value. A bare id — every cookie written before
|
|
22
|
+
* kywi-cms#91, and every boot pin since — reads as a non-switcher pin.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseAudiencePin(raw: string | undefined | null): AudiencePin | null;
|
|
2
25
|
/**
|
|
3
26
|
* Read the client-pinned audience (`kywi_audience` cookie).
|
|
4
27
|
*
|
|
@@ -11,7 +34,10 @@ import type { Audience } from '../types.js';
|
|
|
11
34
|
* and deletes it), so the id is untrusted input: it is only honoured when it
|
|
12
35
|
* names a *currently-active* audience for this render. A stale, forged, or
|
|
13
36
|
* archived id is treated as absent — the caller falls through to signal-derived
|
|
14
|
-
* resolution and the render never errors.
|
|
37
|
+
* resolution and the render never errors. So is a pin the visitor has not
|
|
38
|
+
* consented to being remembered by.
|
|
15
39
|
*/
|
|
16
|
-
export declare function collectPinnedAudience(cookies: Map<string, string>, activeAudiences: Audience[]
|
|
40
|
+
export declare function collectPinnedAudience(cookies: Map<string, string>, activeAudiences: Audience[], gate?: ConsentGateOptions & {
|
|
41
|
+
cookieHeader?: string | null;
|
|
42
|
+
}): string | null;
|
|
17
43
|
//# sourceMappingURL=pinned-audience.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pinned-audience.d.ts","sourceRoot":"","sources":["../../../src/audiences/collectors/pinned-audience.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C
|
|
1
|
+
{"version":3,"file":"pinned-audience.d.ts","sourceRoot":"","sources":["../../../src/audiences/collectors/pinned-audience.ts"],"names":[],"mappings":"AACA,OAAO,EAA8C,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACnG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE3C;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,+EAA+E;IAC/E,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,mDAAmD;AACnD,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,MAAM,CAK9E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAOnF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,eAAe,EAAE,QAAQ,EAAE,EAC3B,IAAI,GAAE,kBAAkB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAC/D,MAAM,GAAG,IAAI,CAYf"}
|
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
import { COOKIE_NAMES } from '../cookies.js';
|
|
2
|
+
import { cookieAllowedByHeader, SWITCHER_PIN_PREFIX } from '../consent.js';
|
|
3
|
+
/** Encode a pin for the `kywi_audience` cookie. */
|
|
4
|
+
export function buildAudiencePinValue(id, viaSwitcher) {
|
|
5
|
+
// A plain id stays a plain id: the un-prefixed form is what every version
|
|
6
|
+
// before kywi-cms#91 wrote, and keeping it means an existing cookie survives
|
|
7
|
+
// the upgrade reading exactly as it always did (as a boot pin).
|
|
8
|
+
return viaSwitcher ? `${SWITCHER_PIN_PREFIX}${id}` : id;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Decode a `kywi_audience` cookie value. A bare id — every cookie written before
|
|
12
|
+
* kywi-cms#91, and every boot pin since — reads as a non-switcher pin.
|
|
13
|
+
*/
|
|
14
|
+
export function parseAudiencePin(raw) {
|
|
15
|
+
if (!raw)
|
|
16
|
+
return null;
|
|
17
|
+
if (raw.startsWith(SWITCHER_PIN_PREFIX)) {
|
|
18
|
+
const id = raw.slice(SWITCHER_PIN_PREFIX.length);
|
|
19
|
+
return id ? { id, viaSwitcher: true } : null;
|
|
20
|
+
}
|
|
21
|
+
return { id: raw, viaSwitcher: false };
|
|
22
|
+
}
|
|
2
23
|
/**
|
|
3
24
|
* Read the client-pinned audience (`kywi_audience` cookie).
|
|
4
25
|
*
|
|
@@ -11,12 +32,21 @@ import { COOKIE_NAMES } from '../cookies.js';
|
|
|
11
32
|
* and deletes it), so the id is untrusted input: it is only honoured when it
|
|
12
33
|
* names a *currently-active* audience for this render. A stale, forged, or
|
|
13
34
|
* archived id is treated as absent — the caller falls through to signal-derived
|
|
14
|
-
* resolution and the render never errors.
|
|
35
|
+
* resolution and the render never errors. So is a pin the visitor has not
|
|
36
|
+
* consented to being remembered by.
|
|
15
37
|
*/
|
|
16
|
-
export function collectPinnedAudience(cookies, activeAudiences) {
|
|
17
|
-
const
|
|
18
|
-
if (!
|
|
38
|
+
export function collectPinnedAudience(cookies, activeAudiences, gate = {}) {
|
|
39
|
+
const pin = parseAudiencePin(cookies.get(COOKIE_NAMES.AUDIENCE));
|
|
40
|
+
if (!pin)
|
|
41
|
+
return null;
|
|
42
|
+
// An automatic pin is `personalization`: a visitor who rejects stops being
|
|
43
|
+
// resolved from tracking they no longer consent to. A pin they set by hand is
|
|
44
|
+
// `essential` and is honoured either way — refusing to act on the switcher
|
|
45
|
+
// they just used would make the panel lie about what its buttons do
|
|
46
|
+
// (kywi-cms#91).
|
|
47
|
+
if (!pin.viaSwitcher && !cookieAllowedByHeader(COOKIE_NAMES.AUDIENCE, gate.cookieHeader, gate)) {
|
|
19
48
|
return null;
|
|
20
|
-
|
|
49
|
+
}
|
|
50
|
+
return activeAudiences.some((a) => a.id === pin.id) ? pin.id : null;
|
|
21
51
|
}
|
|
22
52
|
//# sourceMappingURL=pinned-audience.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pinned-audience.js","sourceRoot":"","sources":["../../../src/audiences/collectors/pinned-audience.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"pinned-audience.js","sourceRoot":"","sources":["../../../src/audiences/collectors/pinned-audience.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAA2B,MAAM,eAAe,CAAA;AAmBnG,mDAAmD;AACnD,MAAM,UAAU,qBAAqB,CAAC,EAAU,EAAE,WAAoB;IACpE,0EAA0E;IAC1E,6EAA6E;IAC7E,gEAAgE;IAChE,OAAO,WAAW,CAAC,CAAC,CAAC,GAAG,mBAAmB,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAA8B;IAC7D,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAA;IACrB,IAAI,GAAG,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACxC,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAChD,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAC9C,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,CAAA;AACxC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAA4B,EAC5B,eAA2B,EAC3B,OAA8D,EAAE;IAEhE,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAA;IAChE,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAA;IACrB,2EAA2E;IAC3E,8EAA8E;IAC9E,2EAA2E;IAC3E,oEAAoE;IACpE,iBAAiB;IACjB,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,qBAAqB,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC;QAC/F,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACrE,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ConsentGateOptions } from '../consent.js';
|
|
1
2
|
export interface UtmSignals {
|
|
2
3
|
source: string | null;
|
|
3
4
|
medium: string | null;
|
|
@@ -5,5 +6,18 @@ export interface UtmSignals {
|
|
|
5
6
|
term: string | null;
|
|
6
7
|
content: string | null;
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the visitor's UTM attribution: this request's `utm_*` query params,
|
|
11
|
+
* falling back to the persisted `kywi_utm` cookie.
|
|
12
|
+
*
|
|
13
|
+
* The cookie fallback is IGNORED unless the visitor consents to personalization
|
|
14
|
+
* (kywi-cms#91). Blocking the write alone would not be enough — a visitor who
|
|
15
|
+
* accepted last month and rejects today still carries the cookie, and reading it
|
|
16
|
+
* would keep them in a campaign audience they just opted out of. The URL's own
|
|
17
|
+
* `utm_*` params are always honoured: they are this request's content, not
|
|
18
|
+
* stored tracking.
|
|
19
|
+
*/
|
|
20
|
+
export declare function collectUtm(req: Request, cookies: Map<string, string>, gate?: ConsentGateOptions & {
|
|
21
|
+
cookieHeader?: string | null;
|
|
22
|
+
}): UtmSignals;
|
|
9
23
|
//# sourceMappingURL=utm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utm.d.ts","sourceRoot":"","sources":["../../../src/audiences/collectors/utm.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utm.d.ts","sourceRoot":"","sources":["../../../src/audiences/collectors/utm.ts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAE9E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,IAAI,GAAE,kBAAkB,GAAG;IAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAC/D,UAAU,CAgBZ"}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { COOKIE_NAMES } from '../cookies.js';
|
|
2
|
-
|
|
2
|
+
import { cookieAllowedByHeader } from '../consent.js';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the visitor's UTM attribution: this request's `utm_*` query params,
|
|
5
|
+
* falling back to the persisted `kywi_utm` cookie.
|
|
6
|
+
*
|
|
7
|
+
* The cookie fallback is IGNORED unless the visitor consents to personalization
|
|
8
|
+
* (kywi-cms#91). Blocking the write alone would not be enough — a visitor who
|
|
9
|
+
* accepted last month and rejects today still carries the cookie, and reading it
|
|
10
|
+
* would keep them in a campaign audience they just opted out of. The URL's own
|
|
11
|
+
* `utm_*` params are always honoured: they are this request's content, not
|
|
12
|
+
* stored tracking.
|
|
13
|
+
*/
|
|
14
|
+
export function collectUtm(req, cookies, gate = {}) {
|
|
3
15
|
const url = new URL(req.url);
|
|
4
16
|
let cookieUtm = {};
|
|
5
|
-
const raw =
|
|
17
|
+
const raw = cookieAllowedByHeader(COOKIE_NAMES.UTM, gate.cookieHeader ?? req.headers.get('cookie'), gate)
|
|
18
|
+
? cookies.get(COOKIE_NAMES.UTM)
|
|
19
|
+
: undefined;
|
|
6
20
|
if (raw) {
|
|
7
21
|
try {
|
|
8
22
|
cookieUtm = JSON.parse(raw);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utm.js","sourceRoot":"","sources":["../../../src/audiences/collectors/utm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"utm.js","sourceRoot":"","sources":["../../../src/audiences/collectors/utm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,qBAAqB,EAA2B,MAAM,eAAe,CAAA;AAU9E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CACxB,GAAY,EACZ,OAA4B,EAC5B,OAA8D,EAAE;IAEhE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,IAAI,SAAS,GAAwB,EAAE,CAAA;IACvC,MAAM,GAAG,GAAG,qBAAqB,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,YAAY,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;QACvG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC;QAC/B,CAAC,CAAC,SAAS,CAAA;IACb,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,CAAC;YAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IACnF,CAAC;IACD,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,SAAS,CAAC,MAAM,IAAI,IAAI;QACtE,MAAM,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,SAAS,CAAC,MAAM,IAAI,IAAI;QACtE,QAAQ,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,SAAS,CAAC,QAAQ,IAAI,IAAI;QAC5E,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,IAAI,IAAI,IAAI;QAChE,OAAO,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,SAAS,CAAC,OAAO,IAAI,IAAI;KAC1E,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve `theme.personalization.requireConsent` from a `KywiConfig`
|
|
3
|
+
* (kywi-cms#91).
|
|
4
|
+
*
|
|
5
|
+
* Kept out of `./consent.ts` because that module must import nothing at all —
|
|
6
|
+
* it is pulled into Next.js edge middleware. This file's only import is a TYPE,
|
|
7
|
+
* which erases at compile time, but it lives next door rather than inside the
|
|
8
|
+
* gate so the edge entry stays obviously dependency-free.
|
|
9
|
+
*/
|
|
10
|
+
import type { KywiConfig } from '../config/types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Does this site require consent before personalization cookies are written?
|
|
13
|
+
*
|
|
14
|
+
* **True unless a theme explicitly opts out.** The flag lives on the theme, so
|
|
15
|
+
* it resolves the same way `clientRuntimeEnabled` / `transparencyNoticeEnabled`
|
|
16
|
+
* do in the reference app: the named site's theme, falling back to the first
|
|
17
|
+
* site's theme and then the first theme declared. A site with no theme at all
|
|
18
|
+
* requires consent — the safe answer is the default answer.
|
|
19
|
+
*/
|
|
20
|
+
export declare function personalizationRequiresConsent(config: KywiConfig, siteId?: string): boolean;
|
|
21
|
+
//# sourceMappingURL=consent-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent-config.d.ts","sourceRoot":"","sources":["../../src/audiences/consent-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAI3F"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does this site require consent before personalization cookies are written?
|
|
3
|
+
*
|
|
4
|
+
* **True unless a theme explicitly opts out.** The flag lives on the theme, so
|
|
5
|
+
* it resolves the same way `clientRuntimeEnabled` / `transparencyNoticeEnabled`
|
|
6
|
+
* do in the reference app: the named site's theme, falling back to the first
|
|
7
|
+
* site's theme and then the first theme declared. A site with no theme at all
|
|
8
|
+
* requires consent — the safe answer is the default answer.
|
|
9
|
+
*/
|
|
10
|
+
export function personalizationRequiresConsent(config, siteId) {
|
|
11
|
+
const site = (siteId ? config.sites.find((s) => s.id === siteId) : undefined) ?? config.sites[0];
|
|
12
|
+
const theme = config.themes.find((t) => t.name === site?.theme) ?? config.themes[0];
|
|
13
|
+
return theme?.personalization?.requireConsent !== false;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=consent-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent-config.js","sourceRoot":"","sources":["../../src/audiences/consent-config.ts"],"names":[],"mappings":"AAWA;;;;;;;;GAQG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAAkB,EAAE,MAAe;IAChF,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAChG,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACnF,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,KAAK,KAAK,CAAA;AACzD,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { KywiDb } from '../db/client.js';
|
|
2
|
+
/** The env var mirroring `theme.personalization.requireConsent` for edge middleware. */
|
|
3
|
+
export declare const REQUIRE_CONSENT_ENV = "KYWI_REQUIRE_CONSENT";
|
|
4
|
+
/** How `middleware.ts` reads the mirror: anything but the literal "false" is true. */
|
|
5
|
+
export declare function requireConsentFromEnv(env?: Record<string, string | undefined>): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Fail startup when the config flag and its edge mirror disagree.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately a throw and not a warning: the two halves of one setting pointing
|
|
10
|
+
* opposite ways is never intentional, and the resulting behaviour (cookies
|
|
11
|
+
* written by the edge that the API then declines to read, or vice versa) is
|
|
12
|
+
* exactly the kind of bug that survives to production because nothing is
|
|
13
|
+
* visibly broken.
|
|
14
|
+
*/
|
|
15
|
+
export declare function assertConsentEnvAgreement(requireConsentFromConfig: boolean, env?: Record<string, string | undefined>): void;
|
|
16
|
+
/**
|
|
17
|
+
* Build the once-only "consent required, but nothing asks for it" check.
|
|
18
|
+
*
|
|
19
|
+
* Returns a function safe to call on every request: it runs at most once, never
|
|
20
|
+
* awaits (the first request does not pay for it), and swallows every error. A
|
|
21
|
+
* warning that could break a page, or add latency to the hot path, would not be
|
|
22
|
+
* worth having.
|
|
23
|
+
*
|
|
24
|
+
* The check is a `::text LIKE` prefilter — the same shape
|
|
25
|
+
* `checkAudienceDeletionSafety` uses — looking for anything that mentions the
|
|
26
|
+
* module type at all. Over-matching is fine here: a false negative (staying
|
|
27
|
+
* quiet) is the safe direction for an advisory warning.
|
|
28
|
+
*
|
|
29
|
+
* It reads BOTH places a module can be placed: `kywi_content.layout` and
|
|
30
|
+
* `kywi_section_templates.definition`. A banner composed from a blueprint is a
|
|
31
|
+
* banner, and scanning pages alone told a site that builds every page that way
|
|
32
|
+
* that consent could never be granted — while the banner was on screen.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createConsentBannerCheck(deps: {
|
|
35
|
+
db: KywiDb;
|
|
36
|
+
requireConsent: boolean;
|
|
37
|
+
warn?: (message: string) => void;
|
|
38
|
+
}): () => void;
|
|
39
|
+
//# sourceMappingURL=consent-startup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent-startup.d.ts","sourceRoot":"","sources":["../../src/audiences/consent-startup.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C,wFAAwF;AACxF,eAAO,MAAM,mBAAmB,yBAAyB,CAAA;AAEzD,sFAAsF;AACtF,wBAAgB,qBAAqB,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,OAAO,CAEpG;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,wBAAwB,EAAE,OAAO,EACjC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,IAAI,CAcN;AASD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,EAAE,EAAE,MAAM,CAAA;IACV,cAAc,EAAE,OAAO,CAAA;IACvB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC,GAAG,MAAM,IAAI,CA8Bb"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup checks for the cookie-consent gate (kywi-cms#91).
|
|
3
|
+
*
|
|
4
|
+
* Two failure modes are invisible at runtime and expensive to discover later:
|
|
5
|
+
*
|
|
6
|
+
* 1. The config flag and its edge mirror disagree. `middleware.ts` runs on the
|
|
7
|
+
* edge and cannot read `kywi.config.ts`, so `requireConsent` is mirrored as
|
|
8
|
+
* `KYWI_REQUIRE_CONSENT`. If the two drift, the middleware and the API
|
|
9
|
+
* disagree about whether a visitor may be tracked — one writes
|
|
10
|
+
* `kywi_visitor`, the other refuses to read it — and nothing anywhere says
|
|
11
|
+
* so. That is a misconfiguration, and it fails the deploy.
|
|
12
|
+
*
|
|
13
|
+
* 2. Consent is required and no page offers a way to give it. Every
|
|
14
|
+
* personalization cookie is then permanently suppressed: audiences,
|
|
15
|
+
* experiments and UTM attribution quietly do nothing, and the site looks
|
|
16
|
+
* broken rather than gated. That is a WARNING, not an error — a site may
|
|
17
|
+
* legitimately have no personalization at all — but it must be said out
|
|
18
|
+
* loud, once, rather than left for someone to debug.
|
|
19
|
+
*/
|
|
20
|
+
import { sql } from 'drizzle-orm';
|
|
21
|
+
/** The env var mirroring `theme.personalization.requireConsent` for edge middleware. */
|
|
22
|
+
export const REQUIRE_CONSENT_ENV = 'KYWI_REQUIRE_CONSENT';
|
|
23
|
+
/** How `middleware.ts` reads the mirror: anything but the literal "false" is true. */
|
|
24
|
+
export function requireConsentFromEnv(env = process.env) {
|
|
25
|
+
return env[REQUIRE_CONSENT_ENV] !== 'false';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Fail startup when the config flag and its edge mirror disagree.
|
|
29
|
+
*
|
|
30
|
+
* Deliberately a throw and not a warning: the two halves of one setting pointing
|
|
31
|
+
* opposite ways is never intentional, and the resulting behaviour (cookies
|
|
32
|
+
* written by the edge that the API then declines to read, or vice versa) is
|
|
33
|
+
* exactly the kind of bug that survives to production because nothing is
|
|
34
|
+
* visibly broken.
|
|
35
|
+
*/
|
|
36
|
+
export function assertConsentEnvAgreement(requireConsentFromConfig, env = process.env) {
|
|
37
|
+
const fromEnv = requireConsentFromEnv(env);
|
|
38
|
+
if (fromEnv === requireConsentFromConfig)
|
|
39
|
+
return;
|
|
40
|
+
const raw = env[REQUIRE_CONSENT_ENV];
|
|
41
|
+
throw new Error(`Cookie-consent misconfiguration: theme.personalization.requireConsent is ` +
|
|
42
|
+
`${requireConsentFromConfig} but ${REQUIRE_CONSENT_ENV} is ` +
|
|
43
|
+
`${raw === undefined ? 'unset (which means true)' : JSON.stringify(raw)}.\n` +
|
|
44
|
+
` Next.js edge middleware cannot read kywi.config.ts, so it mirrors that flag ` +
|
|
45
|
+
`through ${REQUIRE_CONSENT_ENV}. While they disagree, the middleware and the API ` +
|
|
46
|
+
`disagree about whether a visitor may be tracked.\n` +
|
|
47
|
+
` Set both, or neither: ${REQUIRE_CONSENT_ENV}=false alongside ` +
|
|
48
|
+
`personalization: { requireConsent: false }, or remove both.`);
|
|
49
|
+
}
|
|
50
|
+
const NO_BANNER_WARNING = '[kywi] Cookie consent is required (theme.personalization.requireConsent) but no ' +
|
|
51
|
+
'page or layout places the `cookieConsent` module, so no visitor can ever grant it. ' +
|
|
52
|
+
'Every personalization cookie stays suppressed: audiences, A/B bucketing and UTM ' +
|
|
53
|
+
'attribution will resolve to default content for everyone. Place the module, or set ' +
|
|
54
|
+
'personalization: { requireConsent: false } if consent is collected by external tooling.';
|
|
55
|
+
/**
|
|
56
|
+
* Build the once-only "consent required, but nothing asks for it" check.
|
|
57
|
+
*
|
|
58
|
+
* Returns a function safe to call on every request: it runs at most once, never
|
|
59
|
+
* awaits (the first request does not pay for it), and swallows every error. A
|
|
60
|
+
* warning that could break a page, or add latency to the hot path, would not be
|
|
61
|
+
* worth having.
|
|
62
|
+
*
|
|
63
|
+
* The check is a `::text LIKE` prefilter — the same shape
|
|
64
|
+
* `checkAudienceDeletionSafety` uses — looking for anything that mentions the
|
|
65
|
+
* module type at all. Over-matching is fine here: a false negative (staying
|
|
66
|
+
* quiet) is the safe direction for an advisory warning.
|
|
67
|
+
*
|
|
68
|
+
* It reads BOTH places a module can be placed: `kywi_content.layout` and
|
|
69
|
+
* `kywi_section_templates.definition`. A banner composed from a blueprint is a
|
|
70
|
+
* banner, and scanning pages alone told a site that builds every page that way
|
|
71
|
+
* that consent could never be granted — while the banner was on screen.
|
|
72
|
+
*/
|
|
73
|
+
export function createConsentBannerCheck(deps) {
|
|
74
|
+
const warn = deps.warn ?? ((m) => console.warn(m));
|
|
75
|
+
let started = false;
|
|
76
|
+
return () => {
|
|
77
|
+
if (started || !deps.requireConsent)
|
|
78
|
+
return;
|
|
79
|
+
started = true;
|
|
80
|
+
void (async () => {
|
|
81
|
+
try {
|
|
82
|
+
const rows = await deps.db.execute(sql `
|
|
83
|
+
SELECT 1 AS found
|
|
84
|
+
FROM kywi_content
|
|
85
|
+
WHERE layout IS NOT NULL
|
|
86
|
+
AND layout::text LIKE ${'%"cookieConsent"%'}
|
|
87
|
+
UNION ALL
|
|
88
|
+
SELECT 1 AS found
|
|
89
|
+
FROM kywi_section_templates
|
|
90
|
+
WHERE definition IS NOT NULL
|
|
91
|
+
AND definition::text LIKE ${'%"cookieConsent"%'}
|
|
92
|
+
LIMIT 1
|
|
93
|
+
`);
|
|
94
|
+
if (rows.length === 0)
|
|
95
|
+
warn(NO_BANNER_WARNING);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// No content table yet (a fresh install mid-migration), a dialect that
|
|
99
|
+
// cannot cast, a transient connection failure — none of that is worth
|
|
100
|
+
// failing or logging a request over. Silence is the safe direction.
|
|
101
|
+
}
|
|
102
|
+
})();
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=consent-startup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent-startup.js","sourceRoot":"","sources":["../../src/audiences/consent-startup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAGjC,wFAAwF;AACxF,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAA;AAEzD,sFAAsF;AACtF,MAAM,UAAU,qBAAqB,CAAC,MAA0C,OAAO,CAAC,GAAG;IACzF,OAAO,GAAG,CAAC,mBAAmB,CAAC,KAAK,OAAO,CAAA;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CACvC,wBAAiC,EACjC,MAA0C,OAAO,CAAC,GAAG;IAErD,MAAM,OAAO,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAA;IAC1C,IAAI,OAAO,KAAK,wBAAwB;QAAE,OAAM;IAChD,MAAM,GAAG,GAAG,GAAG,CAAC,mBAAmB,CAAC,CAAA;IACpC,MAAM,IAAI,KAAK,CACb,2EAA2E;QACzE,GAAG,wBAAwB,QAAQ,mBAAmB,MAAM;QAC5D,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK;QAC5E,gFAAgF;QAChF,WAAW,mBAAmB,oDAAoD;QAClF,oDAAoD;QACpD,2BAA2B,mBAAmB,mBAAmB;QACjE,6DAA6D,CAChE,CAAA;AACH,CAAC;AAED,MAAM,iBAAiB,GACrB,kFAAkF;IAClF,qFAAqF;IACrF,kFAAkF;IAClF,qFAAqF;IACrF,yFAAyF,CAAA;AAE3F;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAIxC;IACC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1D,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,OAAO,GAAG,EAAE;QACV,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,cAAc;YAAE,OAAM;QAC3C,OAAO,GAAG,IAAI,CAAA;QACd,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAChC,GAAG,CAAA;;;;sCAIyB,mBAAmB;;;;;0CAKf,mBAAmB;;WAElD,CACF,CAAA;gBACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;oBAAE,IAAI,CAAC,iBAAiB,CAAC,CAAA;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,uEAAuE;gBACvE,sEAAsE;gBACtE,oEAAoE;YACtE,CAAC;QACH,CAAC,CAAC,EAAE,CAAA;IACN,CAAC,CAAA;AACH,CAAC"}
|