@open-mercato/cli 0.4.7-main-1768da2e43 → 0.4.7

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 (51) hide show
  1. package/build.mjs +8 -1
  2. package/dist/agentic/claude-code/CLAUDE.md.template +1 -0
  3. package/dist/agentic/claude-code/hooks/entity-migration-check.ts +121 -0
  4. package/dist/agentic/claude-code/mcp.json.example +13 -0
  5. package/dist/agentic/claude-code/settings.json +16 -0
  6. package/dist/agentic/codex/enforcement-rules.md +20 -0
  7. package/dist/agentic/codex/mcp.json.example +12 -0
  8. package/dist/agentic/cursor/hooks/entity-migration-check.mjs +69 -0
  9. package/dist/agentic/cursor/hooks.json +10 -0
  10. package/dist/agentic/cursor/mcp.json.example +13 -0
  11. package/dist/agentic/cursor/rules/entity-guard.mdc +29 -0
  12. package/dist/agentic/cursor/rules/generated-guard.mdc +12 -0
  13. package/dist/agentic/cursor/rules/open-mercato.mdc +34 -0
  14. package/dist/agentic/shared/AGENTS.md.template +180 -0
  15. package/dist/agentic/shared/ai/lessons.md +4 -0
  16. package/dist/agentic/shared/ai/skills/backend-ui-design/SKILL.md +197 -0
  17. package/dist/agentic/shared/ai/skills/backend-ui-design/references/ui-components.md +233 -0
  18. package/dist/agentic/shared/ai/skills/code-review/SKILL.md +144 -0
  19. package/dist/agentic/shared/ai/skills/code-review/references/review-checklist.md +77 -0
  20. package/dist/agentic/shared/ai/skills/data-model-design/SKILL.md +512 -0
  21. package/dist/agentic/shared/ai/skills/data-model-design/references/mikro-orm-cheatsheet.md +146 -0
  22. package/dist/agentic/shared/ai/skills/eject-and-customize/SKILL.md +318 -0
  23. package/dist/agentic/shared/ai/skills/integration-builder/SKILL.md +722 -0
  24. package/dist/agentic/shared/ai/skills/integration-builder/references/adapter-contracts.md +762 -0
  25. package/dist/agentic/shared/ai/skills/module-scaffold/SKILL.md +614 -0
  26. package/dist/agentic/shared/ai/skills/module-scaffold/references/naming-conventions.md +61 -0
  27. package/dist/agentic/shared/ai/skills/spec-writing/SKILL.md +76 -0
  28. package/dist/agentic/shared/ai/skills/spec-writing/references/spec-checklist.md +50 -0
  29. package/dist/agentic/shared/ai/skills/spec-writing/references/spec-template.md +86 -0
  30. package/dist/agentic/shared/ai/skills/system-extension/SKILL.md +858 -0
  31. package/dist/agentic/shared/ai/skills/system-extension/references/extension-contracts.md +271 -0
  32. package/dist/agentic/shared/ai/skills/troubleshooter/SKILL.md +421 -0
  33. package/dist/agentic/shared/ai/skills/troubleshooter/references/diagnostic-commands.md +101 -0
  34. package/dist/agentic/shared/ai/specs/README.md +26 -0
  35. package/dist/agentic/shared/ai/specs/SPEC-000-template.md +35 -0
  36. package/dist/lib/agentic-init.js +54 -0
  37. package/dist/lib/agentic-init.js.map +7 -0
  38. package/dist/lib/agentic-setup.js +209 -0
  39. package/dist/lib/agentic-setup.js.map +7 -0
  40. package/dist/lib/generators/module-registry.js +3 -3
  41. package/dist/lib/generators/module-registry.js.map +2 -2
  42. package/dist/lib/testing/integration.js +8 -2
  43. package/dist/lib/testing/integration.js.map +2 -2
  44. package/dist/mercato.js +5 -0
  45. package/dist/mercato.js.map +2 -2
  46. package/package.json +7 -4
  47. package/src/lib/agentic-init.ts +69 -0
  48. package/src/lib/agentic-setup.ts +277 -0
  49. package/src/lib/generators/module-registry.ts +3 -3
  50. package/src/lib/testing/integration.ts +8 -2
  51. package/src/mercato.ts +7 -0
