@mettlecast/domain-cli 0.2.51 → 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.
Files changed (30) hide show
  1. package/dist/builder/build-registry.js +9 -0
  2. package/dist/templates/api-skeleton.js +1 -0
  3. package/dist/templates/patterns/api/create-with-event.js +1 -0
  4. package/dist/templates/patterns/api/idempotent-mutation.js +1 -0
  5. package/dist/templates/patterns/api/paginated-list.js +1 -0
  6. package/dist/templates/patterns/api/simple-crud.js +2 -0
  7. package/dist/templates/patterns/api/streaming-list.js +1 -0
  8. package/dist/templates/patterns/api/system-admin.js +2 -0
  9. package/dist/templates/patterns/api/webhook-receiver-style.js +1 -0
  10. package/dist/templates/patterns/subscriber/audit-relay.js +15 -0
  11. package/dist/templates/patterns/subscriber/cascade-deletion.js +1 -0
  12. package/dist/templates/patterns/subscriber/single-step-projection.js +1 -0
  13. package/dist/templates/subscriber-skeleton.js +1 -0
  14. package/package.json +1 -1
  15. package/src/__tests__/build-registry.test.ts +29 -2
  16. package/src/__tests__/smoke/scaffold.test.ts +5 -0
  17. package/src/__tests__/template-outbound-access.test.ts +26 -0
  18. package/src/builder/build-registry.ts +10 -0
  19. package/src/templates/api-skeleton.ts +1 -0
  20. package/src/templates/patterns/api/create-with-event.ts +1 -0
  21. package/src/templates/patterns/api/idempotent-mutation.ts +1 -0
  22. package/src/templates/patterns/api/paginated-list.ts +1 -0
  23. package/src/templates/patterns/api/simple-crud.ts +2 -0
  24. package/src/templates/patterns/api/streaming-list.ts +1 -0
  25. package/src/templates/patterns/api/system-admin.ts +2 -0
  26. package/src/templates/patterns/api/webhook-receiver-style.ts +1 -0
  27. package/src/templates/patterns/subscriber/audit-relay.ts +15 -0
  28. package/src/templates/patterns/subscriber/cascade-deletion.ts +1 -0
  29. package/src/templates/patterns/subscriber/single-step-projection.ts +1 -0
  30. 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
  })));
@@ -42,6 +42,7 @@ export const ${camelCase(apiId)} = defineApi({
42
42
  path: '${tenantPath}/${domainId}/${apiId}',
43
43
  method: 'POST',
44
44
  tenancy: '${tenancy}',
45
+ outboundAccess: 'internal',
45
46
  versions: {
46
47
  v1: {
47
48
  status: 'stable',
@@ -37,6 +37,7 @@ export const ${varName} = defineApi({
37
37
  id: '${id}',
38
38
  path: '${tenantPath}/${domain}/${id}',
39
39
  tenancy: '${tenancy}',
40
+ outboundAccess: 'internal',
40
41
  versions: {
41
42
  v1: {
42
43
  status: 'stable',
@@ -42,6 +42,7 @@ export const ${varName} = defineApi({
42
42
  id: '${id}',
43
43
  path: '${tenantPath}/${domain}/${id}',
44
44
  tenancy: '${tenancy}',
45
+ outboundAccess: 'internal',
45
46
  versions: {
46
47
  v1: {
47
48
  status: 'stable',
@@ -41,6 +41,7 @@ export const ${varName} = defineApi({
41
41
  id: '${id}',
42
42
  path: '${tenantPath}/${domain}/${id}',
43
43
  tenancy: '${tenancy}',
44
+ outboundAccess: 'internal',
44
45
  versions: {
45
46
  v1: {
46
47
  status: 'stable',
@@ -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 ${apiId.replace(/-/g, '_')} = defineApi({
44
44
  path: '/v1/${domain}/${apiId}',
45
45
  method: 'GET',
46
46
  tenancy: 'required',
47
+ outboundAccess: 'internal',
47
48
  versions: {
48
49
  v1: {
49
50
  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',
@@ -53,6 +53,7 @@ export const ${varName} = defineApi({
53
53
  id: '${id}',
54
54
  path: '/webhooks/${domain}/${id}',
55
55
  tenancy: '${tenancy}',
56
+ outboundAccess: 'internal',
56
57
  versions: {
57
58
  v1: {
58
59
  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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mettlecast/domain-cli",
3
- "version": "0.2.51",
3
+ "version": "0.2.53",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -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
  }))
@@ -44,6 +44,7 @@ export const ${camelCase(apiId)} = defineApi({
44
44
  path: '${tenantPath}/${domainId}/${apiId}',
45
45
  method: 'POST',
46
46
  tenancy: '${tenancy}',
47
+ outboundAccess: 'internal',
47
48
  versions: {
48
49
  v1: {
49
50
  status: 'stable',
@@ -40,6 +40,7 @@ export const ${varName} = defineApi({
40
40
  id: '${id}',
41
41
  path: '${tenantPath}/${domain}/${id}',
42
42
  tenancy: '${tenancy}',
43
+ outboundAccess: 'internal',
43
44
  versions: {
44
45
  v1: {
45
46
  status: 'stable',
@@ -45,6 +45,7 @@ export const ${varName} = defineApi({
45
45
  id: '${id}',
46
46
  path: '${tenantPath}/${domain}/${id}',
47
47
  tenancy: '${tenancy}',
48
+ outboundAccess: 'internal',
48
49
  versions: {
49
50
  v1: {
50
51
  status: 'stable',
@@ -44,6 +44,7 @@ export const ${varName} = defineApi({
44
44
  id: '${id}',
45
45
  path: '${tenantPath}/${domain}/${id}',
46
46
  tenancy: '${tenancy}',
47
+ outboundAccess: 'internal',
47
48
  versions: {
48
49
  v1: {
49
50
  status: 'stable',
@@ -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',
@@ -44,6 +44,7 @@ export const ${apiId.replace(/-/g, '_')} = defineApi({
44
44
  path: '/v1/${domain}/${apiId}',
45
45
  method: 'GET',
46
46
  tenancy: 'required',
47
+ outboundAccess: 'internal',
47
48
  versions: {
48
49
  v1: {
49
50
  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',
@@ -56,6 +56,7 @@ export const ${varName} = defineApi({
56
56
  id: '${id}',
57
57
  path: '/webhooks/${domain}/${id}',
58
58
  tenancy: '${tenancy}',
59
+ outboundAccess: 'internal',
59
60
  versions: {
60
61
  v1: {
61
62
  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
  },