@cogenta/cli 0.2.0 → 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.
Files changed (62) hide show
  1. package/dist/admin-assets/assets/index-Buwdj1V2.js +71 -0
  2. package/dist/admin-assets/assets/index-Csef0SiA.css +1 -0
  3. package/dist/admin-assets/index.html +2 -2
  4. package/dist/commands/assistant.d.ts +65 -0
  5. package/dist/commands/assistant.d.ts.map +1 -0
  6. package/dist/commands/assistant.js +207 -0
  7. package/dist/commands/assistant.js.map +1 -0
  8. package/dist/commands/content-webhooks.d.ts +41 -0
  9. package/dist/commands/content-webhooks.d.ts.map +1 -0
  10. package/dist/commands/content-webhooks.js +61 -0
  11. package/dist/commands/content-webhooks.js.map +1 -0
  12. package/dist/commands/http-security.d.ts +39 -0
  13. package/dist/commands/http-security.d.ts.map +1 -0
  14. package/dist/commands/http-security.js +153 -0
  15. package/dist/commands/http-security.js.map +1 -0
  16. package/dist/commands/links.d.ts +24 -0
  17. package/dist/commands/links.d.ts.map +1 -0
  18. package/dist/commands/links.js +109 -0
  19. package/dist/commands/links.js.map +1 -0
  20. package/dist/commands/media-images.d.ts +67 -0
  21. package/dist/commands/media-images.d.ts.map +1 -0
  22. package/dist/commands/media-images.js +107 -0
  23. package/dist/commands/media-images.js.map +1 -0
  24. package/dist/commands/search-page.d.ts +40 -0
  25. package/dist/commands/search-page.d.ts.map +1 -0
  26. package/dist/commands/search-page.js +104 -0
  27. package/dist/commands/search-page.js.map +1 -0
  28. package/dist/commands/security-alerts.d.ts +24 -0
  29. package/dist/commands/security-alerts.d.ts.map +1 -0
  30. package/dist/commands/security-alerts.js +82 -0
  31. package/dist/commands/security-alerts.js.map +1 -0
  32. package/dist/commands/seo.d.ts +88 -0
  33. package/dist/commands/seo.d.ts.map +1 -0
  34. package/dist/commands/seo.js +155 -0
  35. package/dist/commands/seo.js.map +1 -0
  36. package/dist/commands/serve.d.ts +87 -4
  37. package/dist/commands/serve.d.ts.map +1 -1
  38. package/dist/commands/serve.js +740 -40
  39. package/dist/commands/serve.js.map +1 -1
  40. package/dist/commands/site-plan.d.ts +86 -0
  41. package/dist/commands/site-plan.d.ts.map +1 -0
  42. package/dist/commands/site-plan.js +235 -0
  43. package/dist/commands/site-plan.js.map +1 -0
  44. package/dist/commands/theme-css.d.ts +54 -0
  45. package/dist/commands/theme-css.d.ts.map +1 -0
  46. package/dist/commands/theme-css.js +121 -0
  47. package/dist/commands/theme-css.js.map +1 -0
  48. package/dist/commands/theme-render.d.ts +78 -4
  49. package/dist/commands/theme-render.d.ts.map +1 -1
  50. package/dist/commands/theme-render.js +170 -16
  51. package/dist/commands/theme-render.js.map +1 -1
  52. package/dist/commands/users.d.ts +7 -1
  53. package/dist/commands/users.d.ts.map +1 -1
  54. package/dist/commands/users.js +159 -15
  55. package/dist/commands/users.js.map +1 -1
  56. package/dist/index.d.ts +2 -0
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +31 -0
  59. package/dist/index.js.map +1 -1
  60. package/package.json +12 -10
  61. package/dist/admin-assets/assets/index-21ZcDkDC.css +0 -1
  62. package/dist/admin-assets/assets/index-CKLmd_Fi.js +0 -23
