@antelopejs/dms-mailing 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -4
- package/dist/crons/jobs.d.ts +1 -1
- package/dist/data/body.js +2 -1
- package/dist/data/body.js.map +1 -1
- package/dist/data/templates-table.js +4 -3
- package/dist/data/templates-table.js.map +1 -1
- package/dist/db/models/template-versions.model.js.map +1 -1
- package/dist/db/models/templates.model.js +2 -1
- package/dist/db/models/templates.model.js.map +1 -1
- package/dist/engine/changes.js +2 -1
- package/dist/engine/changes.js.map +1 -1
- package/dist/engine/conditions.js +2 -3
- package/dist/engine/conditions.js.map +1 -1
- package/dist/engine/fallback-html.js +8 -8
- package/dist/engine/fallback-html.js.map +1 -1
- package/dist/engine/formats.js +6 -6
- package/dist/engine/formats.js.map +1 -1
- package/dist/engine/paths.js +2 -3
- package/dist/engine/paths.js.map +1 -1
- package/dist/engine/system-variables.js +1 -1
- package/dist/engine/system-variables.js.map +1 -1
- package/dist/engine/tokens.js.map +1 -1
- package/dist/pages/sends.js.map +1 -1
- package/dist/pages/toolbar.js.map +1 -1
- package/dist/routes/events.js +2 -2
- package/dist/routes/events.js.map +1 -1
- package/dist/routes/metrics.js +6 -5
- package/dist/routes/metrics.js.map +1 -1
- package/dist/routes/sends.js +1 -1
- package/dist/routes/sends.js.map +1 -1
- package/dist/routes/settings.js +6 -6
- package/dist/routes/settings.js.map +1 -1
- package/dist/routes/templates.js +4 -4
- package/dist/routes/templates.js.map +1 -1
- package/dist/services/attention.js +2 -1
- package/dist/services/attention.js.map +1 -1
- package/dist/services/categories.js +6 -6
- package/dist/services/categories.js.map +1 -1
- package/dist/services/checked-send.js +16 -9
- package/dist/services/checked-send.js.map +1 -1
- package/dist/services/declarations.js.map +1 -1
- package/dist/services/events.js +11 -7
- package/dist/services/events.js.map +1 -1
- package/dist/services/localized-text.d.ts +2 -1
- package/dist/services/localized-text.js +2 -1
- package/dist/services/localized-text.js.map +1 -1
- package/dist/services/metrics.js.map +1 -1
- package/dist/services/render.js.map +1 -1
- package/dist/services/send-import.js +7 -3
- package/dist/services/send-import.js.map +1 -1
- package/dist/services/send.js +4 -3
- package/dist/services/send.js.map +1 -1
- package/dist/services/starters.js +5 -5
- package/dist/services/starters.js.map +1 -1
- package/dist/services/template-stats.js +5 -2
- package/dist/services/template-stats.js.map +1 -1
- package/dist/services/templates.js +6 -2
- package/dist/services/templates.js.map +1 -1
- package/dist/validation/declarations.schema.d.ts +16 -16
- package/dist/validation/declarations.schema.js +2 -2
- package/dist/validation/declarations.schema.js.map +1 -1
- package/dist/validation/guards.d.ts +4 -0
- package/dist/validation/guards.js +19 -0
- package/dist/validation/guards.js.map +1 -0
- package/dist/validation/send-event-type.schema.d.ts +2 -0
- package/dist/validation/send-event-type.schema.js +11 -0
- package/dist/validation/send-event-type.schema.js.map +1 -0
- package/dist/validation/settings.schema.js +1 -1
- package/dist/validation/settings.schema.js.map +1 -1
- package/dist/validation/templates.schema.d.ts +19 -18
- package/dist/validation/templates.schema.js.map +1 -1
- package/frontend-vue/app/build/components/TemplateDrawerFooter.vue +45 -0
- package/frontend-vue/app/build/components/TemplateDrawerPerformance.vue +102 -0
- package/frontend-vue/app/build/components/TemplateDrawerVariables.vue +110 -0
- package/frontend-vue/app/build/composables/useDrawerStats.ts +78 -0
- package/frontend-vue/app/components/DuplicateModal.vue +3 -11
- package/frontend-vue/app/components/FixAddressModal.vue +2 -1
- package/frontend-vue/app/components/NewTemplateModal.vue +3 -11
- package/frontend-vue/app/components/RealSendModal.vue +6 -17
- package/frontend-vue/app/components/RenderingModal.vue +2 -1
- package/frontend-vue/app/components/SendDrawer.vue +5 -4
- package/frontend-vue/app/components/StarterGallery.vue +3 -11
- package/frontend-vue/app/components/TemplateDrawer.vue +40 -269
- package/frontend-vue/app/components/TestSendModal.vue +7 -18
- package/frontend-vue/app/components/VersionHistory.vue +2 -7
- package/frontend-vue/app/components/WebhookStatus.vue +2 -1
- package/frontend-vue/app/components/editor/EditorWorkspace.vue +2 -7
- package/frontend-vue/build/backend-boundary.ts +122 -0
- package/frontend-vue/dms.frontend.build.ts +7 -0
- package/frontend-vue/eslint.config.mjs +13 -0
- package/frontend-vue/package.json +4 -2
- package/frontend-vue/pnpm-lock.yaml +210 -61
- package/frontend-vue/tests/backend-boundary.test.ts +203 -0
- package/frontend-vue/tests/dnd.test.ts +1 -2
- package/frontend-vue/tests/editor-block-list.test.ts +136 -53
- package/frontend-vue/tests/helpers/auth-fetch.ts +123 -0
- package/frontend-vue/tests/helpers/nuxt-globals.ts +17 -1
- package/frontend-vue/tests/new-template-modal.test.ts +41 -6
- package/frontend-vue/tests/page-reads.test.ts +26 -6
- package/frontend-vue/tests/send-actions.test.ts +0 -1
- package/frontend-vue/tests/send-drawer.test.ts +2 -6
- package/frontend-vue/tests/send-modals.test.ts +8 -5
- package/frontend-vue/tests/sortable-list.test.ts +54 -62
- package/frontend-vue/tests/suppression.test.ts +1 -2
- package/frontend-vue/tests/template-drawer.test.ts +27 -18
- package/frontend-vue/tests/template-gallery.test.ts +7 -5
- package/frontend-vue/tests/template-preview-frame.test.ts +2 -5
- package/package.json +3 -8
- package/skills/dms-mailing/SKILL.md +3 -3
- package/skills/dms-mailing/cases.json +49 -0
- package/src/crons/jobs.ts +1 -1
- package/src/data/body.ts +2 -1
- package/src/data/templates-table.ts +12 -7
- package/src/db/models/template-versions.model.ts +5 -1
- package/src/db/models/templates.model.ts +6 -3
- package/src/engine/changes.ts +3 -2
- package/src/engine/conditions.ts +2 -4
- package/src/engine/fallback-html.ts +13 -13
- package/src/engine/formats.ts +6 -6
- package/src/engine/paths.ts +4 -3
- package/src/engine/system-variables.ts +4 -3
- package/src/engine/tokens.ts +1 -2
- package/src/pages/sends.ts +5 -3
- package/src/pages/templates.ts +1 -1
- package/src/pages/toolbar.ts +4 -2
- package/src/routes/events.ts +3 -6
- package/src/routes/metrics.ts +7 -5
- package/src/routes/sends.ts +10 -18
- package/src/routes/settings.ts +8 -9
- package/src/routes/suppressions.ts +1 -1
- package/src/routes/templates.ts +5 -5
- package/src/services/attention.ts +4 -3
- package/src/services/categories.ts +6 -6
- package/src/services/checked-send.ts +17 -19
- package/src/services/declarations.ts +3 -5
- package/src/services/events.ts +16 -13
- package/src/services/localized-text.ts +4 -2
- package/src/services/metrics.ts +2 -2
- package/src/services/notify.ts +1 -1
- package/src/services/render.ts +5 -1
- package/src/services/send-import.ts +16 -11
- package/src/services/send.ts +7 -7
- package/src/services/starters.ts +6 -6
- package/src/services/template-stats.ts +11 -4
- package/src/services/templates.ts +10 -8
- package/src/validation/declarations.schema.ts +2 -2
- package/src/validation/guards.ts +25 -0
- package/src/validation/send-event-type.schema.ts +10 -0
- package/src/validation/settings.schema.ts +7 -2
- package/src/validation/templates.schema.ts +2 -1
- package/frontend-vue/tests/i18n-editor.test.ts +0 -50
- package/frontend-vue/tests/i18n.test.ts +0 -138
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
useEditorShortcuts,
|
|
12
12
|
} from '../../composables/useEditorShortcuts'
|
|
13
13
|
import { createEditorState } from '../../composables/useTemplateEditor'
|
|
14
|
-
import { apiErrorMessage } from '../../utils/api-error'
|
|
15
14
|
|
|
16
15
|
interface Props {
|
|
17
16
|
loaded: TemplateContentResponse
|
|
@@ -23,8 +22,7 @@ const props = defineProps<Props>()
|
|
|
23
22
|
const locale = defineModel<string | null>('locale', { default: null })
|
|
24
23
|
const emit = defineEmits<{ renamed: [string] }>()
|
|
25
24
|
|
|
26
|
-
const
|
|
27
|
-
const { processApiMessage } = useTranslation()
|
|
25
|
+
const { presentError } = useApiErrorPresenter()
|
|
28
26
|
const { uniqueLocales } = useUniqueLocales()
|
|
29
27
|
const api = useMailingApi()
|
|
30
28
|
|
|
@@ -44,10 +42,7 @@ const editor = createEditorState(
|
|
|
44
42
|
)
|
|
45
43
|
|
|
46
44
|
function reportFailure(error: unknown): void {
|
|
47
|
-
|
|
48
|
-
color: 'error',
|
|
49
|
-
title: processApiMessage(apiErrorMessage(error)),
|
|
50
|
-
})
|
|
45
|
+
presentError(error, { fallbackKey: 'error.500.description' })
|
|
51
46
|
}
|
|
52
47
|
|
|
53
48
|
const reads = useEditorReads(props.templateId)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs'
|
|
2
|
+
import { dirname, isAbsolute, join, relative, sep } from 'node:path'
|
|
3
|
+
import type { DmsVitePluginEntry } from '#dms/frontend-build'
|
|
4
|
+
|
|
5
|
+
type VitePlugin = Extract<DmsVitePluginEntry, { name: string }>
|
|
6
|
+
|
|
7
|
+
const BACKEND_PACKAGE = '@antelopejs/dms-mailing'
|
|
8
|
+
const BACKEND_SOURCE = 'src'
|
|
9
|
+
const QUERY_OR_HASH = /[?#].*$/
|
|
10
|
+
|
|
11
|
+
const backendRoots = new Map<string, string | null>()
|
|
12
|
+
|
|
13
|
+
/** Whether a parsed manifest names its package. */
|
|
14
|
+
function isNamedManifest(value: unknown): value is { name: string } {
|
|
15
|
+
return (
|
|
16
|
+
typeof value === 'object' &&
|
|
17
|
+
value !== null &&
|
|
18
|
+
'name' in value &&
|
|
19
|
+
typeof value.name === 'string'
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The package name a `package.json` declares, or `undefined`. */
|
|
24
|
+
function packageName(manifest: string): string | undefined {
|
|
25
|
+
try {
|
|
26
|
+
const parsed: unknown = JSON.parse(readFileSync(manifest, 'utf8'))
|
|
27
|
+
return isNamedManifest(parsed) ? parsed.name : undefined
|
|
28
|
+
} catch {
|
|
29
|
+
return undefined
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The directory of the backend package that holds `directory`, or null. */
|
|
34
|
+
function backendRoot(directory: string): string | null {
|
|
35
|
+
const known = backendRoots.get(directory)
|
|
36
|
+
if (known !== undefined) {
|
|
37
|
+
return known
|
|
38
|
+
}
|
|
39
|
+
const manifest = join(directory, 'package.json')
|
|
40
|
+
const parent = dirname(directory)
|
|
41
|
+
let root: string | null = null
|
|
42
|
+
if (existsSync(manifest)) {
|
|
43
|
+
root = packageName(manifest) === BACKEND_PACKAGE ? directory : null
|
|
44
|
+
} else if (parent !== directory) {
|
|
45
|
+
root = backendRoot(parent)
|
|
46
|
+
}
|
|
47
|
+
backendRoots.set(directory, root)
|
|
48
|
+
return root
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The real path of a resolved module id when it lies under the `src`
|
|
53
|
+
* directory of the backend package, or `undefined`. The package that owns the
|
|
54
|
+
* file decides, not a path, so the answer is the same in the repository and in
|
|
55
|
+
* the build workspace. Virtual ids and ids that are not files are ignored.
|
|
56
|
+
*/
|
|
57
|
+
function backendSourceFile(id: string): string | undefined {
|
|
58
|
+
const path = id.replace(QUERY_OR_HASH, '')
|
|
59
|
+
if (!isAbsolute(path)) {
|
|
60
|
+
return undefined
|
|
61
|
+
}
|
|
62
|
+
let real: string
|
|
63
|
+
try {
|
|
64
|
+
real = realpathSync(path)
|
|
65
|
+
} catch {
|
|
66
|
+
return undefined
|
|
67
|
+
}
|
|
68
|
+
const root = backendRoot(dirname(real))
|
|
69
|
+
if (root === null) {
|
|
70
|
+
return undefined
|
|
71
|
+
}
|
|
72
|
+
return relative(root, real).split(sep)[0] === BACKEND_SOURCE
|
|
73
|
+
? real
|
|
74
|
+
: undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Fails the build and the dev server when a module of the frontend resolves to
|
|
79
|
+
* a file under the `src` of the backend package: the browser reaches the
|
|
80
|
+
* backend only through its HTTP interface. It checks what the whole resolution
|
|
81
|
+
* chain returns, an id marked external included, so an alias is seen through
|
|
82
|
+
* and a symlink the resolver returns is followed to its real path, and it runs
|
|
83
|
+
* before the other plugins (`enforce: "pre"`). Vite builds workers with their
|
|
84
|
+
* own plugin list, so the plugin adds itself there too.
|
|
85
|
+
*
|
|
86
|
+
* antelopejs-sync writes this file from `@antelopejs/tooling-configs` and
|
|
87
|
+
* restores it on every run: change the plugin in the pack, not here.
|
|
88
|
+
*/
|
|
89
|
+
export function backendBoundary(): VitePlugin {
|
|
90
|
+
return {
|
|
91
|
+
...boundaryCheck(),
|
|
92
|
+
config: () => ({ worker: { plugins: () => [boundaryCheck()] } }),
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The check alone, as a worker build runs it. */
|
|
97
|
+
function boundaryCheck(): VitePlugin {
|
|
98
|
+
return {
|
|
99
|
+
name: `${BACKEND_PACKAGE}:backend-boundary`,
|
|
100
|
+
enforce: 'pre',
|
|
101
|
+
async resolveId(source, importer, options) {
|
|
102
|
+
const resolved = await this.resolve(source, importer, {
|
|
103
|
+
...options,
|
|
104
|
+
skipSelf: true,
|
|
105
|
+
})
|
|
106
|
+
if (resolved === null) {
|
|
107
|
+
return resolved
|
|
108
|
+
}
|
|
109
|
+
const file = backendSourceFile(resolved.id)
|
|
110
|
+
if (file === undefined) {
|
|
111
|
+
return resolved
|
|
112
|
+
}
|
|
113
|
+
const from =
|
|
114
|
+
importer === undefined
|
|
115
|
+
? 'an entry point'
|
|
116
|
+
: importer.replace(QUERY_OR_HASH, '')
|
|
117
|
+
return this.error(
|
|
118
|
+
`Backend boundary: ${from} imports ${file}, which is under the src of ${BACKEND_PACKAGE}. The frontend reaches the backend only through its HTTP interface.`,
|
|
119
|
+
)
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineDmsFrontendBuild } from '#dms/frontend-build'
|
|
2
|
+
import { backendBoundary } from './build/backend-boundary.ts'
|
|
3
|
+
|
|
4
|
+
/** The build of the frontend module: the backend boundary in every build. */
|
|
5
|
+
export default defineDmsFrontendBuild((build) => {
|
|
6
|
+
build.registerVitePlugins(() => [backendBoundary()])
|
|
7
|
+
})
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import antiSlop from '@antelopejs/tooling-configs/oxc/anti-slop'
|
|
2
|
+
import guardrails from '@antelopejs/tooling-configs/oxc/guardrails'
|
|
1
3
|
import vue from 'eslint-plugin-vue'
|
|
2
4
|
import ts from 'typescript-eslint'
|
|
3
5
|
|
|
@@ -10,4 +12,15 @@ export default [
|
|
|
10
12
|
rules: { 'vue/multi-word-component-names': 'off' },
|
|
11
13
|
},
|
|
12
14
|
{ files: ['**/*.ts'], languageOptions: { parser: ts.parser } },
|
|
15
|
+
{
|
|
16
|
+
files: ['tests/**/*.ts'],
|
|
17
|
+
plugins: { antelopejs: guardrails, 'anti-slop': antiSlop },
|
|
18
|
+
rules: {
|
|
19
|
+
'antelopejs/no-fs-read-in-tests': 'error',
|
|
20
|
+
'antelopejs/no-constant-value-assertion': 'error',
|
|
21
|
+
'antelopejs/no-typeof-function-only-test': 'error',
|
|
22
|
+
'antelopejs/no-self-import-in-tests': 'error',
|
|
23
|
+
'anti-slop/no-module-mocking': 'error',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
13
26
|
]
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"packageManager": "pnpm@10.2.0",
|
|
8
8
|
"engines": {
|
|
9
|
-
"@antelopejs/dms-frontend": ">=0.9.
|
|
9
|
+
"@antelopejs/dms-frontend": ">=0.9.1 <0.10.0"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"format": "prettier --write .",
|
|
13
|
-
"lint": "eslint .",
|
|
13
|
+
"lint": "eslint . && node --input-type=module -e \"import { assertApiErrorPresentation } from '@antelopejs/dms/checks/api-error-presentation'; assertApiErrorPresentation(['app']);\"",
|
|
14
14
|
"lint:fix": "eslint . --fix",
|
|
15
15
|
"test": "vitest run"
|
|
16
16
|
},
|
|
@@ -21,12 +21,14 @@
|
|
|
21
21
|
"vue": "^3.5.18"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@antelopejs/tooling-configs": "^0.2.12",
|
|
24
25
|
"@nuxt/ui": "4.10.0",
|
|
25
26
|
"@vitejs/plugin-vue": "^6.0.0",
|
|
26
27
|
"@vitest/runner": "^4.1.5",
|
|
27
28
|
"eslint": "^9.0.0",
|
|
28
29
|
"eslint-plugin-vue": "^10.0.0",
|
|
29
30
|
"typescript-eslint": "^8.0.0",
|
|
31
|
+
"vite": "^8.2.2",
|
|
30
32
|
"jsdom": "^26",
|
|
31
33
|
"prettier": "^3.5.3",
|
|
32
34
|
"prettier-plugin-tailwindcss": "^0.6.11",
|