@@ -0,0 +1,762 @@
1
+ # Adapter Contracts Reference
2
+
3
+ Full TypeScript type definitions for each integration hub adapter contract. Load this file during Pre-Flight to understand the interface your integration must implement.
4
+
5
+ ---
6
+
7
+ ## 1. IntegrationDefinition & Registry (ALL categories)
8
+
9
+ **Source**: `packages/shared/src/modules/integrations/types.ts`
10
+
11
+ Every integration MUST export an `IntegrationDefinition`. Bundle integrations also export an `IntegrationBundle`.
12
+
13
+ ```typescript
14
+ export type IntegrationCategory =
15
+ | 'payment'
16
+ | 'shipping'
17
+ | 'data_sync'
18
+ | 'communication'
19
+ | 'webhook'
20
+ | 'storage'
21
+ | 'other'
22
+
23
+ export type IntegrationHubId =
24
+ | 'payment_gateways'
25
+ | 'shipping_carriers'
26
+ | 'data_sync'
27
+ | 'communication_channels'
28
+ | 'webhook_endpoints'
29
+ | 'storage_hubs'
30
+ | string
31
+
32
+ export type CredentialFieldType =
33
+ | 'text'
34
+ | 'secret'
35
+ | 'select'
36
+ | 'boolean'
37
+ | 'url'
38
+ | 'oauth'
39
+ | 'ssh_keypair'
40
+
41
+ export interface CredentialFieldOption {
42
+ value: string
43
+ label: string
44
+ }
45
+
46
+ export interface CredentialFieldVisibleWhen {
47
+ field: string
48
+ equals: string | number | boolean
49
+ }
50
+
51
+ export interface IntegrationCredentialWebhookHelp {
52
+ kind: 'webhook_setup'
53
+ title: string
54
+ summary: string
55
+ endpointPath: string
56
+ dashboardPathLabel: string
57
+ steps: string[]
58
+ events?: string[]
59
+ localDevelopment?: {
60
+ tunnelCommand: string
61
+ publicUrlExample: string
62
+ note?: string
63
+ }
64
+ }
65
+
66
+ export interface IntegrationCredentialFieldBase {
67
+ key: string
68
+ label: string
69
+ required?: boolean
70
+ placeholder?: string
71
+ helpText?: string
72
+ helpDetails?: IntegrationCredentialWebhookHelp
73
+ visibleWhen?: CredentialFieldVisibleWhen
74
+ }
75
+
76
+ export interface IntegrationCredentialFieldText extends IntegrationCredentialFieldBase {
77
+ type: Extract<CredentialFieldType, 'text' | 'secret' | 'url'>
78
+ }
79
+
80
+ export interface IntegrationCredentialFieldBoolean extends IntegrationCredentialFieldBase {
81
+ type: Extract<CredentialFieldType, 'boolean'>
82
+ }
83
+
84
+ export interface IntegrationCredentialFieldSelect extends IntegrationCredentialFieldBase {
85
+ type: Extract<CredentialFieldType, 'select'>
86
+ options: CredentialFieldOption[]
87
+ }
88
+
89
+ export interface IntegrationCredentialFieldOauth extends IntegrationCredentialFieldBase {
90
+ type: Extract<CredentialFieldType, 'oauth'>
91
+ authUrl?: string
92
+ tokenUrl?: string
93
+ scopes?: string[]
94
+ clientIdField?: string
95
+ clientSecretField?: string
96
+ }
97
+
98
+ export interface IntegrationCredentialFieldSshKeypair extends IntegrationCredentialFieldBase {
99
+ type: Extract<CredentialFieldType, 'ssh_keypair'>
100
+ algorithm?: 'ed25519' | 'rsa'
101
+ rsaBits?: 2048 | 3072 | 4096
102
+ }
103
+
104
+ export type IntegrationCredentialField =
105
+ | IntegrationCredentialFieldText
106
+ | IntegrationCredentialFieldBoolean
107
+ | IntegrationCredentialFieldSelect
108
+ | IntegrationCredentialFieldOauth
109
+ | IntegrationCredentialFieldSshKeypair
110
+
111
+ export interface IntegrationCredentialsSchema {
112
+ fields: IntegrationCredentialField[]
113
+ }
114
+
115
+ export interface IntegrationHealthCheckConfig {
116
+ service: string
117
+ }
118
+
119
+ export interface ApiVersionDefinition {
120
+ id: string
121
+ label: string
122
+ status: 'stable' | 'deprecated' | 'experimental'
123
+ default?: boolean
124
+ changelog?: string
125
+ deprecatedAt?: string
126
+ sunsetAt?: string
127
+ migrationGuide?: string
128
+ }
129
+
130
+ export interface IntegrationBundle {
131
+ id: string
132
+ title: string
133
+ description: string
134
+ icon?: string
135
+ package?: string
136
+ version?: string
137
+ author?: string
138
+ credentials: IntegrationCredentialsSchema
139
+ healthCheck?: IntegrationHealthCheckConfig
140
+ }
141
+
142
+ export interface IntegrationDefinition {
143
+ id: string
144
+ title: string
145
+ icon?: string
146
+ buildExternalUrl?: (externalId: string) => string
147
+ bundleId?: string
148
+ apiVersions?: ApiVersionDefinition[]
149
+ description?: string
150
+ category?: IntegrationCategory | string
151
+ hub?: IntegrationHubId
152
+ providerKey?: string
153
+ docsUrl?: string
154
+ package?: string
155
+ version?: string
156
+ author?: string
157
+ company?: string
158
+ license?: string
159
+ tags?: string[]
160
+ credentials?: IntegrationCredentialsSchema
161
+ healthCheck?: IntegrationHealthCheckConfig
162
+ }
163
+
164
+ // Registry functions
165
+ export function registerIntegration(definition: IntegrationDefinition): void
166
+ export function registerIntegrations(definitions: IntegrationDefinition[]): void
167
+ export function registerBundle(bundle: IntegrationBundle): void
168
+ export function registerBundles(bundles: IntegrationBundle[]): void
169
+ export function clearRegisteredIntegrations(): void
170
+ export function getIntegration(integrationId: string): IntegrationDefinition | undefined
171
+ export function getAllIntegrations(): IntegrationDefinition[]
172
+ export function getBundle(bundleId: string): IntegrationBundle | undefined
173
+ export function getAllBundles(): IntegrationBundle[]
174
+ export function getBundleIntegrations(bundleId: string): IntegrationDefinition[]
175
+ export function resolveIntegrationCredentialsSchema(integrationId: string): IntegrationCredentialsSchema | undefined
176
+ export function getIntegrationTitle(integrationId: string): string
177
+ ```
178
+
179
+ ---
180
+
181
+ ## 2. GatewayAdapter (Payment Gateways Hub)
182
+
183
+ **Source**: `packages/shared/src/modules/payment_gateways/types.ts`
184
+ **Hub**: `payment_gateways` | **Category**: `payment` | **Package prefix**: `gateway-`
185
+
186
+ ```typescript
187
+ export type UnifiedPaymentStatus =
188
+ | 'pending'
189
+ | 'authorized'
190
+ | 'captured'
191
+ | 'partially_captured'
192
+ | 'refunded'
193
+ | 'partially_refunded'
194
+ | 'cancelled'
195
+ | 'failed'
196
+ | 'expired'
197
+ | 'unknown'
198
+
199
+ export interface GatewayAdapter {
200
+ readonly providerKey: string
201
+ createSession(input: CreateSessionInput): Promise<CreateSessionResult>
202
+ capture(input: CaptureInput): Promise<CaptureResult>
203
+ refund(input: RefundInput): Promise<RefundResult>
204
+ cancel(input: CancelInput): Promise<CancelResult>
205
+ getStatus(input: GetStatusInput): Promise<GatewayPaymentStatus>
206
+ verifyWebhook(input: VerifyWebhookInput): Promise<WebhookEvent>
207
+ mapStatus(providerStatus: string, eventType?: string): UnifiedPaymentStatus
208
+ }
209
+
210
+ export interface CreateSessionInput {
211
+ orderId?: string
212
+ paymentId: string
213
+ tenantId: string
214
+ organizationId: string
215
+ amount: number
216
+ currencyCode: string
217
+ captureMethod?: 'automatic' | 'manual'
218
+ paymentTypes?: string[]
219
+ description?: string
220
+ successUrl?: string
221
+ cancelUrl?: string
222
+ metadata?: Record<string, unknown>
223
+ credentials: Record<string, unknown>
224
+ lineItems?: SessionLineItem[]
225
+ }
226
+
227
+ export interface SessionLineItem {
228
+ name: string
229
+ quantity: number
230
+ unitAmount: number
231
+ currencyCode: string
232
+ }
233
+
234
+ export interface CreateSessionResult {
235
+ sessionId: string
236
+ clientSecret?: string
237
+ redirectUrl?: string
238
+ status: UnifiedPaymentStatus
239
+ providerData?: Record<string, unknown>
240
+ }
241
+
242
+ export interface CaptureInput {
243
+ sessionId: string
244
+ amount?: number
245
+ credentials: Record<string, unknown>
246
+ metadata?: Record<string, unknown>
247
+ }
248
+
249
+ export interface CaptureResult {
250
+ status: UnifiedPaymentStatus
251
+ capturedAmount: number
252
+ providerData?: Record<string, unknown>
253
+ }
254
+
255
+ export interface RefundInput {
256
+ sessionId: string
257
+ amount?: number
258
+ reason?: string
259
+ credentials: Record<string, unknown>
260
+ metadata?: Record<string, unknown>
261
+ }
262
+
263
+ export interface RefundResult {
264
+ refundId: string
265
+ status: UnifiedPaymentStatus
266
+ refundedAmount: number
267
+ providerData?: Record<string, unknown>
268
+ }
269
+
270
+ export interface CancelInput {
271
+ sessionId: string
272
+ reason?: string
273
+ credentials: Record<string, unknown>
274
+ }
275
+
276
+ export interface CancelResult {
277
+ status: UnifiedPaymentStatus
278
+ providerData?: Record<string, unknown>
279
+ }
280
+
281
+ export interface GetStatusInput {
282
+ sessionId: string
283
+ credentials: Record<string, unknown>
284
+ }
285
+
286
+ export interface GatewayPaymentStatus {
287
+ status: UnifiedPaymentStatus
288
+ amount: number
289
+ amountReceived: number
290
+ currencyCode: string
291
+ providerData?: Record<string, unknown>
292
+ }
293
+
294
+ export interface VerifyWebhookInput {
295
+ rawBody: string | Buffer
296
+ headers: Record<string, string | string[] | undefined>
297
+ credentials: Record<string, unknown>
298
+ }
299
+
300
+ export interface WebhookEvent {
301
+ eventType: string
302
+ eventId: string
303
+ data: Record<string, unknown>
304
+ idempotencyKey: string
305
+ timestamp: Date
306
+ }
307
+
308
+ export interface RegisterAdapterOptions {
309
+ version?: string
310
+ }
311
+
312
+ // Registry functions
313
+ export function registerGatewayAdapter(adapter: GatewayAdapter, options?: RegisterAdapterOptions): () => void
314
+ export function getGatewayAdapter(providerKey: string, version?: string): GatewayAdapter | undefined
315
+ export function listGatewayAdapters(): GatewayAdapter[]
316
+ export function clearGatewayAdapters(): void
317
+ export function registerWebhookHandler(
318
+ providerKey: string,
319
+ handler: (input: VerifyWebhookInput) => Promise<WebhookEvent>,
320
+ options?: { queue?: string },
321
+ ): () => void
322
+ export function getWebhookHandler(providerKey: string): WebhookHandlerRegistration | undefined
323
+ export function clearWebhookHandlers(): void
324
+ ```
325
+
326
+ ---
327
+
328
+ ## 3. ShippingAdapter (Shipping Carriers Hub)
329
+
330
+ **Source**: `packages/core/src/modules/shipping_carriers/lib/adapter.ts`
331
+ **Hub**: `shipping_carriers` | **Category**: `shipping` | **Package prefix**: `carrier-`
332
+
333
+ ```typescript
334
+ export type UnifiedShipmentStatus =
335
+ | 'label_created'
336
+ | 'picked_up'
337
+ | 'in_transit'
338
+ | 'out_for_delivery'
339
+ | 'delivered'
340
+ | 'failed_delivery'
341
+ | 'returned'
342
+ | 'cancelled'
343
+ | 'unknown'
344
+
345
+ export type Address = {
346
+ countryCode: string
347
+ postalCode: string
348
+ city: string
349
+ line1: string
350
+ line2?: string
351
+ }
352
+
353
+ export type PackageInfo = {
354
+ weightKg: number
355
+ lengthCm: number
356
+ widthCm: number
357
+ heightCm: number
358
+ }
359
+
360
+ export type ShippingRate = {
361
+ serviceCode: string
362
+ serviceName: string
363
+ amount: number
364
+ currencyCode: string
365
+ estimatedDays?: number
366
+ guaranteedDelivery?: boolean
367
+ }
368
+
369
+ export type CreateShipmentInput = {
370
+ orderId: string
371
+ origin: Address
372
+ destination: Address
373
+ packages: PackageInfo[]
374
+ serviceCode: string
375
+ credentials: Record<string, unknown>
376
+ labelFormat?: 'pdf' | 'zpl' | 'png'
377
+ }
378
+
379
+ export type CreateShipmentResult = {
380
+ shipmentId: string
381
+ trackingNumber: string
382
+ labelUrl?: string
383
+ labelData?: string
384
+ estimatedDelivery?: Date
385
+ }
386
+
387
+ export type TrackingResult = {
388
+ trackingNumber: string
389
+ status: UnifiedShipmentStatus
390
+ events: Array<{
391
+ status: UnifiedShipmentStatus
392
+ occurredAt: string
393
+ location?: string
394
+ }>
395
+ }
396
+
397
+ export type ShippingWebhookEvent = {
398
+ eventType: string
399
+ eventId: string
400
+ idempotencyKey: string
401
+ data: Record<string, unknown>
402
+ timestamp: Date
403
+ }
404
+
405
+ export interface ShippingAdapter {
406
+ readonly providerKey: string
407
+
408
+ calculateRates(input: {
409
+ origin: Address
410
+ destination: Address
411
+ packages: PackageInfo[]
412
+ credentials: Record<string, unknown>
413
+ }): Promise<ShippingRate[]>
414
+
415
+ createShipment(input: CreateShipmentInput): Promise<CreateShipmentResult>
416
+
417
+ getTracking(input: {
418
+ shipmentId?: string
419
+ trackingNumber?: string
420
+ credentials: Record<string, unknown>
421
+ }): Promise<TrackingResult>
422
+
423
+ cancelShipment(input: {
424
+ shipmentId: string
425
+ reason?: string
426
+ credentials: Record<string, unknown>
427
+ }): Promise<{ status: UnifiedShipmentStatus }>
428
+
429
+ verifyWebhook(input: {
430
+ rawBody: string | Buffer
431
+ headers: Record<string, string | string[] | undefined>
432
+ credentials: Record<string, unknown>
433
+ }): Promise<ShippingWebhookEvent>
434
+
435
+ mapStatus(carrierStatus: string): UnifiedShipmentStatus
436
+ }
437
+
438
+ // Registry functions
439
+ export function registerShippingAdapter(adapter: ShippingAdapter): () => void
440
+ export function getShippingAdapter(providerKey: string): ShippingAdapter | undefined
441
+ export function listShippingAdapters(): ShippingAdapter[]
442
+ export function clearShippingAdapters(): void
443
+ ```
444
+
445
+ ---
446
+
447
+ ## 4. DataSyncAdapter (Data Sync Hub)
448
+
449
+ **Source**: `packages/core/src/modules/data_sync/lib/adapter.ts`
450
+ **Hub**: `data_sync` | **Category**: `data_sync` | **Package prefix**: `sync-`
451
+
452
+ ```typescript
453
+ export interface TenantScope {
454
+ organizationId: string
455
+ tenantId: string
456
+ }
457
+
458
+ export interface FieldMapping {
459
+ externalField: string
460
+ localField: string
461
+ transform?: string
462
+ required?: boolean
463
+ defaultValue?: unknown
464
+ }
465
+
466
+ export interface DataMapping {
467
+ entityType: string
468
+ fields: FieldMapping[]
469
+ matchStrategy: 'externalId' | 'sku' | 'email' | 'custom'
470
+ matchField?: string
471
+ }
472
+
473
+ export interface StreamImportInput {
474
+ entityType: string
475
+ cursor?: string
476
+ batchSize: number
477
+ credentials: Record<string, unknown>
478
+ mapping: DataMapping
479
+ scope: TenantScope
480
+ }
481
+
482
+ export interface ImportItem {
483
+ externalId: string
484
+ data: Record<string, unknown>
485
+ action: 'create' | 'update' | 'skip'
486
+ hash?: string
487
+ }
488
+
489
+ export interface ImportBatch {
490
+ items: ImportItem[]
491
+ cursor: string
492
+ hasMore: boolean
493
+ totalEstimate?: number
494
+ batchIndex: number
495
+ }
496
+
497
+ export interface StreamExportInput {
498
+ entityType: string
499
+ cursor?: string
500
+ batchSize: number
501
+ credentials: Record<string, unknown>
502
+ mapping: DataMapping
503
+ scope: TenantScope
504
+ filter?: Record<string, unknown>
505
+ }
506
+
507
+ export interface ExportItemResult {
508
+ localId: string
509
+ externalId?: string
510
+ status: 'success' | 'error' | 'skipped'
511
+ error?: string
512
+ }
513
+
514
+ export interface ExportBatch {
515
+ results: ExportItemResult[]
516
+ cursor: string
517
+ hasMore: boolean
518
+ batchIndex: number
519
+ }
520
+
521
+ export interface ValidationResult {
522
+ ok: boolean
523
+ message?: string
524
+ details?: Record<string, unknown>
525
+ }
526
+
527
+ export interface DataSyncAdapter {
528
+ readonly providerKey: string
529
+ readonly direction: 'import' | 'export' | 'bidirectional'
530
+ readonly supportedEntities: string[]
531
+
532
+ streamImport?(input: StreamImportInput): AsyncIterable<ImportBatch>
533
+ streamExport?(input: StreamExportInput): AsyncIterable<ExportBatch>
534
+ getInitialCursor?(input: { entityType: string; scope: TenantScope }): Promise<string | null>
535
+ getMapping(input: { entityType: string; scope: TenantScope }): Promise<DataMapping>
536
+ validateConnection?(input: {
537
+ entityType: string
538
+ credentials: Record<string, unknown>
539
+ mapping: DataMapping
540
+ scope: TenantScope
541
+ }): Promise<ValidationResult>
542
+ }
543
+
544
+ // Registry functions
545
+ export function registerDataSyncAdapter(adapter: DataSyncAdapter): void
546
+ export function getDataSyncAdapter(providerKey: string): DataSyncAdapter | undefined
547
+ export function getAllDataSyncAdapters(): DataSyncAdapter[]
548
+ ```
549
+
550
+ ---
551
+
552
+ ## 5. ChannelAdapter (Communication Channels Hub)
553
+
554
+ **Source**: SPEC-045d (spec-only, not yet implemented in code)
555
+ **Hub**: `communication_channels` | **Category**: `communication` | **Package prefix**: `channel-`
556
+
557
+ ```typescript
558
+ interface ChannelAdapter {
559
+ readonly providerKey: string
560
+ readonly channelType: 'whatsapp' | 'sms' | 'email' | string
561
+
562
+ sendMessage(input: SendMessageInput): Promise<SendMessageResult>
563
+ verifyWebhook(input: VerifyWebhookInput): Promise<InboundMessage>
564
+ getStatus(input: GetMessageStatusInput): Promise<MessageStatus>
565
+ listSenders?(input: ListSendersInput): Promise<SenderInfo[]>
566
+ }
567
+
568
+ interface SendMessageInput {
569
+ channelId: string
570
+ recipientId: string
571
+ content: MessageContent
572
+ conversationId?: string
573
+ credentials: Record<string, unknown>
574
+ scope: TenantScope
575
+ }
576
+
577
+ interface MessageContent {
578
+ type: 'text' | 'template' | 'media' | 'interactive'
579
+ text?: string
580
+ templateId?: string
581
+ templateParams?: Record<string, string>
582
+ mediaUrl?: string
583
+ buttons?: MessageButton[]
584
+ }
585
+
586
+ type MessageStatus = 'sent' | 'delivered' | 'read' | 'failed' | 'unknown'
587
+ ```
588
+
589
+ ---
590
+
591
+ ## 6. NotificationTransportAdapter (Notification Providers Hub)
592
+
593
+ **Source**: SPEC-045d (spec-only, not yet implemented in code)
594
+ **Hub**: `notification_providers` | **Category**: `communication` | **Package prefix**: `channel-`
595
+
596
+ ```typescript
597
+ interface NotificationTransportAdapter {
598
+ readonly providerKey: string
599
+ readonly transportType: 'email' | 'sms' | 'push' | string
600
+
601
+ send(input: SendNotificationInput): Promise<SendNotificationResult>
602
+ getDeliveryStatus?(input: GetDeliveryStatusInput): Promise<DeliveryStatus>
603
+ verifyWebhook?(input: VerifyWebhookInput): Promise<DeliveryReceipt>
604
+ }
605
+
606
+ interface SendNotificationInput {
607
+ recipient: NotificationRecipient
608
+ subject?: string
609
+ body: string
610
+ htmlBody?: string
611
+ templateId?: string
612
+ templateData?: Record<string, unknown>
613
+ credentials: Record<string, unknown>
614
+ metadata?: Record<string, string>
615
+ }
616
+
617
+ interface NotificationRecipient {
618
+ email?: string
619
+ phone?: string
620
+ deviceToken?: string
621
+ userId?: string
622
+ }
623
+
624
+ interface SendNotificationResult {
625
+ externalId: string
626
+ status: 'sent' | 'queued' | 'failed'
627
+ error?: string
628
+ }
629
+ ```
630
+
631
+ ---
632
+
633
+ ## 7. WebhookEndpointAdapter (Webhook Endpoints Hub)
634
+
635
+ **Source**: SPEC-045e (spec-only, delegates to SPEC-057)
636
+ **Hub**: `webhook_endpoints` | **Category**: `webhook` | **Package prefix**: `webhook-`
637
+
638
+ ```typescript
639
+ interface WebhookEndpointAdapter {
640
+ readonly providerKey: string
641
+ readonly subscribedEvents: string[]
642
+
643
+ formatPayload(event: EventPayload): Promise<WebhookPayload>
644
+ verifyWebhook(input: VerifyWebhookInput): Promise<InboundWebhookEvent>
645
+ processInbound(event: InboundWebhookEvent): Promise<void>
646
+ }
647
+
648
+ interface WebhookPayload {
649
+ url: string
650
+ headers: Record<string, string>
651
+ body: Record<string, unknown>
652
+ method: 'POST' | 'PUT' | 'PATCH'
653
+ }
654
+ ```
655
+
656
+ ---
657
+
658
+ ## 8. StorageAdapter (Storage Providers Hub)
659
+
660
+ **Source**: SPEC-045i (spec-only, not yet implemented in code)
661
+ **Hub**: `storage_hubs` | **Category**: `storage` | **Package prefix**: `storage-`
662
+
663
+ ```typescript
664
+ interface StorageAdapter {
665
+ readonly providerKey: string
666
+
667
+ upload(input: UploadInput): Promise<UploadResult>
668
+ download(input: DownloadInput): Promise<ReadableStream>
669
+ delete(input: DeleteInput): Promise<void>
670
+ getSignedUrl?(input: SignedUrlInput): Promise<string>
671
+ list?(input: ListInput): Promise<StorageFileInfo[]>
672
+ exists?(input: ExistsInput): Promise<boolean>
673
+ }
674
+ ```
675
+
676
+ ### StorageDriver (Attachments Module Level)
677
+
678
+ Used internally by the attachments module to interface with storage backends:
679
+
680
+ ```typescript
681
+ export type StoreFilePayload = {
682
+ partitionCode: string
683
+ orgId: string | null | undefined
684
+ tenantId: string | null | undefined
685
+ fileName: string
686
+ buffer: Buffer
687
+ }
688
+
689
+ export type StoredFile = {
690
+ storagePath: string
691
+ driverMeta?: Record<string, unknown> | null
692
+ }
693
+
694
+ export type ReadFileResult = {
695
+ buffer: Buffer
696
+ contentType?: string
697
+ }
698
+
699
+ export interface StorageDriver {
700
+ readonly key: string
701
+ store(payload: StoreFilePayload): Promise<StoredFile>
702
+ read(partitionCode: string, storagePath: string): Promise<ReadFileResult>
703
+ delete(partitionCode: string, storagePath: string): Promise<void>
704
+ toLocalPath(partitionCode: string, storagePath: string): Promise<{
705
+ filePath: string
706
+ cleanup: () => Promise<void>
707
+ }>
708
+ }
709
+ ```
710
+
711
+ ---
712
+
713
+ ## Summary Table
714
+
715
+ | Adapter | Status | Source Location | Hub ID | Category |
716
+ |---------|--------|----------------|--------|----------|
717
+ | `GatewayAdapter` | Implemented | `packages/shared/src/modules/payment_gateways/types.ts` | `payment_gateways` | `payment` |
718
+ | `ShippingAdapter` | Implemented | `packages/core/src/modules/shipping_carriers/lib/adapter.ts` | `shipping_carriers` | `shipping` |
719
+ | `DataSyncAdapter` | Implemented | `packages/core/src/modules/data_sync/lib/adapter.ts` | `data_sync` | `data_sync` |
720
+ | `ChannelAdapter` | Spec-only | SPEC-045d | `communication_channels` | `communication` |
721
+ | `NotificationTransportAdapter` | Spec-only | SPEC-045d | `notification_providers` | `communication` |
722
+ | `WebhookEndpointAdapter` | Spec-only | SPEC-045e | `webhook_endpoints` | `webhook` |
723
+ | `StorageAdapter` | Spec-only | SPEC-045i | `storage_hubs` | `storage` |
724
+
725
+ ---
726
+
727
+ ## Common Patterns
728
+
729
+ ### Webhook Verification Input (shared across all adapters)
730
+
731
+ ```typescript
732
+ export interface VerifyWebhookInput {
733
+ rawBody: string | Buffer
734
+ headers: Record<string, string | string[] | undefined>
735
+ credentials: Record<string, unknown>
736
+ }
737
+ ```
738
+
739
+ ### Tenant Scope (shared across adapters that need tenant context)
740
+
741
+ ```typescript
742
+ export interface TenantScope {
743
+ organizationId: string
744
+ tenantId: string
745
+ }
746
+ ```
747
+
748
+ ### DI Registration Pattern
749
+
750
+ All adapters follow the same DI registration pattern in `di.ts`:
751
+
752
+ ```typescript
753
+ import type { AppContainer } from '@open-mercato/shared/lib/di/container'
754
+ import { register<Category>Adapter } from '<hub-types-path>'
755
+
756
+ export function register(container: AppContainer): void {
757
+ const adapter = new MyAdapter()
758
+ register<Category>Adapter(adapter)
759
+ // For gateways with versioning:
760
+ // registerGatewayAdapter(adapter, { version: '2025-01-01' })
761
+ }
762
+ ```