@@ -0,0 +1 @@
1
+ .collection-list__toolbar{align-items:center;gap:var(--space-3);margin-bottom:var(--space-4);display:flex}.collection-list__toolbar select{padding:var(--space-1) var(--space-2);border:1px solid var(--color-border);border-radius:var(--radius);background:var(--color-bg);color:var(--color-text)}table{border-collapse:collapse;width:100%}th,td{text-align:left;padding:var(--space-2) var(--space-3);border-bottom:1px solid var(--color-border)}th button{font:inherit;cursor:pointer;color:var(--color-text);background:0 0;border:none;padding:0;font-weight:600}.collection-list__pagination{gap:var(--space-2);margin-top:var(--space-4);display:flex}.collection-list__pagination button{padding:var(--space-1) var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius);background:var(--color-bg);color:var(--color-text);cursor:pointer}.collection-list__pagination button:disabled{opacity:.5;cursor:not-allowed}.field{gap:var(--space-1);margin-bottom:var(--space-4);flex-direction:column;display:flex}.field label{color:var(--color-text);font-size:.875rem;font-weight:600}.field input[type=text],.field input[type=number],.field input[type=date],.field input[type=datetime-local],.field select,.field textarea{padding:var(--space-2) var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius);background:var(--color-bg);color:var(--color-text);font:inherit}.field textarea{min-height:6rem;font-family:ui-monospace,monospace;font-size:.875rem}.field__required{color:var(--color-danger)}.field__help{color:var(--color-text-muted);margin:0;font-size:.8125rem}.field__error{color:var(--color-danger);margin:0;font-size:.8125rem}.field__placeholder{color:var(--color-text-muted);margin:0;font-size:.875rem;font-style:italic}.field--boolean label{align-items:center;gap:var(--space-2);font-weight:400;display:flex}.field__color{align-items:center;gap:var(--space-2);display:flex}.field__geo{gap:var(--space-1) var(--space-2);grid-template-columns:auto 1fr;align-items:center;max-width:20rem;display:grid}.field__geo label{font-weight:400}.media-grid{grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:.75rem;margin:1rem 0;padding:0;list-style:none;display:grid}.media-grid__item{border:1px solid var(--color-border,#ccc);cursor:pointer;background:0 0;border-radius:4px;flex-direction:column;align-items:center;gap:.25rem;width:100%;padding:.5rem;display:flex}.media-grid__filename{text-overflow:ellipsis;white-space:nowrap;max-width:100%;font-size:.8rem;overflow:hidden}.media-thumbnail{aspect-ratio:1;object-fit:cover;background:var(--color-surface-muted,#eee);width:100%}.media-thumbnail--placeholder,.media-thumbnail--loading{aspect-ratio:1;background:var(--color-surface-muted,#eee);width:100%;display:block}.focal-point-editor__frame{max-width:100%;display:inline-block;position:relative}.focal-point-editor__image{cursor:crosshair;max-width:100%}.media-field__selected{align-items:center;gap:.5rem;display:flex}.media-field__selected .media-thumbnail{aspect-ratio:1;width:60px}.media-field__actions{gap:.5rem;margin-top:.25rem;display:flex}.media-field__picker{grid-template-columns:repeat(auto-fill,minmax(80px,1fr));gap:.5rem;max-height:300px;margin:.5rem 0 0;padding:0;list-style:none;display:grid;overflow-y:auto}.focal-point-editor__marker{pointer-events:none;background:red;border:2px solid #fff;border-radius:50%;width:12px;height:12px;margin:-6px 0 0 -6px;position:absolute}.version-history__list{flex-direction:column;gap:.75rem;margin:0;padding:0;list-style:none;display:flex}.version-history__item{border:1px solid var(--color-border,#ccc);border-radius:4px;flex-wrap:wrap;align-items:center;gap:.5rem 1rem;padding:.5rem .75rem;display:flex}.version-history__actions{gap:.5rem;display:flex}.version-history__diff{flex-basis:100%;margin-top:.5rem}.version-history__field-changes,.version-history__block-changes{margin:.25rem 0;padding-left:1.25rem}.entry-form__error{color:var(--color-danger)}.entry-form__autosave{opacity:.8;font-size:.875rem}.entry-form__modes{border:0;gap:.25rem;margin:0 0 1rem;padding:0;display:flex}.entry-form__recovery{border:1px solid var(--color-border);border-radius:.25rem;margin-bottom:1rem;padding:.75rem 1rem}.blocks-field{flex-direction:column;gap:1rem;margin:0;padding:0;list-style:none;display:flex}.blocks-field__item{border:1px solid var(--color-border,#ccc);border-radius:4px;padding:.75rem}.blocks-field__item-header{justify-content:space-between;align-items:center;gap:.5rem;margin-bottom:.5rem;font-weight:600;display:flex}.blocks-field__item-controls{gap:.25rem;display:flex}.blocks-field__add{align-items:center;gap:.5rem;margin-top:1rem;display:flex}.auth-page{min-height:100%;padding:var(--space-6);justify-content:center;align-items:center;display:flex}.auth-form{gap:var(--space-2);width:100%;max-width:24rem;padding:var(--space-6);border:1px solid var(--color-border);border-radius:var(--radius);background:var(--color-surface);flex-direction:column;display:flex}.auth-form h1{margin:0 0 var(--space-2);font-size:1.25rem}.auth-form form{gap:var(--space-2);flex-direction:column;display:flex}.auth-form__divider{margin:var(--space-2) 0;text-align:center;color:var(--color-text-muted);font-size:.875rem}.auth-form label{color:var(--color-text-muted);font-size:.875rem}.auth-form input{padding:var(--space-2) var(--space-3);border:1px solid var(--color-border);border-radius:var(--radius);background:var(--color-bg);color:var(--color-text);font:inherit}.auth-form button{margin-top:var(--space-3);padding:var(--space-2) var(--space-3);border-radius:var(--radius);background:var(--color-primary);color:var(--color-primary-contrast);font:inherit;cursor:pointer;border:none}.auth-form button:disabled{opacity:.6;cursor:not-allowed}.auth-form__error{color:var(--color-danger);margin:0;font-size:.875rem}.app-shell{grid-template:"topbar topbar""sidebar content"1fr/220px 1fr;min-height:100%;display:grid}.app-shell__topbar{padding:var(--space-3) var(--space-4);border-bottom:1px solid var(--color-border);background:var(--color-surface);grid-area:topbar;align-items:center;display:flex}.app-shell__brand{font-weight:600}.app-shell__account{align-items:center;gap:var(--space-3);color:var(--color-text-muted);margin-left:auto;font-size:.875rem;display:flex}.app-shell__account button{border:1px solid var(--color-border);background:var(--color-bg);color:var(--color-text);border-radius:var(--radius);padding:var(--space-1) var(--space-3);cursor:pointer}.app-shell__account button:hover{background:var(--color-surface)}.app-shell__sidebar{border-right:1px solid var(--color-border);padding:var(--space-4) var(--space-2);grid-area:sidebar}.app-shell__sidebar ul{gap:var(--space-1);flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.app-shell__sidebar a{padding:var(--space-2) var(--space-3);border-radius:var(--radius);color:var(--color-text);text-decoration:none;display:block}.app-shell__sidebar a:hover{background:var(--color-surface)}.app-shell__sidebar a.active{background:var(--color-primary);color:var(--color-primary-contrast)}.app-shell__content{padding:var(--space-6);grid-area:content}.skip-link{top:-40px;left:var(--space-2);z-index:100;background:var(--color-primary);color:var(--color-primary-contrast);padding:var(--space-2) var(--space-3);border-radius:var(--radius);text-decoration:none;position:absolute}.skip-link:focus{top:var(--space-2)}@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--font-mono:ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--radius-md:.5rem;--radius-lg:.625rem;--radius-xl:.875rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--color-border:var(--border);--color-primary:var(--primary);--shadow-card:var(--shadow-card);--shadow-raised:var(--shadow-raised);--shadow-overlay:var(--shadow-overlay)}}@layer base{*,:before,:after{box-sizing:border-box}html,body,#root{height:100%}body{font-family:var(--font-sans);color:var(--color-text);background:var(--color-bg);margin:0;font-size:16px;line-height:1.5}a{color:var(--color-primary)}button{font:inherit}:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}}@layer components;@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:0}.top-1\/2{top:50%}.left-1\/2{left:50%}.z-40{z-index:40}.z-50{z-index:50}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.m-0{margin:0}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.list-item{display:list-item}.table{display:table}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-\[70vh\]{height:70vh}.max-h-\[85vh\]{max-height:85vh}.w-\[min\(32rem\,calc\(100vw-2rem\)\)\]{width:min(32rem,100vw - 2rem)}.w-full{width:100%}.max-w-3xl{max-width:var(--container-3xl)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-grab{cursor:grab}.cursor-pointer{cursor:pointer}.list-none{list-style-type:none}.appearance-none{appearance:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-border{border-color:var(--border)}.border-destructive\/30{border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.border-destructive\/30{border-color:color-mix(in oklab, var(--destructive) 30%, transparent)}}.border-info\/30{border-color:var(--info)}@supports (color:color-mix(in lab, red, red)){.border-info\/30{border-color:color-mix(in oklab, var(--info) 30%, transparent)}}.border-input{border-color:var(--input)}.border-primary{border-color:var(--primary)}.border-success\/30{border-color:var(--success)}@supports (color:color-mix(in lab, red, red)){.border-success\/30{border-color:color-mix(in oklab, var(--success) 30%, transparent)}}.border-transparent{border-color:#0000}.border-warning\/40{border-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.border-warning\/40{border-color:color-mix(in oklab, var(--warning) 40%, transparent)}}.bg-accent{background-color:var(--accent)}.bg-background{background-color:var(--background)}.bg-card{background-color:var(--card)}.bg-destructive{background-color:var(--destructive)}.bg-destructive-surface{background-color:var(--destructive-surface)}.bg-foreground\/40{background-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.bg-foreground\/40{background-color:color-mix(in oklab, var(--foreground) 40%, transparent)}}.bg-info-surface{background-color:var(--info-surface)}.bg-muted{background-color:var(--muted)}.bg-primary{background-color:var(--primary)}.bg-secondary{background-color:var(--secondary)}.bg-success-surface{background-color:var(--success-surface)}.bg-transparent{background-color:#0000}.bg-warning-surface{background-color:var(--warning-surface)}.bg-white{background-color:var(--color-white)}.p-0{padding:0}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-8{padding-block:calc(var(--spacing) * 8)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.text-center{text-align:center}.text-left{text-align:left}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-none{--tw-leading:1;line-height:1}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-card-foreground{color:var(--card-foreground)}.text-destructive{color:var(--destructive)}.text-destructive-foreground{color:var(--destructive-foreground)}.text-foreground{color:var(--foreground)}.text-info{color:var(--info)}.text-muted-foreground{color:var(--muted-foreground)}.text-primary-foreground{color:var(--primary-foreground)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-success{color:var(--success)}.text-warning{color:var(--warning)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.shadow-card{--tw-shadow:var(--shadow-card);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-overlay{--tw-shadow:var(--shadow-overlay);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-\[max-width\]{transition-property:max-width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.select-none{-webkit-user-select:none;user-select:none}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media (hover:hover){.hover\:bg-accent:hover,.hover\:bg-accent\/60:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/60:hover{background-color:color-mix(in oklab, var(--accent) 60%, transparent)}}.hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab, var(--destructive) 90%, transparent)}}.hover\:bg-foreground\/5:hover{background-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-foreground\/5:hover{background-color:color-mix(in oklab, var(--foreground) 5%, transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--primary) 90%, transparent)}}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:text-foreground:hover{color:var(--foreground)}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-ring:focus-visible{outline-color:var(--ring)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-default:disabled{cursor:default}.disabled\:opacity-60:disabled{opacity:.6}.aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}@media (width>=64rem){.lg\:grid-cols-\[16rem_minmax\(0\,1fr\)_20rem\]{grid-template-columns:16rem minmax(0,1fr) 20rem}}.\[\&\>\*\]\:m-0>*{margin:0}.\[\&\>\*\]\:text-inherit>*{color:inherit}.\[\&\>p\]\:m-0>p{margin:0}}:root{--background:#f7f8fa;--foreground:#10131a;--card:#fff;--card-foreground:#10131a;--muted:#eef0f4;--muted-foreground:#565e6e;--border:#e0e3ea;--input:#cbd1db;--ring:#4f46e5;--primary:#4f46e5;--primary-foreground:#fff;--secondary:#fff;--secondary-foreground:#232936;--accent:#eef2ff;--accent-foreground:#312e81;--destructive:#b91c1c;--destructive-foreground:#fff;--destructive-surface:#fef2f2;--success:#15803d;--success-foreground:#fff;--success-surface:#f0fdf4;--warning:#a16207;--warning-foreground:#fff;--warning-surface:#fffbeb;--info:#1d4ed8;--info-foreground:#fff;--info-surface:#eff6ff;--shadow-card:0 1px 2px #10131a0a, 0 1px 3px #10131a0f;--shadow-raised:0 2px 4px #10131a0d, 0 8px 16px -4px #10131a14;--shadow-overlay:0 8px 24px -6px #10131a29, 0 24px 48px -12px #10131a33}@media (prefers-color-scheme:dark){:root{--background:#0d1017;--foreground:#e8eaf0;--card:#151a23;--card-foreground:#e8eaf0;--muted:#1b2029;--muted-foreground:#9aa3b2;--border:#272d38;--input:#3a4250;--ring:#818cf8;--primary:#6366f1;--primary-foreground:#fff;--secondary:#1b2029;--secondary-foreground:#e8eaf0;--accent:#1e2130;--accent-foreground:#c7d2fe;--destructive:#dc2626;--destructive-foreground:#fff;--destructive-surface:#2a1416;--success:#16a34a;--success-foreground:#fff;--success-surface:#0f2018;--warning:#ca8a04;--warning-foreground:#1a1405;--warning-surface:#241d0a;--info:#3b82f6;--info-foreground:#fff;--info-surface:#101b2e;--shadow-card:0 1px 2px #0006, 0 1px 3px #0000004d;--shadow-raised:0 2px 4px #0006, 0 8px 16px -4px #00000073;--shadow-overlay:0 8px 24px -6px #0009, 0 24px 48px -12px #0009}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}:root{--color-bg:var(--background);--color-surface:var(--muted);--color-border:var(--border);--color-text:var(--foreground);--color-text-muted:var(--muted-foreground);--color-primary:var(--primary);--color-primary-contrast:var(--primary-foreground);--color-danger:var(--destructive);--color-focus-ring:var(--ring);--space-1:.25rem;--space-2:.5rem;--space-3:.75rem;--space-4:1rem;--space-6:1.5rem;--space-8:2rem;--radius:.375rem}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important}}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>Cogenta</title>
7
- <script type="module" crossorigin src="/admin/assets/index-CKLmd_Fi.js"></script>
8
- <link rel="stylesheet" crossorigin href="/admin/assets/index-21ZcDkDC.css">
7
+ <script type="module" crossorigin src="/admin/assets/index-Buwdj1V2.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/admin/assets/index-Csef0SiA.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -0,0 +1,65 @@
1
+ import { type AssistToolset, type EmbeddingProvider, type SemanticSearch, type VectorStore } from '@cogenta/agents';
2
+ import type { CogentaConfig, DatabaseHandle, Logger } from '@cogenta/core';
3
+ import type { CollectionDefinition, ContentStore, SearchDriver } from '@cogenta/schema';
4
+ /**
5
+ * Where L18 is actually wired into a running site.
6
+ *
7
+ * This module is the only place in the repository that knows both
8
+ * `@cogenta/agents` (the tools) and `@cogenta/schema` (the content), which is
9
+ * why the bridge between a written entry and a stored embedding lives here
10
+ * rather than in either of them: `@cogenta/schema` may not depend on the agent
11
+ * runtime, and `@cogenta/agents` may not depend on the content engine.
12
+ *
13
+ * **Everything here is optional and fails soft.** A site with no AI provider
14
+ * gets an unavailable toolset and no route change; a site whose embeddings
15
+ * provider has no adapter yet gets no semantic search and a warning in the log,
16
+ * not a refusal to start. Nothing in this file can prevent `cogenta serve` from
17
+ * serving a site (R2).
18
+ */
19
+ export interface AssistantAssembly {
20
+ readonly toolset: AssistToolset;
21
+ /** Absent when semantic search is not available on this site. */
22
+ readonly search?: SemanticSearch;
23
+ /** Absent for the same reason. Used to keep the index in step with the content. */
24
+ readonly vectors?: {
25
+ readonly store: VectorStore;
26
+ readonly embeddings: EmbeddingProvider;
27
+ };
28
+ /** What `cogenta serve` prints on startup. Always truthful about what is off. */
29
+ readonly summary: string;
30
+ dispose(): Promise<void>;
31
+ }
32
+ export interface BuildAssistantOptions {
33
+ readonly config: CogentaConfig;
34
+ readonly db: DatabaseHandle;
35
+ readonly logger: Logger;
36
+ /** L10's full-text index, fused with the vector half rather than replaced by it. */
37
+ readonly fullText?: SearchDriver;
38
+ }
39
+ export declare function buildAssistant(options: BuildAssistantOptions): Promise<AssistantAssembly>;
40
+ /**
41
+ * Keeps the vector index in step with the content, by wrapping the store.
42
+ *
43
+ * Exactly the shape `withSearchIndexing` (L10 task 3) already established, and
44
+ * for the same reason: `serve.ts` hands the *same* store instances to REST and
45
+ * to GraphQL, so one wrap covers both transports and neither can bypass it.
46
+ *
47
+ * Only the **published** face is indexed. A chat answer is quotable, and the
48
+ * one thing that must never happen is a visitor being told something from a
49
+ * draft nobody approved — so an entry with no published face is removed from
50
+ * the index rather than indexed under its draft status.
51
+ *
52
+ * A failed index write never fails the content write that triggered it: the
53
+ * embedding is derived data that can be rebuilt from the content at any time,
54
+ * and losing an editor's save because an embedding could not be stored would be
55
+ * the wrong trade.
56
+ */
57
+ export interface VectorIndexingOptions {
58
+ readonly collection: CollectionDefinition;
59
+ readonly siteId: string;
60
+ readonly store: VectorStore;
61
+ readonly embeddings: EmbeddingProvider;
62
+ readonly onError?: (error: unknown) => void;
63
+ }
64
+ export declare function withVectorIndexing(store: ContentStore, options: VectorIndexingOptions): ContentStore;
65
+ //# sourceMappingURL=assistant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistant.d.ts","sourceRoot":"","sources":["../../src/commands/assistant.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAOlB,KAAK,iBAAiB,EAKtB,KAAK,cAAc,EAEnB,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAC1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGvF;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAA;IAChC,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;QAAC,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAA;KAAE,CAAA;IAC1F,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;CACjC;AAwFD,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0D/F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAA;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAA;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CAC5C;AAyCD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,qBAAqB,GAC7B,YAAY,CAyCd"}
@@ -0,0 +1,207 @@
1
+ import { createAssistToolset, createHashingEmbeddingProvider, createImageProviderRegistry, createProviderRegistry, createSemanticSearch, createVectorRegistry, PROVIDER_NAMES, } from '@cogenta/agents';
2
+ import { searchDocumentFor } from '@cogenta/schema';
3
+ function isProviderName(value) {
4
+ return PROVIDER_NAMES.includes(value);
5
+ }
6
+ /**
7
+ * The text client, or nothing.
8
+ *
9
+ * A configured provider whose name this build does not know, or whose API key
10
+ * is missing, produces `undefined` and a warning — never a throw. An operator
11
+ * who mistyped a provider name should get a site that works with the assistant
12
+ * off, plus a log line saying exactly that.
13
+ */
14
+ function textProvider(options) {
15
+ const llm = options.config.llm;
16
+ if (llm === undefined)
17
+ return undefined;
18
+ if (!isProviderName(llm.provider)) {
19
+ options.logger.warn('unknown LLM provider, the writing assistant stays off', {
20
+ provider: llm.provider,
21
+ known: PROVIDER_NAMES,
22
+ });
23
+ return undefined;
24
+ }
25
+ if (llm.apiKey === undefined) {
26
+ options.logger.warn('LLM provider configured with no API key, the writing assistant stays off', {
27
+ provider: llm.provider,
28
+ variable: 'COGENTA_LLM_API_KEY',
29
+ });
30
+ return undefined;
31
+ }
32
+ const registry = createProviderRegistry({
33
+ [llm.provider]: {
34
+ apiKey: llm.apiKey,
35
+ model: llm.model,
36
+ ...(llm.baseUrl === undefined ? {} : { baseUrl: llm.baseUrl }),
37
+ },
38
+ });
39
+ return registry.get(llm.provider);
40
+ }
41
+ function imageProvider(options) {
42
+ const images = options.config.imageGeneration;
43
+ if (images === undefined)
44
+ return undefined;
45
+ if (images.apiKey === undefined) {
46
+ options.logger.warn('image provider configured with no API key, image generation stays off', {
47
+ provider: images.provider,
48
+ variable: 'COGENTA_IMAGE_API_KEY',
49
+ });
50
+ return undefined;
51
+ }
52
+ const registry = createImageProviderRegistry({
53
+ [images.provider]: {
54
+ apiKey: images.apiKey,
55
+ model: images.model,
56
+ ...(images.baseUrl === undefined ? {} : { baseUrl: images.baseUrl }),
57
+ },
58
+ });
59
+ return registry.get(images.provider);
60
+ }
61
+ /**
62
+ * The embedder, or nothing.
63
+ *
64
+ * Only `local` has an adapter today — the hashing provider, which needs no key,
65
+ * no service and no model download. `openai` is a valid configuration value
66
+ * that nothing implements yet, and the honest answer to it is to switch the
67
+ * feature off with a log line naming what is missing, not to quietly substitute
68
+ * a different embedding space (which would rank nonsense) and not to refuse to
69
+ * boot over a feature the site may not even use.
70
+ */
71
+ function embeddingProvider(options) {
72
+ const { provider, dimensions } = options.config.embeddings;
73
+ if (provider === 'local')
74
+ return createHashingEmbeddingProvider({ dimensions });
75
+ options.logger.warn('no adapter for this embeddings provider yet, semantic search and duplicate detection stay off', { provider, implemented: ['local'] });
76
+ return undefined;
77
+ }
78
+ export async function buildAssistant(options) {
79
+ const { config, logger } = options;
80
+ const provider = textProvider(options);
81
+ const images = imageProvider(options);
82
+ const embeddings = embeddingProvider(options);
83
+ let store;
84
+ let disposeVectors;
85
+ let vectorDriver = 'none';
86
+ if (embeddings !== undefined) {
87
+ try {
88
+ const selection = await createVectorRegistry({ db: options.db, logger }).select({
89
+ driver: config.vector.driver,
90
+ dimensions: embeddings.dimensions,
91
+ path: config.vector.path,
92
+ table: config.vector.table,
93
+ });
94
+ store = selection.instance;
95
+ vectorDriver = selection.driver;
96
+ disposeVectors = () => selection.dispose();
97
+ }
98
+ catch (error) {
99
+ // Same posture as everywhere else here: a vector store that will not
100
+ // start takes semantic search with it and nothing else.
101
+ logger.warn('no vector store available, semantic search stays off', { error: String(error) });
102
+ }
103
+ }
104
+ const search = store === undefined || embeddings === undefined
105
+ ? undefined
106
+ : createSemanticSearch({
107
+ store,
108
+ embeddings,
109
+ ...(options.fullText === undefined ? {} : { fullText: options.fullText }),
110
+ });
111
+ const toolset = createAssistToolset({
112
+ site: { name: config.site.name, locales: config.site.locales },
113
+ ...(provider === undefined ? {} : { provider }),
114
+ ...(images === undefined ? {} : { imageProvider: images }),
115
+ ...(search === undefined ? {} : { search }),
116
+ ...(store === undefined || embeddings === undefined ? {} : { vectors: { store, embeddings } }),
117
+ });
118
+ const summary = toolset.available
119
+ ? `assistant: ${toolset.tools.length} tool(s), text provider: ${provider?.name ?? 'none'}, image provider: ${images?.name ?? 'none'}, vector driver: ${vectorDriver}`
120
+ : 'assistant: off (no AI provider configured)';
121
+ return {
122
+ toolset,
123
+ ...(search === undefined ? {} : { search }),
124
+ ...(store === undefined || embeddings === undefined ? {} : { vectors: { store, embeddings } }),
125
+ summary,
126
+ dispose: async () => {
127
+ await disposeVectors?.();
128
+ },
129
+ };
130
+ }
131
+ /** The chunk id an entry's single document occupies. One chunk per entry, for now — see the note in `reindexEntry`. */
132
+ function chunkIdFor(collection, id) {
133
+ return `${collection}:${id}:0`;
134
+ }
135
+ async function recordFor(options, document) {
136
+ const text = [document.title, document.body].filter((part) => part.length > 0).join('\n\n');
137
+ if (text.trim().length === 0)
138
+ return null;
139
+ const [vector] = await options.embeddings.embed([text]);
140
+ if (vector === undefined)
141
+ return null;
142
+ return {
143
+ siteId: options.siteId,
144
+ collection: options.collection.name,
145
+ entryId: document.id,
146
+ locale: document.locale,
147
+ status: document.status,
148
+ chunk: {
149
+ // One chunk per entry rather than `chunkDocument`'s real chunking.
150
+ // `chunkDocument` (L4) wants a block list with heading flags, which
151
+ // `searchDocumentFor` has already flattened away — feeding it the
152
+ // flattened string would produce chunk boundaries in the wrong places.
153
+ // Wiring real chunking means reading the entry's blocks directly, which
154
+ // is a piece of work of its own; one chunk per entry retrieves the right
155
+ // entries today and simply quotes more of them than it needs to.
156
+ id: chunkIdFor(options.collection.name, document.id),
157
+ documentId: document.id,
158
+ blockIds: [],
159
+ text,
160
+ hash: document.id,
161
+ },
162
+ vector,
163
+ };
164
+ }
165
+ export function withVectorIndexing(store, options) {
166
+ async function reindex(id) {
167
+ try {
168
+ const published = await store.read(id, { state: 'published' });
169
+ if (published === null) {
170
+ await options.store.remove([chunkIdFor(options.collection.name, id)]);
171
+ return;
172
+ }
173
+ const record = await recordFor(options, searchDocumentFor(options.collection, published));
174
+ if (record === null) {
175
+ await options.store.remove([chunkIdFor(options.collection.name, id)]);
176
+ return;
177
+ }
178
+ await options.store.upsert([record]);
179
+ }
180
+ catch (error) {
181
+ options.onError?.(error);
182
+ }
183
+ }
184
+ async function after(entry) {
185
+ await reindex(entry.id);
186
+ return entry;
187
+ }
188
+ return {
189
+ ...store,
190
+ create: async (input) => after(await store.create(input)),
191
+ update: async (id, input) => after(await store.update(id, input)),
192
+ publish: async (id, input) => after(await store.publish(id, input)),
193
+ unpublish: async (id, input) => after(await store.unpublish(id, input)),
194
+ restore: async (id, version, input) => after(await store.restore(id, version, input)),
195
+ delete: async (id) => {
196
+ const removed = await store.delete(id);
197
+ try {
198
+ await options.store.remove([chunkIdFor(options.collection.name, id)]);
199
+ }
200
+ catch (error) {
201
+ options.onError?.(error);
202
+ }
203
+ return removed;
204
+ },
205
+ };
206
+ }
207
+ //# sourceMappingURL=assistant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistant.js","sourceRoot":"","sources":["../../src/commands/assistant.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { type WebhookEventSender } from '@cogenta/channels';
2
+ import type { CogentaConfig, Logger } from '@cogenta/core';
3
+ import type { ContentLifecycleEvent } from '@cogenta/schema';
4
+ /**
5
+ * Turns the site's configuration into the one thing `assembleSite` needs: a
6
+ * function that publishes a content lifecycle event to the outside world
7
+ * (L14 task 1).
8
+ *
9
+ * The signed webhook channel has existed since L6 and nothing ever called it.
10
+ * This is the missing half — and deliberately only the wiring: the signature,
11
+ * the headers and the freshness semantics are `@cogenta/channels`'s, unchanged.
12
+ */
13
+ export interface ContentWebhookOptions {
14
+ readonly webhooks: CogentaConfig['webhooks'];
15
+ /** The site's public base URL, used to turn an entry's path into an absolute URL. */
16
+ readonly siteUrl: string;
17
+ readonly logger: Logger;
18
+ /** Overridable for tests; defaults to the sender built from `webhooks`. */
19
+ readonly sender?: WebhookEventSender;
20
+ }
21
+ export interface ContentWebhookEmitter {
22
+ /** `null` when the site sends nothing — no endpoint, or no secret. */
23
+ readonly emit: ((event: ContentLifecycleEvent) => Promise<void>) | null;
24
+ /**
25
+ * The same signed channel, for the events that are not about content — the
26
+ * suspicious-activity alert of L14 task 4. Deliberately the *same* sender, so
27
+ * a site configures one set of endpoints and one secret, and there is never a
28
+ * second signing path to review.
29
+ */
30
+ readonly send: ((event: string, data: Readonly<Record<string, unknown>>) => Promise<void>) | null;
31
+ }
32
+ /**
33
+ * Both halves are required, and the missing-secret case is a refusal rather
34
+ * than a downgrade: sending a *signed* webhook to nowhere is harmless, but
35
+ * sending an *unsigned* one is an unauthenticated instruction arriving at
36
+ * somebody else's server, which they have no way to tell from an attacker's.
37
+ * A site that configured endpoints without a secret is told so once, at
38
+ * startup, instead of silently never delivering.
39
+ */
40
+ export declare function createContentWebhookEmitter(options: ContentWebhookOptions): ContentWebhookEmitter;
41
+ //# sourceMappingURL=content-webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-webhooks.d.ts","sourceRoot":"","sources":["../../src/commands/content-webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAC1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAE5D;;;;;;;;GAQG;AAEH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IAC5C,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAA;CACrC;AAED,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,qBAAqB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAA;IACvE;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAA;CAClG;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,qBAAqB,GAAG,qBAAqB,CAqDjG"}
@@ -0,0 +1,61 @@
1
+ import { createWebhookEventSender } from '@cogenta/channels';
2
+ /**
3
+ * Both halves are required, and the missing-secret case is a refusal rather
4
+ * than a downgrade: sending a *signed* webhook to nowhere is harmless, but
5
+ * sending an *unsigned* one is an unauthenticated instruction arriving at
6
+ * somebody else's server, which they have no way to tell from an attacker's.
7
+ * A site that configured endpoints without a secret is told so once, at
8
+ * startup, instead of silently never delivering.
9
+ */
10
+ export function createContentWebhookEmitter(options) {
11
+ const { endpoints, secret } = options.webhooks;
12
+ if (options.sender === undefined && endpoints.length === 0)
13
+ return { emit: null, send: null };
14
+ if (options.sender === undefined && secret === undefined) {
15
+ options.logger.warn('outbound webhooks are configured but disabled', {
16
+ endpoints: endpoints.length,
17
+ reason: 'COGENTA_WEBHOOK_SECRET is not set',
18
+ });
19
+ return { emit: null, send: null };
20
+ }
21
+ const sender = options.sender ?? createWebhookEventSender({ endpoints, secret: secret ?? '' });
22
+ /**
23
+ * Structured, and never silent: an outbound side effect that failed is
24
+ * exactly the thing an operator needs in the log, and there is no retry to
25
+ * make it right later (rule R1 — this deployment guarantees no durable
26
+ * worker).
27
+ */
28
+ const send = async (event, data) => {
29
+ for (const result of await sender.send(event, data)) {
30
+ if (result.delivered) {
31
+ options.logger.info('webhook delivered', {
32
+ event,
33
+ url: result.url,
34
+ status: result.status,
35
+ });
36
+ }
37
+ else {
38
+ options.logger.error('webhook delivery failed', {
39
+ event,
40
+ url: result.url,
41
+ status: result.status,
42
+ error: result.error?.code ?? 'UNKNOWN',
43
+ });
44
+ }
45
+ }
46
+ };
47
+ return {
48
+ send,
49
+ emit: async (event) => {
50
+ const { path, ...rest } = event;
51
+ await send(event.event, {
52
+ ...rest,
53
+ path,
54
+ // An absolute URL costs the receiver one less thing to know. Built from
55
+ // the same `site.url` the canonical tag and the sitemap already use.
56
+ url: path === null ? null : new URL(path, options.siteUrl).toString(),
57
+ });
58
+ },
59
+ };
60
+ }
61
+ //# sourceMappingURL=content-webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-webhooks.js","sourceRoot":"","sources":["../../src/commands/content-webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAA2B,MAAM,mBAAmB,CAAA;AAmCrF;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAA8B;IACxE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAA;IAE9C,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IAE7F,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,+CAA+C,EAAE;YACnE,SAAS,EAAE,SAAS,CAAC,MAAM;YAC3B,MAAM,EAAE,mCAAmC;SAC5C,CAAC,CAAA;QACF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACnC,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,wBAAwB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,CAAA;IAE9F;;;;;OAKG;IACH,MAAM,IAAI,GAAG,KAAK,EAAE,KAAa,EAAE,IAAuC,EAAiB,EAAE;QAC3F,KAAK,MAAM,MAAM,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YACpD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACrB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE;oBACvC,KAAK;oBACL,GAAG,EAAE,MAAM,CAAC,GAAG;oBACf,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB,CAAC,CAAA;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE;oBAC9C,KAAK;oBACL,GAAG,EAAE,MAAM,CAAC,GAAG;oBACf,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,IAAI,SAAS;iBACvC,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACpB,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAA;YAC/B,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;gBACtB,GAAG,IAAI;gBACP,IAAI;gBACJ,wEAAwE;gBACxE,qEAAqE;gBACrE,GAAG,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;aACtE,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import type { CogentaConfig } from '@cogenta/core';
3
+ /**
4
+ * CORS, security headers and cache-control for `cogenta serve` (L10 task 6).
5
+ *
6
+ * All three are applied in one place, before any route runs, for the reason
7
+ * that makes them worth having at all: a header added per route is a header
8
+ * some route forgets. `writeHead` is patched once per request so that every
9
+ * existing `res.writeHead(...)` call — and there are a dozen — picks them up
10
+ * without being rewritten, and so that a route added later cannot opt out by
11
+ * omission.
12
+ */
13
+ export type SecurityConfig = CogentaConfig['security'];
14
+ /** Which cache-control a path class gets. */
15
+ export declare function cacheControlFor(pathname: string, security: SecurityConfig): string | null;
16
+ /**
17
+ * The CORS headers this request earns, or an empty object.
18
+ *
19
+ * The origin is echoed rather than reflected blindly: only an exact match in
20
+ * the configured list, or `*` when the list holds it. `Vary: Origin` goes out
21
+ * with any match, because a shared cache that stores one origin's response
22
+ * and serves it to another is the whole class of CORS cache-poisoning bugs.
23
+ */
24
+ export declare function corsHeadersFor(origin: string | undefined, security: SecurityConfig): Readonly<Record<string, string>>;
25
+ /** The extra headers a preflight needs on top of the ones above. */
26
+ export declare function preflightHeadersFor(security: SecurityConfig): Readonly<Record<string, string>>;
27
+ /**
28
+ * Applies the headers to every response of this request, and answers a CORS
29
+ * preflight outright.
30
+ *
31
+ * Returns `true` when the request is finished — the caller must then do
32
+ * nothing else. Patching `writeHead` rather than calling `setHeader` up front
33
+ * is what makes this survive the routes that pass a header object of their
34
+ * own: `res.writeHead(200, { 'content-type': … })` replaces every header
35
+ * previously set, so setting them early would silently lose them on most of
36
+ * the routes in this file.
37
+ */
38
+ export declare function applySecurity(req: IncomingMessage, res: ServerResponse, pathname: string, security: SecurityConfig): boolean;
39
+ //# sourceMappingURL=http-security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-security.d.ts","sourceRoot":"","sources":["../../src/commands/http-security.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAuB,cAAc,EAAE,MAAM,WAAW,CAAA;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAElD;;;;;;;;;GASG;AAEH,MAAM,MAAM,cAAc,GAAG,aAAa,CAAC,UAAU,CAAC,CAAA;AAkBtD,6CAA6C;AAC7C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAkBzF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,cAAc,GACvB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAYlC;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAM9F;AAyDD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAsCT"}