@actuate-media/cms-core 0.30.0 → 0.32.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 (98) hide show
  1. package/dist/__tests__/api/admin-contracts.test.js +10 -2
  2. package/dist/__tests__/api/admin-contracts.test.js.map +1 -1
  3. package/dist/__tests__/api/public-forms.test.d.ts +2 -0
  4. package/dist/__tests__/api/public-forms.test.d.ts.map +1 -0
  5. package/dist/__tests__/api/public-forms.test.js +125 -0
  6. package/dist/__tests__/api/public-forms.test.js.map +1 -0
  7. package/dist/__tests__/api/public-seo.test.js +2 -0
  8. package/dist/__tests__/api/public-seo.test.js.map +1 -1
  9. package/dist/__tests__/forms/forms-service.test.d.ts +2 -0
  10. package/dist/__tests__/forms/forms-service.test.d.ts.map +1 -0
  11. package/dist/__tests__/forms/forms-service.test.js +193 -0
  12. package/dist/__tests__/forms/forms-service.test.js.map +1 -0
  13. package/dist/__tests__/forms/spam.test.d.ts +2 -0
  14. package/dist/__tests__/forms/spam.test.d.ts.map +1 -0
  15. package/dist/__tests__/forms/spam.test.js +115 -0
  16. package/dist/__tests__/forms/spam.test.js.map +1 -0
  17. package/dist/__tests__/forms/submission-files.test.d.ts +2 -0
  18. package/dist/__tests__/forms/submission-files.test.d.ts.map +1 -0
  19. package/dist/__tests__/forms/submission-files.test.js +65 -0
  20. package/dist/__tests__/forms/submission-files.test.js.map +1 -0
  21. package/dist/__tests__/forms/submission-pipeline.test.d.ts +2 -0
  22. package/dist/__tests__/forms/submission-pipeline.test.d.ts.map +1 -0
  23. package/dist/__tests__/forms/submission-pipeline.test.js +131 -0
  24. package/dist/__tests__/forms/submission-pipeline.test.js.map +1 -0
  25. package/dist/__tests__/forms/submission-validation.test.d.ts +2 -0
  26. package/dist/__tests__/forms/submission-validation.test.d.ts.map +1 -0
  27. package/dist/__tests__/forms/submission-validation.test.js +108 -0
  28. package/dist/__tests__/forms/submission-validation.test.js.map +1 -0
  29. package/dist/__tests__/seo/audit-runner.test.js +54 -1
  30. package/dist/__tests__/seo/audit-runner.test.js.map +1 -1
  31. package/dist/api/handler-factory.d.ts.map +1 -1
  32. package/dist/api/handler-factory.js +2 -2
  33. package/dist/api/handler-factory.js.map +1 -1
  34. package/dist/api/handlers.d.ts.map +1 -1
  35. package/dist/api/handlers.js +724 -155
  36. package/dist/api/handlers.js.map +1 -1
  37. package/dist/api/router.d.ts +2 -1
  38. package/dist/api/router.d.ts.map +1 -1
  39. package/dist/api/router.js +3 -0
  40. package/dist/api/router.js.map +1 -1
  41. package/dist/config/types.d.ts +42 -0
  42. package/dist/config/types.d.ts.map +1 -1
  43. package/dist/cron/index.d.ts +1 -0
  44. package/dist/cron/index.d.ts.map +1 -1
  45. package/dist/cron/index.js +10 -1
  46. package/dist/cron/index.js.map +1 -1
  47. package/dist/forms/entries.d.ts +45 -0
  48. package/dist/forms/entries.d.ts.map +1 -0
  49. package/dist/forms/entries.js +348 -0
  50. package/dist/forms/entries.js.map +1 -0
  51. package/dist/forms/files.d.ts +38 -0
  52. package/dist/forms/files.d.ts.map +1 -0
  53. package/dist/forms/files.js +134 -0
  54. package/dist/forms/files.js.map +1 -0
  55. package/dist/forms/index.d.ts +8 -0
  56. package/dist/forms/index.d.ts.map +1 -1
  57. package/dist/forms/index.js +7 -0
  58. package/dist/forms/index.js.map +1 -1
  59. package/dist/forms/service.d.ts +92 -0
  60. package/dist/forms/service.d.ts.map +1 -0
  61. package/dist/forms/service.js +579 -0
  62. package/dist/forms/service.js.map +1 -0
  63. package/dist/forms/spam.d.ts +33 -0
  64. package/dist/forms/spam.d.ts.map +1 -0
  65. package/dist/forms/spam.js +93 -0
  66. package/dist/forms/spam.js.map +1 -0
  67. package/dist/forms/submission.d.ts +95 -0
  68. package/dist/forms/submission.d.ts.map +1 -0
  69. package/dist/forms/submission.js +282 -0
  70. package/dist/forms/submission.js.map +1 -0
  71. package/dist/forms/types.d.ts +244 -0
  72. package/dist/forms/types.d.ts.map +1 -0
  73. package/dist/forms/types.js +36 -0
  74. package/dist/forms/types.js.map +1 -0
  75. package/dist/forms/validation.d.ts +19 -0
  76. package/dist/forms/validation.d.ts.map +1 -0
  77. package/dist/forms/validation.js +235 -0
  78. package/dist/forms/validation.js.map +1 -0
  79. package/dist/index.d.ts +2 -2
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +1 -1
  82. package/dist/index.js.map +1 -1
  83. package/dist/security/client-ip.d.ts +11 -21
  84. package/dist/security/client-ip.d.ts.map +1 -1
  85. package/dist/security/client-ip.js +38 -0
  86. package/dist/security/client-ip.js.map +1 -1
  87. package/dist/seo/audit-runner.d.ts +37 -2
  88. package/dist/seo/audit-runner.d.ts.map +1 -1
  89. package/dist/seo/audit-runner.js +56 -6
  90. package/dist/seo/audit-runner.js.map +1 -1
  91. package/dist/seo/index.d.ts +2 -1
  92. package/dist/seo/index.d.ts.map +1 -1
  93. package/dist/seo/index.js +1 -1
  94. package/dist/seo/index.js.map +1 -1
  95. package/package.json +1 -1
  96. package/prisma/cms-schema.prisma +81 -7
  97. package/prisma/migrations/0010_forms/migration.sql +130 -0
  98. package/prisma/schema.prisma +130 -35
