@antelopejs/dms-saas 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +658 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.js +20 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth-entry.d.ts +5 -0
- package/dist/auth/oauth-entry.js +10 -0
- package/dist/auth/oauth-entry.js.map +1 -0
- package/dist/auth/plan-permissions-resolver.d.ts +1 -0
- package/dist/auth/plan-permissions-resolver.js +44 -0
- package/dist/auth/plan-permissions-resolver.js.map +1 -0
- package/dist/auth/subscription-access-gate.d.ts +8 -0
- package/dist/auth/subscription-access-gate.js +38 -0
- package/dist/auth/subscription-access-gate.js.map +1 -0
- package/dist/automation/index.d.ts +44 -0
- package/dist/automation/index.js +209 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/billing-state/index.d.ts +5 -0
- package/dist/billing-state/index.js +58 -0
- package/dist/billing-state/index.js.map +1 -0
- package/dist/billing-state/recovery.d.ts +22 -0
- package/dist/billing-state/recovery.js +81 -0
- package/dist/billing-state/recovery.js.map +1 -0
- package/dist/config/dev-mode.d.ts +3 -0
- package/dist/config/dev-mode.js +27 -0
- package/dist/config/dev-mode.js.map +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/runtime.d.ts +6 -0
- package/dist/config/runtime.js +54 -0
- package/dist/config/runtime.js.map +1 -0
- package/dist/crons/auto-suspend-past-due.d.ts +2 -0
- package/dist/crons/auto-suspend-past-due.js +43 -0
- package/dist/crons/auto-suspend-past-due.js.map +1 -0
- package/dist/crons/cleanup-stripe-webhook-events.d.ts +2 -0
- package/dist/crons/cleanup-stripe-webhook-events.js +27 -0
- package/dist/crons/cleanup-stripe-webhook-events.js.map +1 -0
- package/dist/crons/expire-free-workspaces.d.ts +2 -0
- package/dist/crons/expire-free-workspaces.js +36 -0
- package/dist/crons/expire-free-workspaces.js.map +1 -0
- package/dist/crons/hard-delete-cancelled.d.ts +2 -0
- package/dist/crons/hard-delete-cancelled.js +55 -0
- package/dist/crons/hard-delete-cancelled.js.map +1 -0
- package/dist/crons/index.d.ts +8 -0
- package/dist/crons/index.js +25 -0
- package/dist/crons/index.js.map +1 -0
- package/dist/crons/notify-free-workspaces-ending-soon.d.ts +2 -0
- package/dist/crons/notify-free-workspaces-ending-soon.js +69 -0
- package/dist/crons/notify-free-workspaces-ending-soon.js.map +1 -0
- package/dist/crons/recompute-billing-state.d.ts +2 -0
- package/dist/crons/recompute-billing-state.js +19 -0
- package/dist/crons/recompute-billing-state.js.map +1 -0
- package/dist/crons/recompute-segments.d.ts +2 -0
- package/dist/crons/recompute-segments.js +19 -0
- package/dist/crons/recompute-segments.js.map +1 -0
- package/dist/crons/reconcile-workspace-lifecycle.d.ts +2 -0
- package/dist/crons/reconcile-workspace-lifecycle.js +19 -0
- package/dist/crons/reconcile-workspace-lifecycle.js.map +1 -0
- package/dist/crons/register.d.ts +2 -0
- package/dist/crons/register.js +24 -0
- package/dist/crons/register.js.map +1 -0
- package/dist/crons/subscription-notifications.d.ts +2 -0
- package/dist/crons/subscription-notifications.js +55 -0
- package/dist/crons/subscription-notifications.js.map +1 -0
- package/dist/data-api/index.d.ts +2 -0
- package/dist/data-api/index.js +19 -0
- package/dist/data-api/index.js.map +1 -0
- package/dist/data-api/platformOwner/admin-user-invoices.d.ts +27 -0
- package/dist/data-api/platformOwner/admin-user-invoices.js +158 -0
- package/dist/data-api/platformOwner/admin-user-invoices.js.map +1 -0
- package/dist/data-api/platformOwner/admin-user-workspaces.d.ts +22 -0
- package/dist/data-api/platformOwner/admin-user-workspaces.js +97 -0
- package/dist/data-api/platformOwner/admin-user-workspaces.js.map +1 -0
- package/dist/data-api/platformOwner/credit-notes.d.ts +24 -0
- package/dist/data-api/platformOwner/credit-notes.js +133 -0
- package/dist/data-api/platformOwner/credit-notes.js.map +1 -0
- package/dist/data-api/platformOwner/features.d.ts +30 -0
- package/dist/data-api/platformOwner/features.js +141 -0
- package/dist/data-api/platformOwner/features.js.map +1 -0
- package/dist/data-api/platformOwner/hidden-filter.d.ts +1 -0
- package/dist/data-api/platformOwner/hidden-filter.js +18 -0
- package/dist/data-api/platformOwner/hidden-filter.js.map +1 -0
- package/dist/data-api/platformOwner/index.d.ts +12 -0
- package/dist/data-api/platformOwner/index.js +29 -0
- package/dist/data-api/platformOwner/index.js.map +1 -0
- package/dist/data-api/platformOwner/invoice-options.d.ts +7 -0
- package/dist/data-api/platformOwner/invoice-options.js +14 -0
- package/dist/data-api/platformOwner/invoice-options.js.map +1 -0
- package/dist/data-api/platformOwner/invoices.d.ts +26 -0
- package/dist/data-api/platformOwner/invoices.js +147 -0
- package/dist/data-api/platformOwner/invoices.js.map +1 -0
- package/dist/data-api/platformOwner/members.d.ts +24 -0
- package/dist/data-api/platformOwner/members.js +125 -0
- package/dist/data-api/platformOwner/members.js.map +1 -0
- package/dist/data-api/platformOwner/plan-migrations.d.ts +24 -0
- package/dist/data-api/platformOwner/plan-migrations.js +138 -0
- package/dist/data-api/platformOwner/plan-migrations.js.map +1 -0
- package/dist/data-api/platformOwner/plans.d.ts +30 -0
- package/dist/data-api/platformOwner/plans.js +228 -0
- package/dist/data-api/platformOwner/plans.js.map +1 -0
- package/dist/data-api/platformOwner/segments.d.ts +29 -0
- package/dist/data-api/platformOwner/segments.js +223 -0
- package/dist/data-api/platformOwner/segments.js.map +1 -0
- package/dist/data-api/platformOwner/support.d.ts +58 -0
- package/dist/data-api/platformOwner/support.js +111 -0
- package/dist/data-api/platformOwner/support.js.map +1 -0
- package/dist/data-api/platformOwner/users.d.ts +22 -0
- package/dist/data-api/platformOwner/users.js +128 -0
- package/dist/data-api/platformOwner/users.js.map +1 -0
- package/dist/data-api/platformOwner/workspaces.d.ts +22 -0
- package/dist/data-api/platformOwner/workspaces.js +153 -0
- package/dist/data-api/platformOwner/workspaces.js.map +1 -0
- package/dist/data-api/support-fields.d.ts +49 -0
- package/dist/data-api/support-fields.js +166 -0
- package/dist/data-api/support-fields.js.map +1 -0
- package/dist/data-api/support-routes.d.ts +10 -0
- package/dist/data-api/support-routes.js +71 -0
- package/dist/data-api/support-routes.js.map +1 -0
- package/dist/data-api/tenant/index.d.ts +2 -0
- package/dist/data-api/tenant/index.js +19 -0
- package/dist/data-api/tenant/index.js.map +1 -0
- package/dist/data-api/tenant/support.d.ts +39 -0
- package/dist/data-api/tenant/support.js +53 -0
- package/dist/data-api/tenant/support.js.map +1 -0
- package/dist/data-api/tenant/tenant-invoices.d.ts +37 -0
- package/dist/data-api/tenant/tenant-invoices.js +242 -0
- package/dist/data-api/tenant/tenant-invoices.js.map +1 -0
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.js +18 -0
- package/dist/db/index.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +20 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/register.d.ts +1 -0
- package/dist/hooks/register.js +57 -0
- package/dist/hooks/register.js.map +1 -0
- package/dist/hooks/tenant-export.d.ts +2 -0
- package/dist/hooks/tenant-export.js +64 -0
- package/dist/hooks/tenant-export.js.map +1 -0
- package/dist/hooks/tenant-provisioning.d.ts +3 -0
- package/dist/hooks/tenant-provisioning.js +12 -0
- package/dist/hooks/tenant-provisioning.js.map +1 -0
- package/dist/implementations/dms-saas/billing.d.ts +2 -0
- package/dist/implementations/dms-saas/billing.js +49 -0
- package/dist/implementations/dms-saas/billing.js.map +1 -0
- package/dist/implementations/dms-saas/invoice-line-items.d.ts +11 -0
- package/dist/implementations/dms-saas/invoice-line-items.js +24 -0
- package/dist/implementations/dms-saas/invoice-line-items.js.map +1 -0
- package/dist/implementations/dms-saas/pages.d.ts +3 -0
- package/dist/implementations/dms-saas/pages.js +12 -0
- package/dist/implementations/dms-saas/pages.js.map +1 -0
- package/dist/implementations/dms-saas/workspace-lifecycle.d.ts +2 -0
- package/dist/implementations/dms-saas/workspace-lifecycle.js +23 -0
- package/dist/implementations/dms-saas/workspace-lifecycle.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +107 -0
- package/dist/index.js.map +1 -0
- package/dist/invoice-line-items/billing-window.d.ts +3 -0
- package/dist/invoice-line-items/billing-window.js +19 -0
- package/dist/invoice-line-items/billing-window.js.map +1 -0
- package/dist/invoice-line-items/index.d.ts +1 -0
- package/dist/invoice-line-items/index.js +18 -0
- package/dist/invoice-line-items/index.js.map +1 -0
- package/dist/invoice-line-items/injection.d.ts +2 -0
- package/dist/invoice-line-items/injection.js +171 -0
- package/dist/invoice-line-items/injection.js.map +1 -0
- package/dist/notifications/index.d.ts +2 -0
- package/dist/notifications/index.js +19 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/recipients.d.ts +14 -0
- package/dist/notifications/recipients.js +87 -0
- package/dist/notifications/recipients.js.map +1 -0
- package/dist/notifications/subjects.d.ts +21 -0
- package/dist/notifications/subjects.js +121 -0
- package/dist/notifications/subjects.js.map +1 -0
- package/dist/operator-actions/commands.d.ts +41 -0
- package/dist/operator-actions/commands.js +233 -0
- package/dist/operator-actions/commands.js.map +1 -0
- package/dist/operator-actions/db/index.d.ts +4 -0
- package/dist/operator-actions/db/index.js +21 -0
- package/dist/operator-actions/db/index.js.map +1 -0
- package/dist/operator-actions/db/lifecycle-delivery.model.d.ts +29 -0
- package/dist/operator-actions/db/lifecycle-delivery.model.js +85 -0
- package/dist/operator-actions/db/lifecycle-delivery.model.js.map +1 -0
- package/dist/operator-actions/db/lifecycle-delivery.table.d.ts +26 -0
- package/dist/operator-actions/db/lifecycle-delivery.table.js +107 -0
- package/dist/operator-actions/db/lifecycle-delivery.table.js.map +1 -0
- package/dist/operator-actions/db/operator-action.model.d.ts +33 -0
- package/dist/operator-actions/db/operator-action.model.js +63 -0
- package/dist/operator-actions/db/operator-action.model.js.map +1 -0
- package/dist/operator-actions/db/operator-action.table.d.ts +21 -0
- package/dist/operator-actions/db/operator-action.table.js +95 -0
- package/dist/operator-actions/db/operator-action.table.js.map +1 -0
- package/dist/operator-actions/index.d.ts +3 -0
- package/dist/operator-actions/index.js +20 -0
- package/dist/operator-actions/index.js.map +1 -0
- package/dist/operator-actions/journal.d.ts +22 -0
- package/dist/operator-actions/journal.js +183 -0
- package/dist/operator-actions/journal.js.map +1 -0
- package/dist/operator-actions/lifecycle-consumers.d.ts +12 -0
- package/dist/operator-actions/lifecycle-consumers.js +28 -0
- package/dist/operator-actions/lifecycle-consumers.js.map +1 -0
- package/dist/operator-actions/lifecycle-outbox.d.ts +19 -0
- package/dist/operator-actions/lifecycle-outbox.js +229 -0
- package/dist/operator-actions/lifecycle-outbox.js.map +1 -0
- package/dist/operator-actions/types.d.ts +11 -0
- package/dist/operator-actions/types.js +3 -0
- package/dist/operator-actions/types.js.map +1 -0
- package/dist/pages/definitions.d.ts +1 -0
- package/dist/pages/definitions.js +18 -0
- package/dist/pages/definitions.js.map +1 -0
- package/dist/pages/index.d.ts +4 -0
- package/dist/pages/index.js +21 -0
- package/dist/pages/index.js.map +1 -0
- package/dist/pages/module.d.ts +5 -0
- package/dist/pages/module.js +15 -0
- package/dist/pages/module.js.map +1 -0
- package/dist/pages/platform/categories.d.ts +6 -0
- package/dist/pages/platform/categories.js +48 -0
- package/dist/pages/platform/categories.js.map +1 -0
- package/dist/pages/platform/credit-notes.d.ts +9 -0
- package/dist/pages/platform/credit-notes.js +40 -0
- package/dist/pages/platform/credit-notes.js.map +1 -0
- package/dist/pages/platform/dashboard.d.ts +10 -0
- package/dist/pages/platform/dashboard.js +95 -0
- package/dist/pages/platform/dashboard.js.map +1 -0
- package/dist/pages/platform/features.d.ts +9 -0
- package/dist/pages/platform/features.js +42 -0
- package/dist/pages/platform/features.js.map +1 -0
- package/dist/pages/platform/index.d.ts +15 -0
- package/dist/pages/platform/index.js +32 -0
- package/dist/pages/platform/index.js.map +1 -0
- package/dist/pages/platform/invoices.d.ts +9 -0
- package/dist/pages/platform/invoices.js +63 -0
- package/dist/pages/platform/invoices.js.map +1 -0
- package/dist/pages/platform/plans/edit.d.ts +17 -0
- package/dist/pages/platform/plans/edit.js +213 -0
- package/dist/pages/platform/plans/edit.js.map +1 -0
- package/dist/pages/platform/plans/index.d.ts +9 -0
- package/dist/pages/platform/plans/index.js +99 -0
- package/dist/pages/platform/plans/index.js.map +1 -0
- package/dist/pages/platform/plans/migrations.d.ts +9 -0
- package/dist/pages/platform/plans/migrations.js +38 -0
- package/dist/pages/platform/plans/migrations.js.map +1 -0
- package/dist/pages/platform/segments/index.d.ts +9 -0
- package/dist/pages/platform/segments/index.js +59 -0
- package/dist/pages/platform/segments/index.js.map +1 -0
- package/dist/pages/platform/settings.d.ts +9 -0
- package/dist/pages/platform/settings.js +147 -0
- package/dist/pages/platform/settings.js.map +1 -0
- package/dist/pages/platform/support.d.ts +9 -0
- package/dist/pages/platform/support.js +29 -0
- package/dist/pages/platform/support.js.map +1 -0
- package/dist/pages/platform/users/detail.d.ts +9 -0
- package/dist/pages/platform/users/detail.js +78 -0
- package/dist/pages/platform/users/detail.js.map +1 -0
- package/dist/pages/platform/users/index.d.ts +9 -0
- package/dist/pages/platform/users/index.js +77 -0
- package/dist/pages/platform/users/index.js.map +1 -0
- package/dist/pages/platform/workspaces/detail.d.ts +9 -0
- package/dist/pages/platform/workspaces/detail.js +120 -0
- package/dist/pages/platform/workspaces/detail.js.map +1 -0
- package/dist/pages/platform/workspaces/index.d.ts +35 -0
- package/dist/pages/platform/workspaces/index.js +300 -0
- package/dist/pages/platform/workspaces/index.js.map +1 -0
- package/dist/pages/public/auth/index.d.ts +1 -0
- package/dist/pages/public/auth/index.js +18 -0
- package/dist/pages/public/auth/index.js.map +1 -0
- package/dist/pages/public/auth/no-workspace.d.ts +9 -0
- package/dist/pages/public/auth/no-workspace.js +26 -0
- package/dist/pages/public/auth/no-workspace.js.map +1 -0
- package/dist/pages/public/index.d.ts +3 -0
- package/dist/pages/public/index.js +20 -0
- package/dist/pages/public/index.js.map +1 -0
- package/dist/pages/public/legal/index.d.ts +3 -0
- package/dist/pages/public/legal/index.js +20 -0
- package/dist/pages/public/legal/index.js.map +1 -0
- package/dist/pages/public/legal/privacy-policy.d.ts +9 -0
- package/dist/pages/public/legal/privacy-policy.js +29 -0
- package/dist/pages/public/legal/privacy-policy.js.map +1 -0
- package/dist/pages/public/legal/terms-and-conditions.d.ts +9 -0
- package/dist/pages/public/legal/terms-and-conditions.js +29 -0
- package/dist/pages/public/legal/terms-and-conditions.js.map +1 -0
- package/dist/pages/public/legal/terms-of-use.d.ts +9 -0
- package/dist/pages/public/legal/terms-of-use.js +29 -0
- package/dist/pages/public/legal/terms-of-use.js.map +1 -0
- package/dist/pages/public/register.d.ts +9 -0
- package/dist/pages/public/register.js +29 -0
- package/dist/pages/public/register.js.map +1 -0
- package/dist/pages/public/screens.d.ts +3 -0
- package/dist/pages/public/screens.js +50 -0
- package/dist/pages/public/screens.js.map +1 -0
- package/dist/pages/tenant/billing.d.ts +15 -0
- package/dist/pages/tenant/billing.js +87 -0
- package/dist/pages/tenant/billing.js.map +1 -0
- package/dist/pages/tenant/data-export.d.ts +10 -0
- package/dist/pages/tenant/data-export.js +32 -0
- package/dist/pages/tenant/data-export.js.map +1 -0
- package/dist/pages/tenant/general.d.ts +10 -0
- package/dist/pages/tenant/general.js +33 -0
- package/dist/pages/tenant/general.js.map +1 -0
- package/dist/pages/tenant/index.d.ts +6 -0
- package/dist/pages/tenant/index.js +23 -0
- package/dist/pages/tenant/index.js.map +1 -0
- package/dist/pages/tenant/members-seat-quota.d.ts +3 -0
- package/dist/pages/tenant/members-seat-quota.js +25 -0
- package/dist/pages/tenant/members-seat-quota.js.map +1 -0
- package/dist/pages/tenant/support.d.ts +9 -0
- package/dist/pages/tenant/support.js +27 -0
- package/dist/pages/tenant/support.js.map +1 -0
- package/dist/pages/tenant/workspace-suspended.d.ts +9 -0
- package/dist/pages/tenant/workspace-suspended.js +26 -0
- package/dist/pages/tenant/workspace-suspended.js.map +1 -0
- package/dist/plan-changes/deferred.d.ts +18 -0
- package/dist/plan-changes/deferred.js +225 -0
- package/dist/plan-changes/deferred.js.map +1 -0
- package/dist/plan-changes/index.d.ts +1 -0
- package/dist/plan-changes/index.js +18 -0
- package/dist/plan-changes/index.js.map +1 -0
- package/dist/plans/index.d.ts +4 -0
- package/dist/plans/index.js +21 -0
- package/dist/plans/index.js.map +1 -0
- package/dist/plans/seat-capacity.d.ts +9 -0
- package/dist/plans/seat-capacity.js +38 -0
- package/dist/plans/seat-capacity.js.map +1 -0
- package/dist/plans/seat-hooks.d.ts +1 -0
- package/dist/plans/seat-hooks.js +80 -0
- package/dist/plans/seat-hooks.js.map +1 -0
- package/dist/plans/seat-sync.d.ts +10 -0
- package/dist/plans/seat-sync.js +23 -0
- package/dist/plans/seat-sync.js.map +1 -0
- package/dist/routes/index.d.ts +3 -0
- package/dist/routes/index.js +20 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/platformOwner/billing-settings.d.ts +20 -0
- package/dist/routes/platformOwner/billing-settings.js +98 -0
- package/dist/routes/platformOwner/billing-settings.js.map +1 -0
- package/dist/routes/platformOwner/credit-notes-issue.d.ts +16 -0
- package/dist/routes/platformOwner/credit-notes-issue.js +56 -0
- package/dist/routes/platformOwner/credit-notes-issue.js.map +1 -0
- package/dist/routes/platformOwner/dashboard.d.ts +62 -0
- package/dist/routes/platformOwner/dashboard.js +310 -0
- package/dist/routes/platformOwner/dashboard.js.map +1 -0
- package/dist/routes/platformOwner/index.d.ts +12 -0
- package/dist/routes/platformOwner/index.js +29 -0
- package/dist/routes/platformOwner/index.js.map +1 -0
- package/dist/routes/platformOwner/plan-deletion.d.ts +30 -0
- package/dist/routes/platformOwner/plan-deletion.js +156 -0
- package/dist/routes/platformOwner/plan-deletion.js.map +1 -0
- package/dist/routes/platformOwner/plans.d.ts +99 -0
- package/dist/routes/platformOwner/plans.js +376 -0
- package/dist/routes/platformOwner/plans.js.map +1 -0
- package/dist/routes/platformOwner/platform-notes.d.ts +36 -0
- package/dist/routes/platformOwner/platform-notes.js +149 -0
- package/dist/routes/platformOwner/platform-notes.js.map +1 -0
- package/dist/routes/platformOwner/platform-owners.d.ts +12 -0
- package/dist/routes/platformOwner/platform-owners.js +77 -0
- package/dist/routes/platformOwner/platform-owners.js.map +1 -0
- package/dist/routes/platformOwner/segments.d.ts +24 -0
- package/dist/routes/platformOwner/segments.js +174 -0
- package/dist/routes/platformOwner/segments.js.map +1 -0
- package/dist/routes/platformOwner/support.d.ts +21 -0
- package/dist/routes/platformOwner/support.js +180 -0
- package/dist/routes/platformOwner/support.js.map +1 -0
- package/dist/routes/platformOwner/users-detail.d.ts +26 -0
- package/dist/routes/platformOwner/users-detail.js +82 -0
- package/dist/routes/platformOwner/users-detail.js.map +1 -0
- package/dist/routes/platformOwner/workspace-operator-actions.d.ts +34 -0
- package/dist/routes/platformOwner/workspace-operator-actions.js +183 -0
- package/dist/routes/platformOwner/workspace-operator-actions.js.map +1 -0
- package/dist/routes/platformOwner/workspaces-admin.d.ts +27 -0
- package/dist/routes/platformOwner/workspaces-admin.js +140 -0
- package/dist/routes/platformOwner/workspaces-admin.js.map +1 -0
- package/dist/routes/public/index.d.ts +3 -0
- package/dist/routes/public/index.js +20 -0
- package/dist/routes/public/index.js.map +1 -0
- package/dist/routes/public/legal-documents.d.ts +15 -0
- package/dist/routes/public/legal-documents.js +72 -0
- package/dist/routes/public/legal-documents.js.map +1 -0
- package/dist/routes/public/register.d.ts +48 -0
- package/dist/routes/public/register.js +193 -0
- package/dist/routes/public/register.js.map +1 -0
- package/dist/routes/public/webhooks/index.d.ts +1 -0
- package/dist/routes/public/webhooks/index.js +18 -0
- package/dist/routes/public/webhooks/index.js.map +1 -0
- package/dist/routes/public/webhooks/stripe.d.ts +7 -0
- package/dist/routes/public/webhooks/stripe.js +41 -0
- package/dist/routes/public/webhooks/stripe.js.map +1 -0
- package/dist/routes/tenant/billing-portal.d.ts +31 -0
- package/dist/routes/tenant/billing-portal.js +117 -0
- package/dist/routes/tenant/billing-portal.js.map +1 -0
- package/dist/routes/tenant/billing-self-refund.d.ts +18 -0
- package/dist/routes/tenant/billing-self-refund.js +199 -0
- package/dist/routes/tenant/billing-self-refund.js.map +1 -0
- package/dist/routes/tenant/data-export.d.ts +16 -0
- package/dist/routes/tenant/data-export.js +102 -0
- package/dist/routes/tenant/data-export.js.map +1 -0
- package/dist/routes/tenant/index.d.ts +9 -0
- package/dist/routes/tenant/index.js +26 -0
- package/dist/routes/tenant/index.js.map +1 -0
- package/dist/routes/tenant/support.d.ts +27 -0
- package/dist/routes/tenant/support.js +185 -0
- package/dist/routes/tenant/support.js.map +1 -0
- package/dist/routes/tenant/tenant-billing.d.ts +26 -0
- package/dist/routes/tenant/tenant-billing.js +148 -0
- package/dist/routes/tenant/tenant-billing.js.map +1 -0
- package/dist/routes/tenant/tenant-plan-ops.d.ts +57 -0
- package/dist/routes/tenant/tenant-plan-ops.js +244 -0
- package/dist/routes/tenant/tenant-plan-ops.js.map +1 -0
- package/dist/routes/tenant/tenant-plan.d.ts +19 -0
- package/dist/routes/tenant/tenant-plan.js +172 -0
- package/dist/routes/tenant/tenant-plan.js.map +1 -0
- package/dist/routes/tenant/tenant-seats.d.ts +17 -0
- package/dist/routes/tenant/tenant-seats.js +58 -0
- package/dist/routes/tenant/tenant-seats.js.map +1 -0
- package/dist/routes/tenant/workspaces.d.ts +78 -0
- package/dist/routes/tenant/workspaces.js +301 -0
- package/dist/routes/tenant/workspaces.js.map +1 -0
- package/dist/stripe/client.d.ts +6 -0
- package/dist/stripe/client.js +44 -0
- package/dist/stripe/client.js.map +1 -0
- package/dist/stripe/customer-balance.d.ts +12 -0
- package/dist/stripe/customer-balance.js +16 -0
- package/dist/stripe/customer-balance.js.map +1 -0
- package/dist/stripe/customer-billing.d.ts +33 -0
- package/dist/stripe/customer-billing.js +140 -0
- package/dist/stripe/customer-billing.js.map +1 -0
- package/dist/stripe/index.d.ts +11 -0
- package/dist/stripe/index.js +28 -0
- package/dist/stripe/index.js.map +1 -0
- package/dist/stripe/plan-schedule.d.ts +9 -0
- package/dist/stripe/plan-schedule.js +83 -0
- package/dist/stripe/plan-schedule.js.map +1 -0
- package/dist/stripe/proration.d.ts +2 -0
- package/dist/stripe/proration.js +19 -0
- package/dist/stripe/proration.js.map +1 -0
- package/dist/stripe/sync-plan.d.ts +2 -0
- package/dist/stripe/sync-plan.js +66 -0
- package/dist/stripe/sync-plan.js.map +1 -0
- package/dist/stripe/webhook-checkout.d.ts +3 -0
- package/dist/stripe/webhook-checkout.js +157 -0
- package/dist/stripe/webhook-checkout.js.map +1 -0
- package/dist/stripe/webhook-credit-notes.d.ts +3 -0
- package/dist/stripe/webhook-credit-notes.js +192 -0
- package/dist/stripe/webhook-credit-notes.js.map +1 -0
- package/dist/stripe/webhook-dispatch.d.ts +2 -0
- package/dist/stripe/webhook-dispatch.js +45 -0
- package/dist/stripe/webhook-dispatch.js.map +1 -0
- package/dist/stripe/webhook-handlers.d.ts +11 -0
- package/dist/stripe/webhook-handlers.js +318 -0
- package/dist/stripe/webhook-handlers.js.map +1 -0
- package/dist/stripe/webhook-shared.d.ts +28 -0
- package/dist/stripe/webhook-shared.js +126 -0
- package/dist/stripe/webhook-shared.js.map +1 -0
- package/dist/stripe/workspace-checkout.d.ts +29 -0
- package/dist/stripe/workspace-checkout.js +106 -0
- package/dist/stripe/workspace-checkout.js.map +1 -0
- package/dist/support/admissions.d.ts +36 -0
- package/dist/support/admissions.js +136 -0
- package/dist/support/admissions.js.map +1 -0
- package/dist/support/attachments.d.ts +12 -0
- package/dist/support/attachments.js +56 -0
- package/dist/support/attachments.js.map +1 -0
- package/dist/support/config.d.ts +19 -0
- package/dist/support/config.js +75 -0
- package/dist/support/config.js.map +1 -0
- package/dist/support/index.d.ts +6 -0
- package/dist/support/index.js +23 -0
- package/dist/support/index.js.map +1 -0
- package/dist/support/operations.d.ts +51 -0
- package/dist/support/operations.js +109 -0
- package/dist/support/operations.js.map +1 -0
- package/dist/support/plans.d.ts +6 -0
- package/dist/support/plans.js +130 -0
- package/dist/support/plans.js.map +1 -0
- package/dist/support/publications.d.ts +8 -0
- package/dist/support/publications.js +106 -0
- package/dist/support/publications.js.map +1 -0
- package/dist/support/recovery.d.ts +7 -0
- package/dist/support/recovery.js +43 -0
- package/dist/support/recovery.js.map +1 -0
- package/dist/support/service.d.ts +51 -0
- package/dist/support/service.js +143 -0
- package/dist/support/service.js.map +1 -0
- package/dist/support/transitions.d.ts +4 -0
- package/dist/support/transitions.js +29 -0
- package/dist/support/transitions.js.map +1 -0
- package/dist/support/uploads.d.ts +39 -0
- package/dist/support/uploads.js +115 -0
- package/dist/support/uploads.js.map +1 -0
- package/dist/support/validation.d.ts +15 -0
- package/dist/support/validation.js +54 -0
- package/dist/support/validation.js.map +1 -0
- package/dist/types/config.d.ts +16 -0
- package/dist/types/config.js +3 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +18 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/billing-document-type.d.ts +3 -0
- package/dist/utils/billing-document-type.js +18 -0
- package/dist/utils/billing-document-type.js.map +1 -0
- package/dist/utils/billing-period-type.d.ts +3 -0
- package/dist/utils/billing-period-type.js +18 -0
- package/dist/utils/billing-period-type.js.map +1 -0
- package/dist/utils/email-hash.d.ts +1 -0
- package/dist/utils/email-hash.js +8 -0
- package/dist/utils/email-hash.js.map +1 -0
- package/dist/utils/export-dataset-stream.d.ts +19 -0
- package/dist/utils/export-dataset-stream.js +40 -0
- package/dist/utils/export-dataset-stream.js.map +1 -0
- package/dist/utils/index.d.ts +15 -0
- package/dist/utils/index.js +32 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/invoice-lines-type.d.ts +27 -0
- package/dist/utils/invoice-lines-type.js +34 -0
- package/dist/utils/invoice-lines-type.js.map +1 -0
- package/dist/utils/money-cents-type.d.ts +3 -0
- package/dist/utils/money-cents-type.js +18 -0
- package/dist/utils/money-cents-type.js.map +1 -0
- package/dist/utils/pagination.d.ts +22 -0
- package/dist/utils/pagination.js +35 -0
- package/dist/utils/pagination.js.map +1 -0
- package/dist/utils/parse-future-date.d.ts +1 -0
- package/dist/utils/parse-future-date.js +15 -0
- package/dist/utils/parse-future-date.js.map +1 -0
- package/dist/utils/row-instance.d.ts +1 -0
- package/dist/utils/row-instance.js +8 -0
- package/dist/utils/row-instance.js.map +1 -0
- package/dist/utils/segment-conditions-type.d.ts +33 -0
- package/dist/utils/segment-conditions-type.js +86 -0
- package/dist/utils/segment-conditions-type.js.map +1 -0
- package/dist/utils/segment-evaluator.d.ts +3 -0
- package/dist/utils/segment-evaluator.js +117 -0
- package/dist/utils/segment-evaluator.js.map +1 -0
- package/dist/utils/segment-fields.d.ts +19 -0
- package/dist/utils/segment-fields.js +212 -0
- package/dist/utils/segment-fields.js.map +1 -0
- package/dist/utils/segment-matching.d.ts +56 -0
- package/dist/utils/segment-matching.js +200 -0
- package/dist/utils/segment-matching.js.map +1 -0
- package/dist/utils/segment-name-cache.d.ts +2 -0
- package/dist/utils/segment-name-cache.js +22 -0
- package/dist/utils/segment-name-cache.js.map +1 -0
- package/dist/utils/time.d.ts +3 -0
- package/dist/utils/time.js +10 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/workers/index.d.ts +1 -0
- package/dist/workers/index.js +18 -0
- package/dist/workers/index.js.map +1 -0
- package/dist/workers/plan-migration.d.ts +4 -0
- package/dist/workers/plan-migration.js +206 -0
- package/dist/workers/plan-migration.js.map +1 -0
- package/dist/workspaces/billing-profile.d.ts +3 -0
- package/dist/workspaces/billing-profile.js +55 -0
- package/dist/workspaces/billing-profile.js.map +1 -0
- package/dist/workspaces/complimentary.d.ts +7 -0
- package/dist/workspaces/complimentary.js +47 -0
- package/dist/workspaces/complimentary.js.map +1 -0
- package/dist/workspaces/db/card-capacity.model.d.ts +30 -0
- package/dist/workspaces/db/card-capacity.model.js +98 -0
- package/dist/workspaces/db/card-capacity.model.js.map +1 -0
- package/dist/workspaces/db/card-capacity.table.d.ts +11 -0
- package/dist/workspaces/db/card-capacity.table.js +34 -0
- package/dist/workspaces/db/card-capacity.table.js.map +1 -0
- package/dist/workspaces/db/provisioning-attempt.model.d.ts +24 -0
- package/dist/workspaces/db/provisioning-attempt.model.js +33 -0
- package/dist/workspaces/db/provisioning-attempt.model.js.map +1 -0
- package/dist/workspaces/db/provisioning-attempt.table.d.ts +18 -0
- package/dist/workspaces/db/provisioning-attempt.table.js +77 -0
- package/dist/workspaces/db/provisioning-attempt.table.js.map +1 -0
- package/dist/workspaces/db/trial-identity.model.d.ts +25 -0
- package/dist/workspaces/db/trial-identity.model.js +62 -0
- package/dist/workspaces/db/trial-identity.model.js.map +1 -0
- package/dist/workspaces/db/trial-identity.table.d.ts +7 -0
- package/dist/workspaces/db/trial-identity.table.js +34 -0
- package/dist/workspaces/db/trial-identity.table.js.map +1 -0
- package/dist/workspaces/deletion.d.ts +8 -0
- package/dist/workspaces/deletion.js +75 -0
- package/dist/workspaces/deletion.js.map +1 -0
- package/dist/workspaces/free-workspace-guard.d.ts +11 -0
- package/dist/workspaces/free-workspace-guard.js +96 -0
- package/dist/workspaces/free-workspace-guard.js.map +1 -0
- package/dist/workspaces/index.d.ts +6 -0
- package/dist/workspaces/index.js +23 -0
- package/dist/workspaces/index.js.map +1 -0
- package/dist/workspaces/provisioning-rollback.d.ts +2 -0
- package/dist/workspaces/provisioning-rollback.js +78 -0
- package/dist/workspaces/provisioning-rollback.js.map +1 -0
- package/dist/workspaces/provisioning-state.d.ts +6 -0
- package/dist/workspaces/provisioning-state.js +91 -0
- package/dist/workspaces/provisioning-state.js.map +1 -0
- package/dist/workspaces/provisioning.d.ts +49 -0
- package/dist/workspaces/provisioning.js +263 -0
- package/dist/workspaces/provisioning.js.map +1 -0
- package/dist/workspaces/registration-extras.d.ts +1 -0
- package/dist/workspaces/registration-extras.js +50 -0
- package/dist/workspaces/registration-extras.js.map +1 -0
- package/dist/workspaces/suspension.d.ts +13 -0
- package/dist/workspaces/suspension.js +124 -0
- package/dist/workspaces/suspension.js.map +1 -0
- package/frontend-vue/.editorconfig +12 -0
- package/frontend-vue/.prettierrc +11 -0
- package/frontend-vue/app/build/.gitkeep +0 -0
- package/frontend-vue/app/components/CardGrid.vue +77 -0
- package/frontend-vue/app/components/CustomerPortalButton.vue +45 -0
- package/frontend-vue/app/components/DataExport.vue +300 -0
- package/frontend-vue/app/components/DeletePlanModal.vue +223 -0
- package/frontend-vue/app/components/FreeAccessBanner.vue +70 -0
- package/frontend-vue/app/components/InvoiceLines.vue +57 -0
- package/frontend-vue/app/components/IssueCreditNoteModal.vue +128 -0
- package/frontend-vue/app/components/LegalLayout.vue +63 -0
- package/frontend-vue/app/components/LoadFailure.vue +25 -0
- package/frontend-vue/app/components/PastDueAlert.vue +96 -0
- package/frontend-vue/app/components/PaymentMethodCard.vue +86 -0
- package/frontend-vue/app/components/PlanCard.vue +294 -0
- package/frontend-vue/app/components/PlanCardPublic.vue +59 -0
- package/frontend-vue/app/components/PlanCardsDisplay.vue +127 -0
- package/frontend-vue/app/components/PlanComparisonModal.vue +213 -0
- package/frontend-vue/app/components/PlanInheritancePicker.vue +329 -0
- package/frontend-vue/app/components/PlatformNotes.vue +281 -0
- package/frontend-vue/app/components/PlatformSupport.vue +461 -0
- package/frontend-vue/app/components/RecentActivity.vue +72 -0
- package/frontend-vue/app/components/RefundButton.vue +126 -0
- package/frontend-vue/app/components/Register.vue +174 -0
- package/frontend-vue/app/components/RegistrationClosed.vue +15 -0
- package/frontend-vue/app/components/SeatQuotaBanner.vue +78 -0
- package/frontend-vue/app/components/SegmentConditionsBuilder.vue +176 -0
- package/frontend-vue/app/components/SegmentConditionsGroup.vue +494 -0
- package/frontend-vue/app/components/SupportAttachmentUpload.vue +140 -0
- package/frontend-vue/app/components/SupportThreadHistory.vue +139 -0
- package/frontend-vue/app/components/TenantBillingForm.vue +208 -0
- package/frontend-vue/app/components/TenantPlanCard.vue +223 -0
- package/frontend-vue/app/components/TenantSupport.vue +415 -0
- package/frontend-vue/app/components/UserSummaryCard.vue +166 -0
- package/frontend-vue/app/components/WorkspaceBillingInfo.vue +68 -0
- package/frontend-vue/app/components/WorkspaceCompAccessButton.vue +198 -0
- package/frontend-vue/app/components/WorkspaceCreateModal.vue +256 -0
- package/frontend-vue/app/components/WorkspaceDangerZone.vue +146 -0
- package/frontend-vue/app/components/WorkspaceDetailHeader.vue +24 -0
- package/frontend-vue/app/components/WorkspaceIdentity.vue +99 -0
- package/frontend-vue/app/components/WorkspaceJoinButton.vue +50 -0
- package/frontend-vue/app/components/WorkspaceOperatorActions.vue +340 -0
- package/frontend-vue/app/components/WorkspaceSummaryCard.vue +161 -0
- package/frontend-vue/app/components/WorkspaceSuspendButton.vue +167 -0
- package/frontend-vue/app/components/WorkspaceSuspended.vue +164 -0
- package/frontend-vue/app/components/WorkspaceSwitcherWidget.vue +247 -0
- package/frontend-vue/app/composables/useApiErrorMessage.ts +35 -0
- package/frontend-vue/app/composables/useBillingCountries.ts +54 -0
- package/frontend-vue/app/composables/useBillingDocumentType.ts +7 -0
- package/frontend-vue/app/composables/useBillingStatus.ts +39 -0
- package/frontend-vue/app/composables/useCurrentWorkspace.ts +43 -0
- package/frontend-vue/app/composables/useDetailRefresh.ts +17 -0
- package/frontend-vue/app/composables/useExportHistory.ts +143 -0
- package/frontend-vue/app/composables/useInvoiceLines.ts +22 -0
- package/frontend-vue/app/composables/useMoneyFormat.ts +49 -0
- package/frontend-vue/app/composables/useMyWorkspaces.ts +47 -0
- package/frontend-vue/app/composables/usePlanFeatureFormat.ts +60 -0
- package/frontend-vue/app/composables/usePlanIntervalLabel.ts +30 -0
- package/frontend-vue/app/composables/useSaasRegistration.ts +522 -0
- package/frontend-vue/app/composables/useSeatQuota.ts +18 -0
- package/frontend-vue/app/composables/useSharedRequest.ts +54 -0
- package/frontend-vue/app/composables/useStripePaymentElement.ts +74 -0
- package/frontend-vue/app/composables/useSubscriptionAccess.ts +12 -0
- package/frontend-vue/app/composables/useSupportRequest.ts +74 -0
- package/frontend-vue/app/composables/useTenantPlan.ts +95 -0
- package/frontend-vue/app/composables/useTenantSwitch.ts +22 -0
- package/frontend-vue/app/composables/useWorkspaceAccessCache.ts +25 -0
- package/frontend-vue/app/custom-pages/auth/no-workspace.vue +495 -0
- package/frontend-vue/app/middleware/workspace-suspended.global.ts +56 -0
- package/frontend-vue/app/plugins/auth-links.ts +24 -0
- package/frontend-vue/app/plugins/billing-data-types.ts +62 -0
- package/frontend-vue/app/plugins/footer-links.ts +36 -0
- package/frontend-vue/app/plugins/plan-cards-display.client.ts +16 -0
- package/frontend-vue/app/plugins/segment-conditions-data-type.client.ts +122 -0
- package/frontend-vue/app/plugins/sidebar-widgets.ts +13 -0
- package/frontend-vue/app/types/support.ts +123 -0
- package/frontend-vue/dms.frontend.ts +68 -0
- package/frontend-vue/eslint.config.mjs +13 -0
- package/frontend-vue/i18n/locales/saas-en-GB.json +1285 -0
- package/frontend-vue/i18n/locales/saas-fr-FR.json +1285 -0
- package/frontend-vue/package.json +27 -0
- package/frontend-vue/pnpm-lock.yaml +4948 -0
- package/frontend-vue/pnpm-workspace.yaml +2 -0
- package/frontend-vue/server/routes/auth/finalize-workspace.post.ts +61 -0
- package/package.json +91 -0
package/README.md
ADDED
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
# @antelopejs/dms-saas
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue?style=for-the-badge&labelColor=000000"></a>
|
|
5
|
+
<a href="https://discord.gg/sjK28QHrA7"><img src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000" alt="Discord"></a>
|
|
6
|
+
<a href="https://antelopejs.com"><img src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000" alt="Documentation"></a>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
SaaS extension module for the AntelopeJS DMS.
|
|
10
|
+
|
|
11
|
+
Adds multi-tenant billing, plans, workspace switching, self-service workspace creation, refund policies, segments, reminders, and Stripe integration on top of the core DMS multi-tenant primitives.
|
|
12
|
+
|
|
13
|
+
See the design documents in `dms/saas/` (sibling repo) for the full architectural reference.
|
|
14
|
+
|
|
15
|
+
## Vue frontend development
|
|
16
|
+
|
|
17
|
+
The module registers `frontend-vue/dms.frontend.ts` with the Vue 3 Inertia
|
|
18
|
+
adapter. It preserves the `DmsSaas*` component names, the `auth/no-workspace`
|
|
19
|
+
page override, client-only displays, global guards, and English/French catalogs.
|
|
20
|
+
Public module configuration moves from `public.cmsSaas` to `public.dmsSaas` —
|
|
21
|
+
a breaking change for any frontend reading the old key. Stripe secrets are
|
|
22
|
+
never exposed to the frontend.
|
|
23
|
+
|
|
24
|
+
The backend integration requires `@antelopejs/dms`. Frontend source
|
|
25
|
+
verification runs through `@antelopejs/dms-frontend` and the DMS frontend
|
|
26
|
+
source shipped in that published DMS package; no sibling checkout or local
|
|
27
|
+
package link is required.
|
|
28
|
+
|
|
29
|
+
This package lives in `packages/dms-saas` of the `AntelopeJS/dms-saas`
|
|
30
|
+
workspace. From that directory run `pnpm install`,
|
|
31
|
+
`pnpm --dir frontend-vue install`, `pnpm build`, `pnpm typecheck`, and
|
|
32
|
+
`pnpm test:frontend`. The frontend check generates a temporary workspace, then
|
|
33
|
+
builds client, SSR, and email bundles and runs Vue typechecking.
|
|
34
|
+
|
|
35
|
+
## Tenant owner permissions
|
|
36
|
+
|
|
37
|
+
The `dms-saas.plan-intersection` permissions resolver runs at order 100. For a
|
|
38
|
+
member whose `isTenantOwner` is true in the requested tenant, it grants all
|
|
39
|
+
explicit permissions from that tenant's resolved plan, including inherited
|
|
40
|
+
permissions, regardless of assigned roles. Permissions outside the plan are
|
|
41
|
+
removed even when a role grants them. Other members retain only the intersection
|
|
42
|
+
of their incoming permissions and the resolved plan.
|
|
43
|
+
|
|
44
|
+
Tenant ownership never grants `*`, even if a plan contains it. An incoming `*`
|
|
45
|
+
(including the DMS platform owner's wildcard) retains the existing behavior:
|
|
46
|
+
the wildcard survives, and other incoming permissions are intersected with the
|
|
47
|
+
plan. Without a subscription, a `planId`, or an existing plan, the resolver
|
|
48
|
+
preserves incoming permissions and grants nothing new. This compatibility
|
|
49
|
+
fallback is not a denial of access for tenants with missing billing data.
|
|
50
|
+
|
|
51
|
+
Applications define their business permissions and can project the capabilities
|
|
52
|
+
that survive the plan into resource-specific actions in later resolvers. They
|
|
53
|
+
do not need a separate tenant-owner grant list. Subscription access gates remain
|
|
54
|
+
independent and unchanged. This resolver alone does not constrain
|
|
55
|
+
`defaultGranted` permissions or guards that do not consult effective permissions.
|
|
56
|
+
|
|
57
|
+
## Native support tickets
|
|
58
|
+
|
|
59
|
+
The Support page stores tickets, messages, and ticket events in the active
|
|
60
|
+
tenant schema. Platform ticket listing uses `CROSS_INSTANCE`; MongoDB's
|
|
61
|
+
`_instance` identifies each ticket's tenant. Detail reads and writes use that
|
|
62
|
+
tenant's scoped models.
|
|
63
|
+
|
|
64
|
+
Support listings use the Data API endpoints:
|
|
65
|
+
|
|
66
|
+
- `/api/saas/tenant/tables/support-tickets/list`
|
|
67
|
+
- `/api/saas/tables/support-tickets/list`
|
|
68
|
+
- `/api/saas/tables/support-owners/list`
|
|
69
|
+
- Existing tenant and platform detail URLs, with `/messages/list` and
|
|
70
|
+
`/events/list` children (and `/count` variants)
|
|
71
|
+
|
|
72
|
+
List queries accept `offset`, `limit`, `sortKey`, `sortDirection`, and
|
|
73
|
+
`filter_<field>`. Responses contain `{ results, total, offset, limit }`. Owner
|
|
74
|
+
rows contain `_id`, `name`, and `email`. Global ticket rows include the joined
|
|
75
|
+
`tenantName`.
|
|
76
|
+
|
|
77
|
+
Pages default to 20 rows and are capped at 100. String filters use the DMS
|
|
78
|
+
comparison modes, for example `filter_status=is:open`. Recent-first reads keep
|
|
79
|
+
timestamp/ID compound ordering. Message and event pagination loads only the
|
|
80
|
+
requested collection; ticket scope is enforced by the server.
|
|
81
|
+
|
|
82
|
+
Status and assignment changes record the actor, previous/new values, and time
|
|
83
|
+
in `support_ticket_events`. This includes automatic reply transitions: support
|
|
84
|
+
replies wait for the customer, and customer replies resume tickets waiting for
|
|
85
|
+
them. Existing tickets start with no historical events; old history is not
|
|
86
|
+
invented. Existing central mirror data is unused and is not automatically deleted.
|
|
87
|
+
|
|
88
|
+
Support level comes from the inherited plan feature whose id is
|
|
89
|
+
`support-sla`. Supported string values are `community`, `email`, `priority`,
|
|
90
|
+
and `dedicated`. An absent or invalid value falls back to community support.
|
|
91
|
+
Those levels respectively expose normal; low/normal; low/normal/high; and all
|
|
92
|
+
priorities. Displayed first-response targets are no guarantee, 48 business
|
|
93
|
+
hours, 8 business hours, and 2 elapsed hours.
|
|
94
|
+
|
|
95
|
+
Attachments use the DMS upload token and staging flow below the tenant-bound
|
|
96
|
+
`support-attachments/{tenantId}` path. A message accepts up to five image, PDF,
|
|
97
|
+
or text files of 10 MiB each. Only staged keys from that tenant path are
|
|
98
|
+
accepted, each is promoted before the tenant message is persisted, and failed
|
|
99
|
+
writes move promoted files back to staging. Ticket-specific metadata routes
|
|
100
|
+
verify that a key belongs to the requested thread before issuing its read URL.
|
|
101
|
+
|
|
102
|
+
## Extension points
|
|
103
|
+
|
|
104
|
+
### Consuming this module
|
|
105
|
+
|
|
106
|
+
A module that extends dms-saas depends on the separately published interface
|
|
107
|
+
package (`"@antelopejs/interface-dms-saas"` in its `dependencies`) and
|
|
108
|
+
imports the extension points from it. The dms-saas runtime package remains a
|
|
109
|
+
separate dependency for modules that need the implementation; its package root
|
|
110
|
+
boots the registration graph:
|
|
111
|
+
|
|
112
|
+
| Subpath | Surface |
|
|
113
|
+
| --- | --- |
|
|
114
|
+
| `@antelopejs/interface-dms-saas` | every extension point except `db`: billing, data API, pages, plans, provisioning and registration flat, plus the `invoiceLineItems` and `workspaceLifecycle` namespaces |
|
|
115
|
+
| `@antelopejs/interface-dms-saas/billing` | customer balance and complimentary subscription state |
|
|
116
|
+
| `@antelopejs/interface-dms-saas/data-api` | hidden-value data API filters |
|
|
117
|
+
| `@antelopejs/interface-dms-saas/db` | canonical SaaS tables and data models |
|
|
118
|
+
| `@antelopejs/interface-dms-saas/hidden-filter` | the `HiddenStringFilter` decorator on its own |
|
|
119
|
+
| `@antelopejs/interface-dms-saas/invoice-line-items` | provider registration, line item types, line key helpers |
|
|
120
|
+
| `@antelopejs/interface-dms-saas/page-definitions` | page and module ids, slugs and descriptors |
|
|
121
|
+
| `@antelopejs/interface-dms-saas/pages` | workspace settings category and tenant billing page extensions |
|
|
122
|
+
| `@antelopejs/interface-dms-saas/plans` | plan projections, catalog builder, and price normalization |
|
|
123
|
+
| `@antelopejs/interface-dms-saas/provisioning` | provisioning hook payload |
|
|
124
|
+
| `@antelopejs/interface-dms-saas/registration` | public registration capture limits |
|
|
125
|
+
| `@antelopejs/interface-dms-saas/workspace-lifecycle` | workspace lifecycle events and operator actions |
|
|
126
|
+
|
|
127
|
+
`invoiceLineItems` and `workspaceLifecycle` come off the root entry as
|
|
128
|
+
namespaces because each carries an `internal` proxy namespace of its own; `db`
|
|
129
|
+
is reachable only through its subpath, since importing it registers the SaaS
|
|
130
|
+
tables.
|
|
131
|
+
|
|
132
|
+
This module declares the interface package name in `antelopeJs.implements`, so as
|
|
133
|
+
long as both modules run in the same AntelopeJS project, those imports are
|
|
134
|
+
detoured to the running dms-saas instance instead of a second copy pulled from
|
|
135
|
+
`node_modules`. Registration goes through an interface proxy on top of that: a
|
|
136
|
+
provider registered before dms-saas is constructed is held and replayed on
|
|
137
|
+
attach, replayed again when dms-saas is reloaded, and dropped when the
|
|
138
|
+
registering module is unloaded.
|
|
139
|
+
|
|
140
|
+
The interface package must be released before dms-saas. During workspace
|
|
141
|
+
development dms-saas uses `workspace:*`; publishing replaces that range with
|
|
142
|
+
the released interface version. Release the interface package first, then
|
|
143
|
+
release dms-saas, and update consumers to the published interface version.
|
|
144
|
+
|
|
145
|
+
### Public screens
|
|
146
|
+
|
|
147
|
+
dms-saas ships a working registration screen so a fresh project can sell from
|
|
148
|
+
day one. It is a reference implementation, not a design: the module owns the
|
|
149
|
+
money and the compliance of the flow, the consuming SaaS owns the conversion.
|
|
150
|
+
|
|
151
|
+
Replacing it takes two steps. Turn the bundled page off in the module config —
|
|
152
|
+
page registration is keyed by slug, so declaring a second page on `register`
|
|
153
|
+
races the bundled one instead of overriding it:
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"modules": {
|
|
158
|
+
"dms-saas": {
|
|
159
|
+
"config": {
|
|
160
|
+
"publicScreens": { "register": false }
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Then register your own page on the `register` slug and build it on the
|
|
168
|
+
`useSaasRegistration()` composable the Vue adapter auto-imports. It holds the
|
|
169
|
+
whole flow — plan loading and filtering by customer type, the Stripe setup
|
|
170
|
+
intent and card confirmation, the order the requirements are validated in, the
|
|
171
|
+
provisioning call and the landing route — and renders nothing:
|
|
172
|
+
|
|
173
|
+
```vue
|
|
174
|
+
<script setup lang="ts">
|
|
175
|
+
const { form, plans, errorMessage, isSubmitting, formatPlanPrice, submit } =
|
|
176
|
+
useSaasRegistration({ redirectTo: "/welcome" });
|
|
177
|
+
</script>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Nothing it returns throws: a failure surfaces as a translated `errorMessage`,
|
|
181
|
+
and `submit()` resolves to the new tenant id or `null`. Every screen stays
|
|
182
|
+
enabled by default, so an existing project needs no configuration change.
|
|
183
|
+
|
|
184
|
+
### Registration extras and the provisioning hook
|
|
185
|
+
|
|
186
|
+
A SaaS that captures its own fields at signup — referral source, team size,
|
|
187
|
+
anything — sends them as `extras` on the registration payload and writes them
|
|
188
|
+
from a `TENANT_BEING_PROVISIONED` listener. dms-saas forwards the object
|
|
189
|
+
verbatim: it never reads it, never stores it, never returns it. The data stays
|
|
190
|
+
the consumer's, and so does the schema.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import type { TenantBeingProvisionedPayload } from "@antelopejs/interface-dms-saas/provisioning";
|
|
194
|
+
import {
|
|
195
|
+
Hook,
|
|
196
|
+
RegisterHook,
|
|
197
|
+
} from "@antelopejs/interface-dms/hooks";
|
|
198
|
+
|
|
199
|
+
RegisterHook(
|
|
200
|
+
Hook.TENANT_BEING_PROVISIONED,
|
|
201
|
+
async ({ tenantId, userId, extras }: TenantBeingProvisionedPayload) => {
|
|
202
|
+
await storeOnboardingAnswers(tenantId, userId, extras);
|
|
203
|
+
return undefined;
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`storeOnboardingAnswers` is your module's persistence function. Keep the explicit `undefined` return: this hook's handler contract is `Promise<undefined>`, not `Promise<void>`.
|
|
209
|
+
|
|
210
|
+
**Contract**
|
|
211
|
+
|
|
212
|
+
- The hook is emitted inside the provisioning transaction, once the workspace
|
|
213
|
+
is complete and before it is handed back. Listeners run in series and are
|
|
214
|
+
awaited; **a listener that throws cancels the registration** — tenant,
|
|
215
|
+
subscription, Stripe customer and, on the password path, the account itself
|
|
216
|
+
are rolled back. That is the point: a workspace that is paid for but missing
|
|
217
|
+
the data its owner filled in is worse than no workspace.
|
|
218
|
+
- It runs while the per-card provisioning lock is held, so a slow listener
|
|
219
|
+
slows every concurrent signup on that card. Write, do not call out.
|
|
220
|
+
- `extras` reaches both entry points — password registration and the
|
|
221
|
+
OAuth-entry completion — and is absent when the consumer captured nothing.
|
|
222
|
+
- Registration is public and unauthenticated, so `extras` is bounded before it
|
|
223
|
+
is forwarded: **4 KB serialised, 64 keys, 4 levels deep**, and no
|
|
224
|
+
`__proto__` / `constructor` / `prototype` key. Anything above answers 400
|
|
225
|
+
with `saas.errors.registration.extras_*`. `REGISTRATION_EXTRAS_LIMITS` is
|
|
226
|
+
available from `dms-saas/registration` so a consumer can bound
|
|
227
|
+
its own capture first.
|
|
228
|
+
- Nothing else in dms-saas depends on a listener existing: with no listener
|
|
229
|
+
registered, registration behaves exactly as before.
|
|
230
|
+
|
|
231
|
+
On the browser side, `useSaasRegistration()` takes the capture as an option
|
|
232
|
+
and sends it with the rest of the form:
|
|
233
|
+
|
|
234
|
+
```vue
|
|
235
|
+
<script setup lang="ts">
|
|
236
|
+
const answers = reactive({ referral: "", teamSize: "" });
|
|
237
|
+
const { form, submit } = useSaasRegistration({ extras: () => answers });
|
|
238
|
+
</script>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Invoice line items
|
|
242
|
+
|
|
243
|
+
`RegisterInvoiceLineItemsProvider` lets a module bill its own metered usage on
|
|
244
|
+
the workspace's subscription invoice. When Stripe opens the renewal invoice of
|
|
245
|
+
a billing cycle, dms-saas asks every registered provider for the lines it wants
|
|
246
|
+
and pushes them as Stripe invoice items while the invoice is still a draft, so
|
|
247
|
+
they are charged on finalization.
|
|
248
|
+
|
|
249
|
+
dms-saas stays agnostic: it never interprets a line. What a metric is, how it
|
|
250
|
+
is measured and how it is priced belong to the provider.
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
import {
|
|
254
|
+
RegisterInvoiceLineItemsProvider,
|
|
255
|
+
UnregisterInvoiceLineItemsProvider,
|
|
256
|
+
} from "@antelopejs/interface-dms-saas/invoice-line-items";
|
|
257
|
+
|
|
258
|
+
const PROVIDER_ID = "cloud";
|
|
259
|
+
|
|
260
|
+
export async function construct(): Promise<void> {
|
|
261
|
+
RegisterInvoiceLineItemsProvider({
|
|
262
|
+
id: PROVIDER_ID,
|
|
263
|
+
resolve: async ({ tenantId, periodStart, periodEnd, currency }) => {
|
|
264
|
+
const usage = await aggregateUsage(tenantId, periodStart, periodEnd);
|
|
265
|
+
return [
|
|
266
|
+
{
|
|
267
|
+
key: "vcpu-minutes",
|
|
268
|
+
description: "vCPU minutes",
|
|
269
|
+
amountCents: usage.vcpuCents,
|
|
270
|
+
quantity: usage.vcpuMinutes,
|
|
271
|
+
unit: "minute",
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
key: "included-credit",
|
|
275
|
+
description: "Included usage credit",
|
|
276
|
+
amountCents: -usage.includedCreditCents,
|
|
277
|
+
},
|
|
278
|
+
];
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export async function stop(): Promise<void> {
|
|
284
|
+
UnregisterInvoiceLineItemsProvider(PROVIDER_ID);
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Contract**
|
|
289
|
+
|
|
290
|
+
- Providers run on `subscription_cycle` invoices only — never on a
|
|
291
|
+
subscription's first invoice nor on one-off invoices, which have no closed
|
|
292
|
+
usage period behind them.
|
|
293
|
+
- `periodStart` / `periodEnd` are the boundaries of the **cycle that just
|
|
294
|
+
closed**, not of the upcoming cycle the plan line covers.
|
|
295
|
+
- `amountCents` is an integer total in the invoice currency and may be
|
|
296
|
+
negative: that is how a plan's included credit is deducted. Zero-amount lines
|
|
297
|
+
are dropped. A structurally invalid line (non-integer amount, empty key or
|
|
298
|
+
description, oversized or `:`-carrying key) fails the webhook event once
|
|
299
|
+
every provider has run: it is usage that would otherwise never be billed.
|
|
300
|
+
- `key` is the unit of idempotency, namespaced by the provider `id`. The same
|
|
301
|
+
key is injected at most once per invoice, whatever the number of webhook
|
|
302
|
+
redeliveries or concurrent workers — so keep it stable across cycles and
|
|
303
|
+
never derive it from a timestamp. Neither `id` nor `key` may contain `:`,
|
|
304
|
+
which joins them, and together they must stay under 150 characters — they
|
|
305
|
+
compose the Stripe idempotency key. `quantity` and `unit` are recorded as
|
|
306
|
+
Stripe metadata for auditability; the amount charged is always
|
|
307
|
+
`amountCents`.
|
|
308
|
+
- A resolver that throws is logged and skipped: the other providers still run
|
|
309
|
+
and the invoice is still mirrored. Once every provider has been attempted,
|
|
310
|
+
a partial injection fails the webhook so it surfaces instead of silently
|
|
311
|
+
underbilling the cycle — replays cannot double-charge, every line being
|
|
312
|
+
idempotent.
|
|
313
|
+
- Resolvers run inside the Stripe webhook request. Read pre-aggregated
|
|
314
|
+
rollups; a resolver that computes usage on the fly delays the webhook
|
|
315
|
+
response for every provider.
|
|
316
|
+
- Register in `construct()`, unregister in `stop()`. An `id` must be unique
|
|
317
|
+
across modules: registering one that is already taken replaces the previous
|
|
318
|
+
provider, whose usage lines then stop being invoiced. Registration is keyed
|
|
319
|
+
by `id` all the way down to the interface proxy — which is both why a clash
|
|
320
|
+
cannot be refused without stranding whichever module registered first, and
|
|
321
|
+
why it is only reported at error level once dms-saas is attached. Two modules
|
|
322
|
+
registering the same `id` before that collapse into one silently, so pick an
|
|
323
|
+
`id` no other module could plausibly choose.
|
|
324
|
+
|
|
325
|
+
### Workspace settings pages
|
|
326
|
+
|
|
327
|
+
A module adding a page to a workspace's settings takes the side-effect-free
|
|
328
|
+
`workspaceSettingsCategory` descriptor from the interface rather than
|
|
329
|
+
rebuilding its hierarchy and metadata. The descriptor supports synchronous
|
|
330
|
+
`PageController` declarations but is intentionally not reference-equal to the
|
|
331
|
+
registered runtime object. Runtime code that requires canonical identity can
|
|
332
|
+
await `GetWorkspaceSettingsCategory()` after the SaaS runtime implements the
|
|
333
|
+
interface.
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
import { PageController, RegisterPage } from "@antelopejs/interface-dms/page";
|
|
337
|
+
import { workspaceSettingsCategory } from "@antelopejs/interface-dms-saas/pages";
|
|
338
|
+
|
|
339
|
+
@RegisterPage()
|
|
340
|
+
export class WorkspaceRegistriesController extends PageController("registries", {
|
|
341
|
+
displayName: "$cloud.workspace.registries.title",
|
|
342
|
+
category: workspaceSettingsCategory,
|
|
343
|
+
icon: "i-ph-package",
|
|
344
|
+
order: 10,
|
|
345
|
+
}) {}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Extensions of the existing tenant billing page register components through
|
|
349
|
+
stable page and anchor identifiers. They do not import the page controller,
|
|
350
|
+
which would load the module's page registration graph.
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
import { CustomComponent } from "@antelopejs/interface-dms/base/custom";
|
|
354
|
+
import {
|
|
355
|
+
RegisterTenantBillingPageExtension,
|
|
356
|
+
tenantBillingPage,
|
|
357
|
+
type TenantBillingPageExtensionRegistration,
|
|
358
|
+
} from "@antelopejs/interface-dms-saas/pages";
|
|
359
|
+
|
|
360
|
+
let billingBlocks: TenantBillingPageExtensionRegistration | undefined;
|
|
361
|
+
|
|
362
|
+
export function construct(): void {
|
|
363
|
+
billingBlocks = RegisterTenantBillingPageExtension({
|
|
364
|
+
name: "CloudBillingBlocks",
|
|
365
|
+
components: [
|
|
366
|
+
{
|
|
367
|
+
key: "inProgressInvoice",
|
|
368
|
+
component: CustomComponent("CloudInProgressInvoice"),
|
|
369
|
+
side: "after",
|
|
370
|
+
anchorKey: tenantBillingPage.components.planCard,
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export function stop(): void {
|
|
377
|
+
billingBlocks?.unregister();
|
|
378
|
+
billingBlocks = undefined;
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Platform modules can extend the SaaS platform-owner workspace detail without
|
|
383
|
+
importing its controller or the private `saasModule` instance. Use
|
|
384
|
+
`platformSaasModule`, `platformWorkspaceDetailPage`, and
|
|
385
|
+
`RegisterPlatformWorkspaceDetailPageExtension` from the same public `pages`
|
|
386
|
+
entry point. `platformSaasModule` is also a synchronous descriptor; runtime
|
|
387
|
+
code that requires the registered module root can await
|
|
388
|
+
`GetPlatformSaasModule()`. Platform data controllers that must hide a tenant
|
|
389
|
+
routing field can import `HiddenStringFilter` from
|
|
390
|
+
`@antelopejs/interface-dms-saas/data-api`; the underlying
|
|
391
|
+
SaaS data controllers and database models remain private.
|
|
392
|
+
|
|
393
|
+
### Platform-owner operations and workspace lifecycle
|
|
394
|
+
|
|
395
|
+
The platform-owner workspace page provides suspension, reactivation, immediate
|
|
396
|
+
Stripe-backed upgrades, and Stripe customer-balance credits. Every request
|
|
397
|
+
uses a caller-supplied operation ID and creates a private durable command intent
|
|
398
|
+
before any Stripe or lifecycle effect. The command state retains the actor,
|
|
399
|
+
tenant, action, redacted-safe values, attempts, outcome, and effective time.
|
|
400
|
+
Retrying the same ID and values resumes an eligible failed operation; reusing
|
|
401
|
+
it with different values is rejected.
|
|
402
|
+
|
|
403
|
+
Operator attempts do not use leases or timed takeover. A definitive failure
|
|
404
|
+
whose execution has finished may retry with the same operation and provider
|
|
405
|
+
payload for 23 hours from intent creation. This preserves a one-hour margin
|
|
406
|
+
inside Stripe's minimum 24-hour idempotency retention. An unknown outcome,
|
|
407
|
+
including lost journal acknowledgement, requires reconciliation instead.
|
|
408
|
+
|
|
409
|
+
Suspension, reactivation, and immediate plan changes persist a subscription
|
|
410
|
+
transition before effects. Its revision fences competing local transitions and
|
|
411
|
+
deletion; the operator journal must succeed before its intent is cleared.
|
|
412
|
+
An ordinary subscription write rejects pending transitions and deletion markers.
|
|
413
|
+
This does not provide distributed transactions or fence an external request
|
|
414
|
+
that has already left the process.
|
|
415
|
+
|
|
416
|
+
Inspect an operation through the platform-owner-only endpoint
|
|
417
|
+
`GET /api/saas/workspaces/:tenantId/operations/:operationId`. A running or
|
|
418
|
+
reconciliation-required operation may have an old executor still active.
|
|
419
|
+
Before resolving it, establish **both** that the previous executor is stopped
|
|
420
|
+
or quiescent and what happened externally, using the persisted operation,
|
|
421
|
+
provider request details, and provider records. A matching Stripe read alone
|
|
422
|
+
does not establish quiescence. There is deliberately no force-success endpoint
|
|
423
|
+
that clears the intent without those proofs. This trades automatic crash
|
|
424
|
+
recovery and availability for protection against conflicting external effects.
|
|
425
|
+
|
|
426
|
+
Bulk plan migrations capture an immutable workspace list and resolved target
|
|
427
|
+
configuration before admitting an execution. Each workspace gets a persisted
|
|
428
|
+
outcome and a subscription transition before provider effects. A crash after
|
|
429
|
+
changing `planId` does not remove that workspace from the snapshot. Running
|
|
430
|
+
jobs never use timed takeover; startup marks interrupted jobs as
|
|
431
|
+
`reconciliation_required`, retaining their per-workspace evidence and pending
|
|
432
|
+
subscription intents instead of blindly replaying effects.
|
|
433
|
+
|
|
434
|
+
The historical `migrate-and-delete` endpoint now requests migration only.
|
|
435
|
+
Inspect `GET /api/saas/plans-deletion/migrations/:migrationId` for the snapshot,
|
|
436
|
+
outcomes, and reconciliation requirements. **Snapshot completion does not retire
|
|
437
|
+
the source plan.** The source remains available even at zero observed references;
|
|
438
|
+
workspaces arriving after capture are outside this job. Any later retirement
|
|
439
|
+
requires a separate procedure that establishes writer quiescence. A current
|
|
440
|
+
reference count cannot exclude a suspended writer that already validated the plan.
|
|
441
|
+
|
|
442
|
+
Migration reconciliation requires stopping or proving quiescence of the prior
|
|
443
|
+
executor and establishing the provider, subscription, permission-cleanup, and
|
|
444
|
+
notification outcomes. A target `planId` or matching Stripe response alone is
|
|
445
|
+
not sufficient. Failed core lifecycle admissions may also remain closed to
|
|
446
|
+
destruction until their evidence is resolved. There is no automatic force-success
|
|
447
|
+
or effect-replay endpoint; arbitrary hooks are not made idempotent by a job ID.
|
|
448
|
+
|
|
449
|
+
Self-service cancellation, deferred plan changes, and administrative free grants
|
|
450
|
+
also admit subscription intent before Stripe effects. An ambiguous schedule
|
|
451
|
+
replacement retains the previous mirror and pending intent; it does not attempt
|
|
452
|
+
to restore or erase provider state blindly. Owners can inspect these intents and
|
|
453
|
+
the irreversible deletion marker through the workspace `admin-state` endpoint.
|
|
454
|
+
|
|
455
|
+
Checkout holds a `checkout` intent until the exact recorded session completes
|
|
456
|
+
or expires. Completion admits one callback executor and writes a terminal session
|
|
457
|
+
receipt only after its awaited provider effects finish. Unknown callback outcomes
|
|
458
|
+
retain intent rather than enabling timed replay. A session whose ID was never
|
|
459
|
+
acknowledged locally requires manual reconciliation, including executor quiescence.
|
|
460
|
+
Trial reservations are permanent across checkout expiration; uncertain attempts
|
|
461
|
+
do not receive another trial. Checkout automation remains best-effort, outside
|
|
462
|
+
the terminal receipt, and does not promise exactly-once delivery or external order.
|
|
463
|
+
|
|
464
|
+
Stripe webhook dispatch admits an event once and fences completion with its
|
|
465
|
+
admitted revision. An old `pending` record never permits timed takeover. Handler
|
|
466
|
+
failures become `reconciliation_required`; legacy `failed` records also block
|
|
467
|
+
replay because they may contain partial effects. Redelivery receives an error
|
|
468
|
+
while unresolved, rather than a successful acknowledgement or another execution.
|
|
469
|
+
|
|
470
|
+
Inspect `stripe_webhook_events` by Stripe event ID for its result, revision, and
|
|
471
|
+
error message. Recovery requires establishing the prior executor's quiescence
|
|
472
|
+
and the handler's database and external outcomes; do not delete the admission
|
|
473
|
+
or resend blindly. There is no automatic recovery endpoint. Unresolved records
|
|
474
|
+
remain indefinitely. The existing retention policy still removes old terminal
|
|
475
|
+
`success`/`skipped` receipts, so deduplication is not guaranteed after that window.
|
|
476
|
+
|
|
477
|
+
Revision mutations require the published database interface `0.1.6` or later
|
|
478
|
+
and an adapter implementing that contract. The MongoDB test adapter uses `1.3.0`,
|
|
479
|
+
and any DMS release carrying this module satisfies the requirement. New records
|
|
480
|
+
initialize revisions; legacy PostgreSQL rows with a declared revision column
|
|
481
|
+
require an explicit revision backfill
|
|
482
|
+
before these mutations can proceed. An absent revision is not equivalent to
|
|
483
|
+
`null`, and unsupported bootstrap fails closed. Do not run this backfill against
|
|
484
|
+
shared data without a separately approved migration and quiescent writers.
|
|
485
|
+
|
|
486
|
+
Lifecycle-dependent modules register a required consumer through the public
|
|
487
|
+
interface:
|
|
488
|
+
|
|
489
|
+
```ts
|
|
490
|
+
import {
|
|
491
|
+
RegisterWorkspaceLifecycleConsumer,
|
|
492
|
+
type WorkspaceLifecycleConsumerRegistration,
|
|
493
|
+
} from "@antelopejs/interface-dms-saas/workspace-lifecycle";
|
|
494
|
+
|
|
495
|
+
let lifecycleRegistration: WorkspaceLifecycleConsumerRegistration | undefined;
|
|
496
|
+
|
|
497
|
+
export function construct(): void {
|
|
498
|
+
lifecycleRegistration = RegisterWorkspaceLifecycleConsumer({
|
|
499
|
+
name: "cloud.workspaces",
|
|
500
|
+
transitions: ["suspended", "reactivation_requested"],
|
|
501
|
+
async consume(message) {
|
|
502
|
+
const receipt = await applyWorkspaceLifecycle(message);
|
|
503
|
+
return {
|
|
504
|
+
receiptId: receipt.id,
|
|
505
|
+
effectiveAt: receipt.effectiveAt,
|
|
506
|
+
};
|
|
507
|
+
},
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
export function stop(): void {
|
|
512
|
+
lifecycleRegistration?.unregister();
|
|
513
|
+
lifecycleRegistration = undefined;
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Registration may happen before dms-saas construction: dms-saas replays buffered
|
|
518
|
+
consumers when it attaches its module-owned registry. Registrations are removed
|
|
519
|
+
automatically when their owning module unloads; the explicit handle remains
|
|
520
|
+
available for module stop compatibility. Register required consumers during
|
|
521
|
+
module construction, before module startup reconciliation. Messages carry
|
|
522
|
+
stable `tenantId` and `operationId` values. Deliveries and receipts are
|
|
523
|
+
persisted; a persisted success is skipped on later retries. Concurrent
|
|
524
|
+
reconcilers may invoke the same consumer more than once before its receipt is
|
|
525
|
+
persisted. Consumers must deduplicate concurrent calls by operation identity;
|
|
526
|
+
the outbox does not provide exactly-once execution or ordering of external
|
|
527
|
+
effects. Failed deliveries remain available to startup reconciliation and a
|
|
528
|
+
five-minute retry worker. Suspension
|
|
529
|
+
closes SaaS access before consumer delivery. Reactivation keeps SaaS access
|
|
530
|
+
closed until every required consumer returns a durable receipt; the consumer
|
|
531
|
+
therefore owns any product-specific sleep or wake work.
|
|
532
|
+
|
|
533
|
+
#### Successful workspace creation
|
|
534
|
+
|
|
535
|
+
Provisioning reserves free-workspace capacity per card and trial eligibility
|
|
536
|
+
per email/card identity before issuing provider effects. Reservations do not
|
|
537
|
+
expire. An unknown provider or persistence outcome keeps the reservation and
|
|
538
|
+
the account for reconciliation; the service never replays opaque provisioning
|
|
539
|
+
hooks or stores their `extras`. Known provider handles and the attempt ID are
|
|
540
|
+
persisted separately from billing profiles. Stripe customer metadata also
|
|
541
|
+
contains the attempt ID for investigating a lost creation response.
|
|
542
|
+
|
|
543
|
+
Platform owners inspect the first 100 unresolved records through
|
|
544
|
+
`GET /api/saas/workspaces/provisioning-attempts` and an individual record through
|
|
545
|
+
`GET /api/saas/workspaces/:tenantId/provisioning-attempt`. Preparing records can
|
|
546
|
+
represent an executor that disappeared before recording its error. Establish
|
|
547
|
+
executor quiescence, provider cancellation or successful creation, and tenant
|
|
548
|
+
closure before repairing a record or releasing an allocation. This release
|
|
549
|
+
does not provide an automated repair command. Never release uncertain
|
|
550
|
+
reservations by age or re-run non-idempotent hooks with guessed input.
|
|
551
|
+
|
|
552
|
+
Every consumer declares the transitions it handles, for example
|
|
553
|
+
`transitions: ["created"]` for creation only or all three when it also handles
|
|
554
|
+
suspension and reactivation. A consumer must return a durable receipt and
|
|
555
|
+
deduplicate effects by `operationId`:
|
|
556
|
+
`workspace-created:<tenantId>` remains stable across delivery retries.
|
|
557
|
+
|
|
558
|
+
Self-service provisioning writes a creation marker in the existing lifecycle
|
|
559
|
+
outbox **before inserting the tenant**. Only after ownership, billing records
|
|
560
|
+
and every `TENANT_BEING_PROVISIONED` listener succeed does it allow payment
|
|
561
|
+
confirmation. Trials and creations without an invoice require no payment;
|
|
562
|
+
zero-total invoices already marked paid are not paid again. An invoice-backed
|
|
563
|
+
creation becomes committed only after Stripe reports its first invoice paid.
|
|
564
|
+
Consumer failures never roll back committed workspaces.
|
|
565
|
+
|
|
566
|
+
Inventory reconcilers must check the public provisioning gate before creating
|
|
567
|
+
external resources. This check prevents a concurrent inventory scan from
|
|
568
|
+
provisioning a tenant whose membership, hooks or payment are still incomplete.
|
|
569
|
+
It does not replace tenant existence, authorization or suspension checks.
|
|
570
|
+
|
|
571
|
+
```ts
|
|
572
|
+
import { IsWorkspaceProvisioningCommitted } from
|
|
573
|
+
"@antelopejs/interface-dms-saas/workspace-lifecycle";
|
|
574
|
+
|
|
575
|
+
async function reconcileTenant(tenantId: string): Promise<void> {
|
|
576
|
+
if (!(await IsWorkspaceProvisioningCommitted(tenantId))) return;
|
|
577
|
+
await ensureWorkspaceResources(tenantId);
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
The gate returns true for legacy/default/bootstrap tenants without a creation
|
|
582
|
+
marker. It returns false for preparing, unpaid or cancelled creations, and
|
|
583
|
+
propagates storage failures; callers must fail closed. Cancellation leaves a
|
|
584
|
+
tombstone so even a partial rollback cannot make an orphaned tenant eligible.
|
|
585
|
+
Do not delete these markers while the tenant may remain in an inventory.
|
|
586
|
+
|
|
587
|
+
Reconciliation recovers a crash after successful payment but before delivery,
|
|
588
|
+
partial consumer fan-out and lost receipts. It may deliver a message again
|
|
589
|
+
when a consumer commits its effect before the receipt is saved. Consumers must
|
|
590
|
+
make their resource creation and ownership linkage idempotent. Delivery skips
|
|
591
|
+
tenants already deleted when the attempt starts; consumers must also tolerate
|
|
592
|
+
deletion racing with an in-flight attempt.
|
|
593
|
+
|
|
594
|
+
A definitive card decline permits rollback only after tenant lifecycle
|
|
595
|
+
admission closes and all required deletion hooks succeed. An incomplete
|
|
596
|
+
closure preserves data, account ownership, and recovery markers. Rollback
|
|
597
|
+
never drops the tenant schema or the lifecycle/invitation tombstones. An
|
|
598
|
+
ambiguous payment error preserves the tenant and account because a timeout can
|
|
599
|
+
hide a successful charge. Reconciliation checks payment status but never starts
|
|
600
|
+
another charge. A crash before payment, an unpaid ambiguous result, or an
|
|
601
|
+
interrupted pre-payment preparation requires payment/provisioning recovery;
|
|
602
|
+
it never emits `created` merely because the tenant exists. HTTP creation requests
|
|
603
|
+
are not made idempotent by the delivery operation ID.
|
|
604
|
+
|
|
605
|
+
These additions require a dms-saas package built from this source revision (or
|
|
606
|
+
a later release containing it), including its lifecycle table fields and worker.
|
|
607
|
+
The previously published `0.2.5` package does not provide the gate or `created`
|
|
608
|
+
contract. Register consumers before startup reconciliation; use the existing
|
|
609
|
+
tenant inventory and gate for bootstrap/backfill rather than treating `created`
|
|
610
|
+
as a historical inventory API.
|
|
611
|
+
|
|
612
|
+
## Support attachment storage and recovery
|
|
613
|
+
|
|
614
|
+
Configure `supportStorage` with an explicit named file-storage definition. Support
|
|
615
|
+
issues private staged uploads through its tenant-member `/api/saas/support/uploads`
|
|
616
|
+
route and persists the tenant, source key and storage name before returning the
|
|
617
|
+
upload capability. Native `/api/files` routes do not authorize support files.
|
|
618
|
+
Support read routes check ticket/message membership before minting a read URL.
|
|
619
|
+
|
|
620
|
+
Keep every old named storage definition unchanged while its uploads, receipts or
|
|
621
|
+
files remain live. Selecting a new `supportStorage` name affects only new uploads;
|
|
622
|
+
existing receipts retain their original routing. Unknown names fail closed. A name
|
|
623
|
+
does not identify a provider incarnation and cannot detect remapping that same
|
|
624
|
+
name to a different backend. Use isolated nonreused keys and prevent privileged or
|
|
625
|
+
external writers from modifying support objects.
|
|
626
|
+
|
|
627
|
+
The storage adapter must provide write-once uploads and dedicated no-clobber
|
|
628
|
+
`PromoteFile`, with trusted-origin replay and private visibility preservation.
|
|
629
|
+
Promotion moves a staged upload to its canonical key without the staging prefix;
|
|
630
|
+
support never retains an expiring staged key as the published reference. Support
|
|
631
|
+
records positive promotion confirmation before validating final metadata, then
|
|
632
|
+
uses the existing database operation receipt to authorize publication. Published
|
|
633
|
+
prerequisites are the database interface `0.1.6`, the storage interface `0.1.3`,
|
|
634
|
+
and a compatible provider: local `0.1.4` or S3 `0.1.3`, all of which any DMS
|
|
635
|
+
release carrying this module provides. Tests use MongoDB `1.3.0`.
|
|
636
|
+
There is no legacy move/existence fallback.
|
|
637
|
+
|
|
638
|
+
Source admissions remain insert-only and permanent. Rejected work cannot publish,
|
|
639
|
+
even if a delayed promotion finishes. Owner-initiated paginated support recovery
|
|
640
|
+
repeats ordinary deletion of owned rejected sources and positively confirmed
|
|
641
|
+
finals. It never promotes rejected work just to establish cleanup ownership and
|
|
642
|
+
never deletes an unconfirmed or foreign final. Uncertain acknowledgements can
|
|
643
|
+
therefore retain private orphans. Recovery is not autonomous garbage collection;
|
|
644
|
+
operators must repeat complete passes, including after delayed uploads finish.
|
|
645
|
+
Already issued signed read URLs remain valid until their normal expiry.
|
|
646
|
+
|
|
647
|
+
Never-submitted upload receipts have no operation to recover. Configure provider
|
|
648
|
+
staging expiry for abandoned bytes; permanent issuance/admission metadata is not
|
|
649
|
+
automatically collected. Upload capabilities and in-flight writes can outlive a
|
|
650
|
+
cleanup pass, so storage expiry/operational cleanup must account for them. Do not
|
|
651
|
+
delete receipts to free a source for another request or garbage-collect a file
|
|
652
|
+
that a committed support message still references.
|
|
653
|
+
|
|
654
|
+
The earlier draft seal schema has no production installations and is replaced,
|
|
655
|
+
not migrated online. If retaining development fixtures from that draft, stop
|
|
656
|
+
writers and reconcile or discard those disposable support fixtures and their
|
|
657
|
+
private files offline before adopting this schema. Do not reinterpret old seal
|
|
658
|
+
records as confirmed promotion ownership.
|