@mettlecast/domain-cli 0.2.52 → 0.2.53
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/dist/builder/build-registry.js +9 -0
- package/dist/templates/api-skeleton.js +1 -0
- package/dist/templates/patterns/api/create-with-event.js +1 -0
- package/dist/templates/patterns/api/idempotent-mutation.js +1 -0
- package/dist/templates/patterns/api/paginated-list.js +1 -0
- package/dist/templates/patterns/api/simple-crud.js +2 -0
- package/dist/templates/patterns/api/streaming-list.js +1 -0
- package/dist/templates/patterns/api/system-admin.js +2 -0
- package/dist/templates/patterns/api/webhook-receiver-style.js +1 -0
- package/dist/templates/patterns/subscriber/audit-relay.js +15 -0
- package/dist/templates/patterns/subscriber/cascade-deletion.js +1 -0
- package/dist/templates/patterns/subscriber/single-step-projection.js +1 -0
- package/dist/templates/subscriber-skeleton.js +1 -0
- package/package.json +1 -1
- package/src/__tests__/build-registry.test.ts +29 -2
- package/src/__tests__/smoke/scaffold.test.ts +5 -0
- package/src/__tests__/template-outbound-access.test.ts +26 -0
- package/src/builder/build-registry.ts +10 -0
- package/src/templates/api-skeleton.ts +1 -0
- package/src/templates/patterns/api/create-with-event.ts +1 -0
- package/src/templates/patterns/api/idempotent-mutation.ts +1 -0
- package/src/templates/patterns/api/paginated-list.ts +1 -0
- package/src/templates/patterns/api/simple-crud.ts +2 -0
- package/src/templates/patterns/api/streaming-list.ts +1 -0
- package/src/templates/patterns/api/system-admin.ts +2 -0
- package/src/templates/patterns/api/webhook-receiver-style.ts +1 -0
- package/src/templates/patterns/subscriber/audit-relay.ts +15 -0
- package/src/templates/patterns/subscriber/cascade-deletion.ts +1 -0
- package/src/templates/patterns/subscriber/single-step-projection.ts +1 -0
- package/src/templates/subscriber-skeleton.ts +1 -0
|
@@ -39,6 +39,9 @@ export async function buildRegistry(domainRoot) {
|
|
|
39
39
|
function deployment(raw) {
|
|
40
40
|
return raw['deployment'];
|
|
41
41
|
}
|
|
42
|
+
function outboundAccess(raw) {
|
|
43
|
+
return raw['outboundAccess'] === 'internet' ? 'internet' : 'internal';
|
|
44
|
+
}
|
|
42
45
|
const domainExports = await load(paths.domain);
|
|
43
46
|
const domainRaw = domainExports.find(e => e['_kind'] === 'domain');
|
|
44
47
|
if (!domainRaw) {
|
|
@@ -90,6 +93,7 @@ export async function buildRegistry(domainRoot) {
|
|
|
90
93
|
authType: e['auth']?.type ?? 'jwt',
|
|
91
94
|
description: typeof e['description'] === 'string' ? e['description'] : undefined,
|
|
92
95
|
deployment: deployment(e),
|
|
96
|
+
outboundAccess: outboundAccess(e),
|
|
93
97
|
requestSchema: latestVersion?.requestSchema,
|
|
94
98
|
responseSchema: latestVersion?.responseSchema,
|
|
95
99
|
versions: versionSnapshots.length > 0 ? versionSnapshots : undefined,
|
|
@@ -107,6 +111,7 @@ export async function buildRegistry(domainRoot) {
|
|
|
107
111
|
hmacAlgorithm: e['verification']?.type,
|
|
108
112
|
hmacSecretRef: e['verification']?.secretRef,
|
|
109
113
|
deployment: deployment(e),
|
|
114
|
+
outboundAccess: outboundAccess(e),
|
|
110
115
|
})));
|
|
111
116
|
const subscribers = paths.subscribers.flatMap((filePath, i) => (subscriberExports[i] ?? [])
|
|
112
117
|
.filter(e => e['_kind'] === 'subscriber')
|
|
@@ -118,6 +123,7 @@ export async function buildRegistry(domainRoot) {
|
|
|
118
123
|
semverRange: String(e['semverRange']),
|
|
119
124
|
concurrency: e['concurrency'],
|
|
120
125
|
deployment: deployment(e),
|
|
126
|
+
outboundAccess: outboundAccess(e),
|
|
121
127
|
})));
|
|
122
128
|
const schedules = paths.schedules.flatMap((filePath, i) => (scheduleExports[i] ?? [])
|
|
123
129
|
.filter(e => e['_kind'] === 'schedule')
|
|
@@ -128,6 +134,7 @@ export async function buildRegistry(domainRoot) {
|
|
|
128
134
|
cron: String(e['cron']),
|
|
129
135
|
enabled: Boolean(e['enabled'] ?? true),
|
|
130
136
|
deployment: deployment(e),
|
|
137
|
+
outboundAccess: outboundAccess(e),
|
|
131
138
|
})));
|
|
132
139
|
const jobs = paths.jobs.flatMap((filePath, i) => (jobExports[i] ?? [])
|
|
133
140
|
.filter(e => e['_kind'] === 'job')
|
|
@@ -138,6 +145,7 @@ export async function buildRegistry(domainRoot) {
|
|
|
138
145
|
maxRetries: Number(e['maxRetries'] ?? 3),
|
|
139
146
|
visibilityTimeoutSeconds: Number(e['visibilityTimeoutSeconds'] ?? 30),
|
|
140
147
|
deployment: deployment(e),
|
|
148
|
+
outboundAccess: outboundAccess(e),
|
|
141
149
|
})));
|
|
142
150
|
const actions = paths.actions.flatMap((filePath, i) => (actionExports[i] ?? [])
|
|
143
151
|
.filter(e => e['_kind'] === 'action')
|
|
@@ -149,6 +157,7 @@ export async function buildRegistry(domainRoot) {
|
|
|
149
157
|
idempotent: Boolean(e['idempotent'] ?? false),
|
|
150
158
|
description: typeof e['description'] === 'string' ? e['description'] : undefined,
|
|
151
159
|
deployment: deployment(e),
|
|
160
|
+
outboundAccess: outboundAccess(e),
|
|
152
161
|
inputSchema: isJsonSchema(e['input']) ? e['input'] : undefined,
|
|
153
162
|
outputSchema: isJsonSchema(e['output']) ? e['output'] : undefined,
|
|
154
163
|
})));
|
|
@@ -43,6 +43,7 @@ export const ${varName} = defineApi({
|
|
|
43
43
|
id: '${id}',
|
|
44
44
|
path: '${tenantPath}/${domain}/${id}',
|
|
45
45
|
tenancy: '${tenancy}',
|
|
46
|
+
outboundAccess: 'internal',
|
|
46
47
|
versions: {
|
|
47
48
|
v1: {
|
|
48
49
|
status: 'stable',
|
|
@@ -92,6 +93,7 @@ export const ${varName}List = defineApi({
|
|
|
92
93
|
id: '${id}-list',
|
|
93
94
|
path: '${tenantPath}/${domain}/${id}-list',
|
|
94
95
|
tenancy: '${tenancy}',
|
|
96
|
+
outboundAccess: 'internal',
|
|
95
97
|
versions: {
|
|
96
98
|
v1: {
|
|
97
99
|
status: 'stable',
|
|
@@ -44,6 +44,7 @@ export const ${varName} = defineApi({
|
|
|
44
44
|
id: '${id}',
|
|
45
45
|
path: '/system/${domain}/${id}',
|
|
46
46
|
tenancy: '${tenancy}',
|
|
47
|
+
outboundAccess: 'internal',
|
|
47
48
|
versions: {
|
|
48
49
|
v1: {
|
|
49
50
|
status: 'stable',
|
|
@@ -81,6 +82,7 @@ export const ${varName}Health = defineApi({
|
|
|
81
82
|
id: '${id}-health',
|
|
82
83
|
path: '/system/${domain}/${id}-health',
|
|
83
84
|
tenancy: '${tenancy}',
|
|
85
|
+
outboundAccess: 'internal',
|
|
84
86
|
versions: {
|
|
85
87
|
v1: {
|
|
86
88
|
status: 'stable',
|
|
@@ -19,6 +19,7 @@ export const ${varName} = defineSubscriber({
|
|
|
19
19
|
id: '${domain}.${id}',
|
|
20
20
|
event: '${event}',
|
|
21
21
|
semverRange: '^1',
|
|
22
|
+
outboundAccess: 'internet',
|
|
22
23
|
handler: async (event, ctx) => {
|
|
23
24
|
const ev = event as { id?: string; type?: string; version?: number; data?: unknown; timestamp?: string };
|
|
24
25
|
const eventId = ev.id ?? crypto.randomUUID();
|
|
@@ -35,6 +36,20 @@ export const ${varName} = defineSubscriber({
|
|
|
35
36
|
},
|
|
36
37
|
{ ttl: Math.floor(Date.now() / 1000) + 90 * 86400 }, // 90-day retention
|
|
37
38
|
);
|
|
39
|
+
|
|
40
|
+
if (process.env.AUDIT_RELAY_URL) {
|
|
41
|
+
await ctx.fetch.fetch(process.env.AUDIT_RELAY_URL, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { 'Content-Type': 'application/json' },
|
|
44
|
+
body: JSON.stringify({
|
|
45
|
+
eventId,
|
|
46
|
+
eventType: ev.type,
|
|
47
|
+
eventVersion: ev.version,
|
|
48
|
+
payload: ev.data,
|
|
49
|
+
timestamp: ev.timestamp ?? new Date().toISOString(),
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
38
53
|
},
|
|
39
54
|
});
|
|
40
55
|
`;
|
|
@@ -21,6 +21,7 @@ export const ${varName} = defineSubscriber({
|
|
|
21
21
|
id: '${domain}.${id}',
|
|
22
22
|
event: '${event}',
|
|
23
23
|
semverRange: '^1',
|
|
24
|
+
outboundAccess: 'internal',
|
|
24
25
|
handler: async (event, ctx) => {
|
|
25
26
|
const data = (event as { data: { entityId: string; deletedBy?: string } }).data;
|
|
26
27
|
|
|
@@ -16,6 +16,7 @@ export const ${varName} = defineSubscriber({
|
|
|
16
16
|
id: '${domain}.${id}',
|
|
17
17
|
event: '${event}',
|
|
18
18
|
semverRange: '^1',
|
|
19
|
+
outboundAccess: 'internal',
|
|
19
20
|
handler: async (event, ctx) => {
|
|
20
21
|
const { tenantId: _tenantId, ...eventData } = (event as { data: Record<string, unknown> }).data;
|
|
21
22
|
const eventId = (event as { id?: string }).id ?? 'unknown';
|
|
@@ -15,6 +15,7 @@ export const ${subscriberId.replace(/-([a-z])/g, (_, c) => c.toUpperCase())} = d
|
|
|
15
15
|
id: '${domainId}.${subscriberId}',
|
|
16
16
|
event: '${eventId}',
|
|
17
17
|
semverRange: '*',
|
|
18
|
+
outboundAccess: 'internal',
|
|
18
19
|
handler: async (_event, _ctx) => {
|
|
19
20
|
// receive _event.data (typed payload) and use _ctx.store, _ctx.publish, _ctx.audit
|
|
20
21
|
},
|
package/package.json
CHANGED
|
@@ -72,7 +72,7 @@ describe('buildRegistry', () => {
|
|
|
72
72
|
{ _kind: 'domain', _exportName: 'default', id: 'billing', name: 'Billing', tenancy: 'required' },
|
|
73
73
|
])
|
|
74
74
|
.mockResolvedValueOnce([
|
|
75
|
-
{ _kind: 'api', _exportName: 'getInvoice', id: 'get-invoice', path: '/invoices/:id', auth: { type: 'jwt' } },
|
|
75
|
+
{ _kind: 'api', _exportName: 'getInvoice', id: 'get-invoice', path: '/invoices/:id', method: 'GET', auth: { type: 'jwt' } },
|
|
76
76
|
]);
|
|
77
77
|
|
|
78
78
|
const { registry, warnings } = await buildRegistry(DOMAIN_ROOT);
|
|
@@ -84,7 +84,34 @@ describe('buildRegistry', () => {
|
|
|
84
84
|
expect(registry.apis[0]!.id).toBe('get-invoice');
|
|
85
85
|
expect(registry.apis[0]!.path).toBe('/invoices/:id');
|
|
86
86
|
expect(registry.apis[0]!.authType).toBe('jwt');
|
|
87
|
-
expect(registry.apis[0]!.handlerFile).toBe('api/get-invoice.ts');
|
|
87
|
+
expect(registry.apis[0]!.handlerFile.replaceAll('\\', '/')).toBe('api/get-invoice.ts');
|
|
88
|
+
expect(registry.apis[0]!.outboundAccess).toBe('internal');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('preserves explicit outboundAccess on primitives', async () => {
|
|
92
|
+
mockWalkDomainDir.mockResolvedValue({
|
|
93
|
+
domain: '/fake/domains/billing/domain.config.ts',
|
|
94
|
+
apis: ['/fake/domains/billing/api/sync-invoice.ts'],
|
|
95
|
+
webhooks: [],
|
|
96
|
+
subscribers: [],
|
|
97
|
+
actions: [],
|
|
98
|
+
schedules: [],
|
|
99
|
+
jobs: [],
|
|
100
|
+
integrations: [],
|
|
101
|
+
publishes: undefined,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
mockLoadModuleExports
|
|
105
|
+
.mockResolvedValueOnce([
|
|
106
|
+
{ _kind: 'domain', _exportName: 'default', id: 'billing', name: 'Billing', tenancy: 'required' },
|
|
107
|
+
])
|
|
108
|
+
.mockResolvedValueOnce([
|
|
109
|
+
{ _kind: 'api', _exportName: 'syncInvoice', id: 'sync-invoice', path: '/invoices/sync', method: 'POST', auth: { type: 'jwt' }, outboundAccess: 'internet' },
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
const { registry } = await buildRegistry(DOMAIN_ROOT);
|
|
113
|
+
|
|
114
|
+
expect(registry.apis[0]!.outboundAccess).toBe('internet');
|
|
88
115
|
});
|
|
89
116
|
|
|
90
117
|
it('collects warnings when a file fails to load', async () => {
|
|
@@ -517,6 +517,11 @@ describe('scaffold smoke test (issue #3831)', () => {
|
|
|
517
517
|
}
|
|
518
518
|
});
|
|
519
519
|
|
|
520
|
+
it('api-skeleton template emits explicit outboundAccess default', async () => {
|
|
521
|
+
const out = apiSkeletonTemplateForTest('payments', 'charge-card', 'required');
|
|
522
|
+
expect(out).toContain("outboundAccess: 'internal'");
|
|
523
|
+
});
|
|
524
|
+
|
|
520
525
|
// ── npm install / build / test (gated on npm availability) ───────────
|
|
521
526
|
// These three steps are the heart of the smoke test. On environments
|
|
522
527
|
// without npm (e.g. some sandboxes) they're recorded as soft skips so
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { apiSkeletonTemplate } from '../templates/api-skeleton.js';
|
|
3
|
+
import { subscriberSkeletonTemplate } from '../templates/subscriber-skeleton.js';
|
|
4
|
+
import { auditRelayTemplate } from '../templates/patterns/subscriber/audit-relay.js';
|
|
5
|
+
|
|
6
|
+
describe('domain-cli templates emit outboundAccess', () => {
|
|
7
|
+
it('adds explicit internal outbound access to API skeletons', () => {
|
|
8
|
+
const output = apiSkeletonTemplate('payments', 'charge-card', 'required');
|
|
9
|
+
|
|
10
|
+
expect(output).toContain("outboundAccess: 'internal'");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('adds explicit internal outbound access to subscriber skeletons', () => {
|
|
14
|
+
const output = subscriberSkeletonTemplate('payments', 'on-charge-created', 'payments.charge.created');
|
|
15
|
+
|
|
16
|
+
expect(output).toContain("outboundAccess: 'internal'");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('documents internet egress in the audit relay pattern', () => {
|
|
20
|
+
const output = auditRelayTemplate('payments', 'relay-audit', 'payments.charge.created');
|
|
21
|
+
|
|
22
|
+
expect(output).toContain("outboundAccess: 'internet'");
|
|
23
|
+
expect(output).toContain('AUDIT_RELAY_URL');
|
|
24
|
+
expect(output).toContain('ctx.fetch.fetch');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -71,6 +71,10 @@ export async function buildRegistry(domainRoot: string): Promise<BuildResult> {
|
|
|
71
71
|
return raw['deployment'] as SerialDeploymentConfig | undefined;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
function outboundAccess(raw: RawPrimitiveExport): 'internal' | 'internet' {
|
|
75
|
+
return raw['outboundAccess'] === 'internet' ? 'internet' : 'internal';
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
const domainExports = await load(paths.domain);
|
|
75
79
|
const domainRaw = domainExports.find(e => e['_kind'] === 'domain');
|
|
76
80
|
if (!domainRaw) {
|
|
@@ -127,6 +131,7 @@ export async function buildRegistry(domainRoot: string): Promise<BuildResult> {
|
|
|
127
131
|
authType: ((e['auth'] as { type?: string } | undefined)?.type as 'jwt' | 'api-key' | 'none' | undefined) ?? 'jwt',
|
|
128
132
|
description: typeof e['description'] === 'string' ? e['description'] : undefined,
|
|
129
133
|
deployment: deployment(e),
|
|
134
|
+
outboundAccess: outboundAccess(e),
|
|
130
135
|
requestSchema: latestVersion?.requestSchema,
|
|
131
136
|
responseSchema: latestVersion?.responseSchema,
|
|
132
137
|
versions: versionSnapshots.length > 0 ? versionSnapshots : undefined,
|
|
@@ -147,6 +152,7 @@ export async function buildRegistry(domainRoot: string): Promise<BuildResult> {
|
|
|
147
152
|
hmacAlgorithm: (e['verification'] as { type?: string } | undefined)?.type,
|
|
148
153
|
hmacSecretRef: (e['verification'] as { secretRef?: string } | undefined)?.secretRef,
|
|
149
154
|
deployment: deployment(e),
|
|
155
|
+
outboundAccess: outboundAccess(e),
|
|
150
156
|
}))
|
|
151
157
|
);
|
|
152
158
|
|
|
@@ -161,6 +167,7 @@ export async function buildRegistry(domainRoot: string): Promise<BuildResult> {
|
|
|
161
167
|
semverRange: String(e['semverRange']),
|
|
162
168
|
concurrency: e['concurrency'] as number | undefined,
|
|
163
169
|
deployment: deployment(e),
|
|
170
|
+
outboundAccess: outboundAccess(e),
|
|
164
171
|
}))
|
|
165
172
|
);
|
|
166
173
|
|
|
@@ -174,6 +181,7 @@ export async function buildRegistry(domainRoot: string): Promise<BuildResult> {
|
|
|
174
181
|
cron: String(e['cron']),
|
|
175
182
|
enabled: Boolean(e['enabled'] ?? true),
|
|
176
183
|
deployment: deployment(e),
|
|
184
|
+
outboundAccess: outboundAccess(e),
|
|
177
185
|
}))
|
|
178
186
|
);
|
|
179
187
|
|
|
@@ -187,6 +195,7 @@ export async function buildRegistry(domainRoot: string): Promise<BuildResult> {
|
|
|
187
195
|
maxRetries: Number(e['maxRetries'] ?? 3),
|
|
188
196
|
visibilityTimeoutSeconds: Number(e['visibilityTimeoutSeconds'] ?? 30),
|
|
189
197
|
deployment: deployment(e),
|
|
198
|
+
outboundAccess: outboundAccess(e),
|
|
190
199
|
}))
|
|
191
200
|
);
|
|
192
201
|
|
|
@@ -201,6 +210,7 @@ export async function buildRegistry(domainRoot: string): Promise<BuildResult> {
|
|
|
201
210
|
idempotent: Boolean(e['idempotent'] ?? false),
|
|
202
211
|
description: typeof e['description'] === 'string' ? e['description'] : undefined,
|
|
203
212
|
deployment: deployment(e),
|
|
213
|
+
outboundAccess: outboundAccess(e),
|
|
204
214
|
inputSchema: isJsonSchema(e['input']) ? (e['input'] as SchemaSnapshot) : undefined,
|
|
205
215
|
outputSchema: isJsonSchema(e['output']) ? (e['output'] as SchemaSnapshot) : undefined,
|
|
206
216
|
}))
|
|
@@ -46,6 +46,7 @@ export const ${varName} = defineApi({
|
|
|
46
46
|
id: '${id}',
|
|
47
47
|
path: '${tenantPath}/${domain}/${id}',
|
|
48
48
|
tenancy: '${tenancy}',
|
|
49
|
+
outboundAccess: 'internal',
|
|
49
50
|
versions: {
|
|
50
51
|
v1: {
|
|
51
52
|
status: 'stable',
|
|
@@ -97,6 +98,7 @@ export const ${varName}List = defineApi({
|
|
|
97
98
|
id: '${id}-list',
|
|
98
99
|
path: '${tenantPath}/${domain}/${id}-list',
|
|
99
100
|
tenancy: '${tenancy}',
|
|
101
|
+
outboundAccess: 'internal',
|
|
100
102
|
versions: {
|
|
101
103
|
v1: {
|
|
102
104
|
status: 'stable',
|
|
@@ -47,6 +47,7 @@ export const ${varName} = defineApi({
|
|
|
47
47
|
id: '${id}',
|
|
48
48
|
path: '/system/${domain}/${id}',
|
|
49
49
|
tenancy: '${tenancy}',
|
|
50
|
+
outboundAccess: 'internal',
|
|
50
51
|
versions: {
|
|
51
52
|
v1: {
|
|
52
53
|
status: 'stable',
|
|
@@ -84,6 +85,7 @@ export const ${varName}Health = defineApi({
|
|
|
84
85
|
id: '${id}-health',
|
|
85
86
|
path: '/system/${domain}/${id}-health',
|
|
86
87
|
tenancy: '${tenancy}',
|
|
88
|
+
outboundAccess: 'internal',
|
|
87
89
|
versions: {
|
|
88
90
|
v1: {
|
|
89
91
|
status: 'stable',
|
|
@@ -22,6 +22,7 @@ export const ${varName} = defineSubscriber({
|
|
|
22
22
|
id: '${domain}.${id}',
|
|
23
23
|
event: '${event}',
|
|
24
24
|
semverRange: '^1',
|
|
25
|
+
outboundAccess: 'internet',
|
|
25
26
|
handler: async (event, ctx) => {
|
|
26
27
|
const ev = event as { id?: string; type?: string; version?: number; data?: unknown; timestamp?: string };
|
|
27
28
|
const eventId = ev.id ?? crypto.randomUUID();
|
|
@@ -38,6 +39,20 @@ export const ${varName} = defineSubscriber({
|
|
|
38
39
|
},
|
|
39
40
|
{ ttl: Math.floor(Date.now() / 1000) + 90 * 86400 }, // 90-day retention
|
|
40
41
|
);
|
|
42
|
+
|
|
43
|
+
if (process.env.AUDIT_RELAY_URL) {
|
|
44
|
+
await ctx.fetch.fetch(process.env.AUDIT_RELAY_URL, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
body: JSON.stringify({
|
|
48
|
+
eventId,
|
|
49
|
+
eventType: ev.type,
|
|
50
|
+
eventVersion: ev.version,
|
|
51
|
+
payload: ev.data,
|
|
52
|
+
timestamp: ev.timestamp ?? new Date().toISOString(),
|
|
53
|
+
}),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
41
56
|
},
|
|
42
57
|
});
|
|
43
58
|
`;
|
|
@@ -24,6 +24,7 @@ export const ${varName} = defineSubscriber({
|
|
|
24
24
|
id: '${domain}.${id}',
|
|
25
25
|
event: '${event}',
|
|
26
26
|
semverRange: '^1',
|
|
27
|
+
outboundAccess: 'internal',
|
|
27
28
|
handler: async (event, ctx) => {
|
|
28
29
|
const data = (event as { data: { entityId: string; deletedBy?: string } }).data;
|
|
29
30
|
|
|
@@ -19,6 +19,7 @@ export const ${varName} = defineSubscriber({
|
|
|
19
19
|
id: '${domain}.${id}',
|
|
20
20
|
event: '${event}',
|
|
21
21
|
semverRange: '^1',
|
|
22
|
+
outboundAccess: 'internal',
|
|
22
23
|
handler: async (event, ctx) => {
|
|
23
24
|
const { tenantId: _tenantId, ...eventData } = (event as { data: Record<string, unknown> }).data;
|
|
24
25
|
const eventId = (event as { id?: string }).id ?? 'unknown';
|
|
@@ -20,6 +20,7 @@ export const ${subscriberId.replace(/-([a-z])/g, (_, c) => c.toUpperCase())} = d
|
|
|
20
20
|
id: '${domainId}.${subscriberId}',
|
|
21
21
|
event: '${eventId}',
|
|
22
22
|
semverRange: '*',
|
|
23
|
+
outboundAccess: 'internal',
|
|
23
24
|
handler: async (_event, _ctx) => {
|
|
24
25
|
// receive _event.data (typed payload) and use _ctx.store, _ctx.publish, _ctx.audit
|
|
25
26
|
},
|