@@ -561,30 +561,30 @@ model SeoAuditRun {
561
561
  /// hash of (type + entityId/url) used to carry status across runs so a
562
562
  /// resolved/ignored issue stays resolved/ignored when re-detected.
563
563
  model SeoIssue {
564
- id String @id @default(cuid())
565
- auditRunId String?
566
- issueKey String
567
- entityType String?
568
- entityId String?
569
- entityTitle String?
570
- url String?
571
- severity SeoIssueSeverity
572
- category SeoIssueCategory
573
- type String
574
- title String
575
- description String?
576
- impact String?
577
- recommendation String?
578
- status SeoIssueStatus @default(open)
579
- fixable Boolean @default(false)
580
- fixActionType String?
564
+ id String @id @default(cuid())
565
+ auditRunId String?
566
+ issueKey String
567
+ entityType String?
568
+ entityId String?
569
+ entityTitle String?
570
+ url String?
571
+ severity SeoIssueSeverity
572
+ category SeoIssueCategory
573
+ type String
574
+ title String
575
+ description String?
576
+ impact String?
577
+ recommendation String?
578
+ status SeoIssueStatus @default(open)
579
+ fixable Boolean @default(false)
580
+ fixActionType String?
581
581
  relatedEntityIds Json?
582
- source String @default("audit")
583
- firstDetectedAt DateTime @default(now())
584
- lastDetectedAt DateTime @default(now())
585
- resolvedAt DateTime?
586
- resolvedById String?
587
- metadata Json?
582
+ source String @default("audit")
583
+ firstDetectedAt DateTime @default(now())
584
+ lastDetectedAt DateTime @default(now())
585
+ resolvedAt DateTime?
586
+ resolvedById String?
587
+ metadata Json?
588
588
 
589
589
  auditRun SeoAuditRun? @relation(fields: [auditRunId], references: [id], onDelete: SetNull)
590
590
 
@@ -599,13 +599,13 @@ model SeoIssue {
599
599
  /// A 404 hit observed by the redirect middleware. Aggregated per path so
600
600
  /// the Redirects tab can surface "broken URLs still getting traffic".
601
601
  model Redirect404Hit {
602
- id String @id @default(cuid())
603
- path String
604
- hits Int @default(1)
605
- referrer String?
606
- resolvedAt DateTime?
607
- firstSeenAt DateTime @default(now())
608
- lastSeenAt DateTime @default(now())
602
+ id String @id @default(cuid())
603
+ path String
604
+ hits Int @default(1)
605
+ referrer String?
606
+ resolvedAt DateTime?
607
+ firstSeenAt DateTime @default(now())
608
+ lastSeenAt DateTime @default(now())
609
609
 
610
610
  @@unique([path])
611
611
  @@index([lastSeenAt])
@@ -632,20 +632,115 @@ model RedirectSuggestion {
632
632
  @@map("actuate_redirect_suggestions")
633
633
  }
634
634
 
635
- model FormSubmission {
635
+ // A versioned snapshot of a form's field schema. Saving a form's schema in
636
+ // the admin creates a new row here; submissions reference the version they
637
+ // were captured against so historical entries always render with the fields
638
+ // that existed at submit time, even after the live form schema changes.
639
+ model FormSchemaVersion {
636
640
  id String @id @default(cuid())
637
641
  formId String
638
- data Json
639
- attribution Json?
640
- status String @default("new")
641
- submittedAt DateTime @default(now())
642
+ version Int
643
+ fields Json
644
+ notes String?
645
+ createdById String?
642
646
  createdAt DateTime @default(now())
643
647
 
648
+ @@unique([formId, version])
649
+ @@index([formId])
650
+ @@map("actuate_form_schema_versions")
651
+ }
652
+
653
+ model FormSubmission {
654
+ id String @id @default(cuid())
655
+ // Per-instance sequential number shown in the UI (e.g. #00001). Assigned by
656
+ // the submission service inside a transaction; nullable for legacy rows.
657
+ entryNumber Int?
658
+ formId String
659
+ schemaVersionId String?
660
+ data Json
661
+ // Server-derived, type-coerced view of `data` (e.g. checkbox -> bool,
662
+ // number -> number) used for export/search. `data` keeps the raw payload.
663
+ normalizedData Json?
664
+ attribution Json?
665
+ senderName String?
666
+ senderEmail String?
667
+ senderPhone String?
668
+ preview String?
669
+ // Legacy free-form status ('new'); superseded by the booleans below but
670
+ // retained so existing rows/integrations keep working.
671
+ status String @default("new")
672
+ unread Boolean @default(true)
673
+ starred Boolean @default(false)
674
+ archived Boolean @default(false)
675
+ spamStatus String @default("clean")
676
+ ipAddressHash String?
677
+ userAgent String?
678
+ referrer String?
679
+ pageUrl String?
680
+ utmSource String?
681
+ utmMedium String?
682
+ utmCampaign String?
683
+ submittedAt DateTime @default(now())
684
+ readAt DateTime?
685
+ archivedAt DateTime?
686
+ createdAt DateTime @default(now())
687
+ updatedAt DateTime @updatedAt
688
+
689
+ files FormSubmissionFile[]
690
+
644
691
  @@index([formId])
645
692
  @@index([status])
693
+ @@index([unread])
694
+ @@index([starred])
695
+ @@index([archived])
696
+ @@index([spamStatus])
697
+ @@index([submittedAt])
698
+ @@index([senderEmail])
646
699
  @@map("actuate_form_submissions")
647
700
  }
648
701
 
702
+ // File attachments for a submission. Files are stored via the configured
703
+ // storage adapter (never inline in the DB); this row tracks metadata and the
704
+ // storage key needed to mint a secure download link.
705
+ model FormSubmissionFile {
706
+ id String @id @default(cuid())
707
+ submissionId String
708
+ fieldKey String
709
+ mediaAssetId String?
710
+ fileName String
711
+ mimeType String
712
+ sizeBytes Int
713
+ storageKey String
714
+ publicUrl String?
715
+ secureDownloadUrl String?
716
+ createdAt DateTime @default(now())
717
+
718
+ submission FormSubmission @relation(fields: [submissionId], references: [id], onDelete: Cascade)
719
+
720
+ @@index([submissionId])
721
+ @@map("actuate_form_submission_files")
722
+ }
723
+
724
+ // Per-form outbound webhook configuration. Distinct from the global
725
+ // WebhookEndpoint registry so form owners can wire delivery without admin
726
+ // access to site-wide webhooks.
727
+ model FormWebhook {
728
+ id String @id @default(cuid())
729
+ formId String
730
+ url String
731
+ secret String
732
+ enabled Boolean @default(true)
733
+ events Json
734
+ retryCount Int @default(0)
735
+ lastDeliveryAt DateTime?
736
+ lastDeliveryStatus String?
737
+ createdAt DateTime @default(now())
738
+ updatedAt DateTime @updatedAt
739
+
740
+ @@index([formId])
741
+ @@map("actuate_form_webhooks")
742
+ }
743
+
649
744
  model BackupRecord {
650
745
  id String @id @default(cuid())
651
746
  filename String