@gravito/signal 3.0.3 → 3.0.4
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/CHANGELOG.md +16 -0
- package/README.md +89 -60
- package/README.zh-TW.md +140 -9
- package/dist/MjmlRenderer-IUH663FT.mjs +8 -0
- package/dist/ReactMjmlRenderer-C3P5YO5L.mjs +8 -0
- package/dist/ReactRenderer-2JFLRVST.mjs +45 -0
- package/dist/{ReactRenderer-L5INVYKT.mjs → ReactRenderer-LYEOSYFS.mjs} +9 -8
- package/dist/ReactRenderer-V54CUUEI.mjs +45 -0
- package/dist/VueMjmlRenderer-4F4CXHDB.mjs +8 -0
- package/dist/VueMjmlRenderer-5WZR4CQG.mjs +8 -0
- package/dist/VueMjmlRenderer-U5YMWI44.mjs +8 -0
- package/dist/VueRenderer-3YBRQXME.mjs +48 -0
- package/dist/VueRenderer-46JGXTJ2.mjs +48 -0
- package/dist/VueRenderer-5KWD4R3C.mjs +48 -0
- package/dist/VueRenderer-C23U4O5E.mjs +48 -0
- package/dist/VueRenderer-LEVDFLHP.mjs +31 -0
- package/dist/VueRenderer-RNHSCCRI.mjs +48 -0
- package/dist/chunk-3WOR3XSL.mjs +82 -0
- package/dist/chunk-DBFIVHHG.mjs +79 -0
- package/dist/{chunk-6DZX6EAA.mjs → chunk-HEBXNMVQ.mjs} +12 -1
- package/dist/chunk-KB7IDDBT.mjs +82 -0
- package/dist/chunk-LZL5UUPC.mjs +82 -0
- package/dist/chunk-W6LXIJKK.mjs +57 -0
- package/dist/chunk-XBIVBJS2.mjs +8 -0
- package/dist/index.d.mts +1680 -209
- package/dist/index.d.ts +1680 -209
- package/dist/index.js +69405 -542
- package/dist/index.mjs +993 -110
- package/dist/lib-HJTRWKU5.mjs +67788 -0
- package/dist/{VueRenderer-Z5PRVBNH.mjs → server-renderer-4IM3P5XZ.mjs} +308 -423
- package/dist/server-renderer-7KWFSTPV.mjs +37193 -0
- package/dist/{VueRenderer-S65ZARRI.mjs → server-renderer-S5FPSTJ2.mjs} +931 -877
- package/dist/server-renderer-X5LUFVWT.mjs +37193 -0
- package/doc/OPTIMIZATION_PLAN.md +496 -0
- package/package.json +14 -12
- package/scripts/check-coverage.ts +64 -0
- package/src/Mailable.ts +340 -44
- package/src/OrbitSignal.ts +350 -50
- package/src/TypedMailable.ts +96 -0
- package/src/dev/DevMailbox.ts +89 -33
- package/src/dev/DevServer.ts +14 -14
- package/src/dev/storage/FileMailboxStorage.ts +66 -0
- package/src/dev/storage/MailboxStorage.ts +15 -0
- package/src/dev/storage/MemoryMailboxStorage.ts +36 -0
- package/src/dev/ui/mailbox.ts +1 -1
- package/src/dev/ui/preview.ts +4 -4
- package/src/errors.ts +69 -0
- package/src/events.ts +72 -0
- package/src/index.ts +20 -1
- package/src/renderers/HtmlRenderer.ts +20 -18
- package/src/renderers/MjmlRenderer.ts +73 -0
- package/src/renderers/ReactMjmlRenderer.ts +94 -0
- package/src/renderers/ReactRenderer.ts +26 -21
- package/src/renderers/Renderer.ts +43 -3
- package/src/renderers/TemplateRenderer.ts +48 -15
- package/src/renderers/VueMjmlRenderer.ts +99 -0
- package/src/renderers/VueRenderer.ts +26 -21
- package/src/renderers/mjml-templates.ts +50 -0
- package/src/transports/BaseTransport.ts +148 -0
- package/src/transports/LogTransport.ts +28 -6
- package/src/transports/MemoryTransport.ts +34 -6
- package/src/transports/SesTransport.ts +62 -17
- package/src/transports/SmtpTransport.ts +123 -27
- package/src/transports/Transport.ts +33 -4
- package/src/types.ts +172 -3
- package/src/utils/html.ts +43 -0
- package/src/webhooks/SendGridWebhookDriver.ts +80 -0
- package/src/webhooks/SesWebhookDriver.ts +44 -0
- package/tests/DevMailbox.test.ts +54 -0
- package/tests/FileMailboxStorage.test.ts +56 -0
- package/tests/MjmlLayout.test.ts +28 -0
- package/tests/MjmlRenderer.test.ts +53 -0
- package/tests/OrbitSignalWebhook.test.ts +56 -0
- package/tests/ReactMjmlRenderer.test.ts +33 -0
- package/tests/SendGridWebhookDriver.test.ts +69 -0
- package/tests/SesWebhookDriver.test.ts +46 -0
- package/tests/VueMjmlRenderer.test.ts +35 -0
- package/tests/dev-server.test.ts +1 -1
- package/tests/transports.test.ts +3 -3
- package/tsconfig.json +12 -24
- package/dist/OrbitMail-2Z7ZTKYA.mjs +0 -7
- package/dist/OrbitMail-BGV32HWN.mjs +0 -7
- package/dist/OrbitMail-FUYZQSAV.mjs +0 -7
- package/dist/OrbitMail-NAPCRK7B.mjs +0 -7
- package/dist/OrbitMail-REGJ276B.mjs +0 -7
- package/dist/OrbitMail-TCFBJWDT.mjs +0 -7
- package/dist/OrbitMail-XZZW6U4N.mjs +0 -7
- package/dist/OrbitSignal-IPSA2CDO.mjs +0 -7
- package/dist/OrbitSignal-MABW4DDW.mjs +0 -7
- package/dist/OrbitSignal-QSW5VQ5M.mjs +0 -7
- package/dist/OrbitSignal-R22QHWAA.mjs +0 -7
- package/dist/OrbitSignal-ZKKMEC27.mjs +0 -7
- package/dist/chunk-3U2CYJO5.mjs +0 -367
- package/dist/chunk-3XFC4T6M.mjs +0 -392
- package/dist/chunk-456QRYFW.mjs +0 -401
- package/dist/chunk-DT3R2TNV.mjs +0 -367
- package/dist/chunk-F6MVTUCT.mjs +0 -421
- package/dist/chunk-GADWIVC4.mjs +0 -400
- package/dist/chunk-HHKFAMSE.mjs +0 -380
- package/dist/chunk-NEQCQSZI.mjs +0 -406
- package/dist/chunk-OKRNL6PN.mjs +0 -400
- package/dist/chunk-ULN3GMY2.mjs +0 -367
- package/dist/chunk-XAWO7RSP.mjs +0 -398
- package/dist/chunk-YLVDJSED.mjs +0 -431
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it, mock } from 'bun:test'
|
|
2
|
+
import { ReactMjmlRenderer } from '../src/renderers/ReactMjmlRenderer'
|
|
3
|
+
|
|
4
|
+
describe('ReactMjmlRenderer', () => {
|
|
5
|
+
it('should render React component to MJML then to HTML', async () => {
|
|
6
|
+
const mockComponent = {}
|
|
7
|
+
const mockElement = { type: 'mjml' }
|
|
8
|
+
const mockMjml = '<mjml><mj-body>Hello</mj-body></mjml>'
|
|
9
|
+
const mockHtml = '<html><body>Hello</body></html>'
|
|
10
|
+
|
|
11
|
+
const createElement = mock(() => mockElement)
|
|
12
|
+
const renderToStaticMarkup = mock(() => mockMjml)
|
|
13
|
+
const mjml2html = mock(() => ({ html: mockHtml, errors: [] }))
|
|
14
|
+
|
|
15
|
+
const renderer = new ReactMjmlRenderer(
|
|
16
|
+
mockComponent,
|
|
17
|
+
{ name: 'World' },
|
|
18
|
+
{},
|
|
19
|
+
{
|
|
20
|
+
createElement,
|
|
21
|
+
renderToStaticMarkup,
|
|
22
|
+
mjml2html,
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
const result = await renderer.render({ extra: 'data' })
|
|
27
|
+
|
|
28
|
+
expect(createElement).toHaveBeenCalledWith(mockComponent, { name: 'World', extra: 'data' })
|
|
29
|
+
expect(renderToStaticMarkup).toHaveBeenCalledWith(mockElement)
|
|
30
|
+
expect(mjml2html).toHaveBeenCalledWith(mockMjml, expect.any(Object))
|
|
31
|
+
expect(result.html).toBe(mockHtml)
|
|
32
|
+
})
|
|
33
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test'
|
|
2
|
+
import type { GravitoContext } from '@gravito/core'
|
|
3
|
+
import { SendGridWebhookDriver } from '../src/webhooks/SendGridWebhookDriver'
|
|
4
|
+
|
|
5
|
+
describe('SendGridWebhookDriver', () => {
|
|
6
|
+
it('should parse batch events from request body', async () => {
|
|
7
|
+
const driver = new SendGridWebhookDriver()
|
|
8
|
+
|
|
9
|
+
const mockEvents = [
|
|
10
|
+
{ event: 'delivered', email: 'user1@example.com', timestamp: 123456789 },
|
|
11
|
+
{ event: 'opened', email: 'user1@example.com', timestamp: 123456790 },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
const mockCtx = {
|
|
15
|
+
req: {
|
|
16
|
+
json: async () => mockEvents,
|
|
17
|
+
header: () => undefined,
|
|
18
|
+
},
|
|
19
|
+
} as unknown as GravitoContext
|
|
20
|
+
|
|
21
|
+
const result = await driver.handle(mockCtx)
|
|
22
|
+
|
|
23
|
+
expect(result).toHaveLength(2)
|
|
24
|
+
expect(result?.[0].event).toBe('delivered')
|
|
25
|
+
expect(result?.[1].event).toBe('opened')
|
|
26
|
+
expect(result?.[0].payload.email).toBe('user1@example.com')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should handle single event body', async () => {
|
|
30
|
+
const driver = new SendGridWebhookDriver()
|
|
31
|
+
const mockEvent = { event: 'bounced', email: 'bad@example.com' }
|
|
32
|
+
|
|
33
|
+
const mockCtx = {
|
|
34
|
+
req: {
|
|
35
|
+
json: async () => mockEvent,
|
|
36
|
+
header: () => undefined,
|
|
37
|
+
},
|
|
38
|
+
} as unknown as GravitoContext
|
|
39
|
+
|
|
40
|
+
const result = await driver.handle(mockCtx)
|
|
41
|
+
expect(result).toHaveLength(1)
|
|
42
|
+
expect(result?.[0].event).toBe('bounced')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should return null for empty body', async () => {
|
|
46
|
+
const driver = new SendGridWebhookDriver()
|
|
47
|
+
const mockCtx = {
|
|
48
|
+
req: {
|
|
49
|
+
json: async () => [],
|
|
50
|
+
header: () => undefined,
|
|
51
|
+
},
|
|
52
|
+
} as unknown as GravitoContext
|
|
53
|
+
|
|
54
|
+
const result = await driver.handle(mockCtx)
|
|
55
|
+
expect(result).toBeNull()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should throw if public key is set but signature is missing', async () => {
|
|
59
|
+
const driver = new SendGridWebhookDriver({ publicKey: 'some-key' })
|
|
60
|
+
const mockCtx = {
|
|
61
|
+
req: {
|
|
62
|
+
json: async () => [{ event: 'test' }],
|
|
63
|
+
header: (_name: string) => undefined,
|
|
64
|
+
},
|
|
65
|
+
} as unknown as GravitoContext
|
|
66
|
+
|
|
67
|
+
expect(driver.handle(mockCtx)).rejects.toThrow('Missing SendGrid signature headers')
|
|
68
|
+
})
|
|
69
|
+
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test'
|
|
2
|
+
import type { GravitoContext } from '@gravito/core'
|
|
3
|
+
import { SesWebhookDriver } from '../src/webhooks/SesWebhookDriver'
|
|
4
|
+
|
|
5
|
+
describe('SesWebhookDriver', () => {
|
|
6
|
+
it('should parse SNS notification events', async () => {
|
|
7
|
+
const driver = new SesWebhookDriver()
|
|
8
|
+
|
|
9
|
+
const mockSnsBody = {
|
|
10
|
+
Type: 'Notification',
|
|
11
|
+
Message: JSON.stringify({
|
|
12
|
+
notificationType: 'Bounce',
|
|
13
|
+
bounce: { bounceType: 'Permanent', bounceSubType: 'General' },
|
|
14
|
+
}),
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const mockCtx = {
|
|
18
|
+
req: {
|
|
19
|
+
json: async () => mockSnsBody,
|
|
20
|
+
},
|
|
21
|
+
} as unknown as GravitoContext
|
|
22
|
+
|
|
23
|
+
const result = await driver.handle(mockCtx)
|
|
24
|
+
|
|
25
|
+
expect(result).toHaveLength(1)
|
|
26
|
+
expect(result?.[0].event).toBe('bounce')
|
|
27
|
+
expect(result?.[0].payload.bounce.bounceType).toBe('Permanent')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should handle subscription confirmation', async () => {
|
|
31
|
+
const driver = new SesWebhookDriver()
|
|
32
|
+
const mockSnsBody = {
|
|
33
|
+
Type: 'SubscriptionConfirmation',
|
|
34
|
+
SubscribeURL: 'https://sns.aws.com/confirm',
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const mockCtx = {
|
|
38
|
+
req: {
|
|
39
|
+
json: async () => mockSnsBody,
|
|
40
|
+
},
|
|
41
|
+
} as unknown as GravitoContext
|
|
42
|
+
|
|
43
|
+
const result = await driver.handle(mockCtx)
|
|
44
|
+
expect(result?.[0].event).toBe('sns:subscription')
|
|
45
|
+
})
|
|
46
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, it, mock } from 'bun:test'
|
|
2
|
+
import { VueMjmlRenderer } from '../src/renderers/VueMjmlRenderer'
|
|
3
|
+
|
|
4
|
+
describe('VueMjmlRenderer', () => {
|
|
5
|
+
it('should render Vue component to MJML then to HTML', async () => {
|
|
6
|
+
const mockComponent = { name: 'Test' }
|
|
7
|
+
const mockApp = { _context: {} }
|
|
8
|
+
const mockMjml = '<mjml><mj-body>Vue MJML</mj-body></mjml>'
|
|
9
|
+
const mockHtml = '<html><body>Vue MJML</body></html>'
|
|
10
|
+
|
|
11
|
+
const createSSRApp = mock(() => mockApp)
|
|
12
|
+
const h = mock(() => ({}))
|
|
13
|
+
const renderToString = mock(async () => mockMjml)
|
|
14
|
+
const mjml2html = mock(() => ({ html: mockHtml, errors: [] }))
|
|
15
|
+
|
|
16
|
+
const renderer = new VueMjmlRenderer(
|
|
17
|
+
mockComponent,
|
|
18
|
+
{ name: 'World' },
|
|
19
|
+
{},
|
|
20
|
+
{
|
|
21
|
+
createSSRApp,
|
|
22
|
+
h,
|
|
23
|
+
renderToString,
|
|
24
|
+
mjml2html,
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
const result = await renderer.render({ extra: 'data' })
|
|
29
|
+
|
|
30
|
+
expect(createSSRApp).toHaveBeenCalled()
|
|
31
|
+
expect(renderToString).toHaveBeenCalledWith(mockApp)
|
|
32
|
+
expect(mjml2html).toHaveBeenCalledWith(mockMjml, expect.any(Object))
|
|
33
|
+
expect(result.html).toBe(mockHtml)
|
|
34
|
+
})
|
|
35
|
+
})
|
package/tests/dev-server.test.ts
CHANGED
|
@@ -20,7 +20,7 @@ const createCore = () => {
|
|
|
20
20
|
describe('DevServer', () => {
|
|
21
21
|
it('registers mailbox routes and serves entries', async () => {
|
|
22
22
|
const mailbox = new DevMailbox()
|
|
23
|
-
const entry = mailbox.add({
|
|
23
|
+
const entry = await mailbox.add({
|
|
24
24
|
from: { address: 'from@example.com' },
|
|
25
25
|
to: [{ address: 'to@example.com' }],
|
|
26
26
|
subject: 'Hello',
|
package/tests/transports.test.ts
CHANGED
|
@@ -19,7 +19,7 @@ describe('Transports', () => {
|
|
|
19
19
|
|
|
20
20
|
await transport.send(message)
|
|
21
21
|
|
|
22
|
-
const entries = mailbox.list()
|
|
22
|
+
const entries = await mailbox.list()
|
|
23
23
|
expect(entries).toHaveLength(1)
|
|
24
24
|
|
|
25
25
|
const entry = entries[0]
|
|
@@ -44,9 +44,9 @@ describe('Transports', () => {
|
|
|
44
44
|
})
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
expect(mailbox.list().length).toBeLessThanOrEqual(50)
|
|
47
|
+
expect((await mailbox.list()).length).toBeLessThanOrEqual(50)
|
|
48
48
|
// Should be the latest ones (last one added is index 0)
|
|
49
|
-
expect(mailbox.list()[0].envelope.subject).toBe('Msg 59')
|
|
49
|
+
expect((await mailbox.list())[0].envelope.subject).toBe('Msg 59')
|
|
50
50
|
})
|
|
51
51
|
})
|
|
52
52
|
})
|
package/tsconfig.json
CHANGED
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
],
|
|
10
|
-
"@gravito/*": [
|
|
11
|
-
"../../packages/*/src/index.ts"
|
|
12
|
-
]
|
|
13
|
-
},
|
|
14
|
-
"types": [
|
|
15
|
-
"bun-types"
|
|
16
|
-
]
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"baseUrl": ".",
|
|
6
|
+
"paths": {
|
|
7
|
+
"@gravito/core": ["../../packages/core/src/index.ts"],
|
|
8
|
+
"@gravito/*": ["../../packages/*/src/index.ts"]
|
|
17
9
|
},
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"dist",
|
|
24
|
-
"**/*.test.ts"
|
|
25
|
-
]
|
|
26
|
-
}
|
|
10
|
+
"types": ["bun-types"]
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"],
|
|
13
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
14
|
+
}
|