@happyvertical/smrt-messages 0.55.9 → 0.55.11

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 (41) hide show
  1. package/README.md +37 -0
  2. package/dist/chunks/{AccountCollection-DhANBhva.js → AccountCollection-BI-osnRy.js} +2 -2
  3. package/dist/chunks/{AccountCollection-DhANBhva.js.map → AccountCollection-BI-osnRy.js.map} +1 -1
  4. package/dist/chunks/{Email-C4cUUFNI.js → Email-BWTPou1O.js} +3 -3
  5. package/dist/chunks/{Email-C4cUUFNI.js.map → Email-BWTPou1O.js.map} +1 -1
  6. package/dist/chunks/{EmailFolder-qoUUSqKI.js → EmailFolder-acO0l4c0.js} +2 -2
  7. package/dist/chunks/{EmailFolder-qoUUSqKI.js.map → EmailFolder-acO0l4c0.js.map} +1 -1
  8. package/dist/chunks/{Message-Bd_2XiIC.js → Message-CX5L_ANS.js} +4 -4
  9. package/dist/chunks/{Message-Bd_2XiIC.js.map → Message-CX5L_ANS.js.map} +1 -1
  10. package/dist/chunks/{MessageCollection-B9MqCWdi.js → MessageCollection-CmKXEeiT.js} +2 -2
  11. package/dist/chunks/{MessageCollection-B9MqCWdi.js.map → MessageCollection-CmKXEeiT.js.map} +1 -1
  12. package/dist/chunks/__smrt-register__-BwaxW-WF.js +6 -0
  13. package/dist/chunks/__smrt-register__-BwaxW-WF.js.map +1 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +145 -11
  17. package/dist/index.js.map +1 -1
  18. package/dist/manifest.json +199 -1
  19. package/dist/playground.js +9 -0
  20. package/dist/playground.js.map +1 -1
  21. package/dist/recipes.d.ts +135 -0
  22. package/dist/recipes.d.ts.map +1 -0
  23. package/dist/smrt-knowledge.json +201 -3
  24. package/dist/svelte/components/MailboxDemo.svelte +65 -0
  25. package/dist/svelte/components/MailboxDemo.svelte.d.ts +4 -0
  26. package/dist/svelte/components/MailboxDemo.svelte.d.ts.map +1 -0
  27. package/dist/svelte/i18n.messages.d.ts +8 -0
  28. package/dist/svelte/i18n.messages.d.ts.map +1 -1
  29. package/dist/svelte/i18n.messages.js +8 -0
  30. package/dist/svelte/index.d.ts +3 -0
  31. package/dist/svelte/index.d.ts.map +1 -1
  32. package/dist/svelte/index.js +2 -0
  33. package/dist/svelte/notifications.d.ts +35 -0
  34. package/dist/svelte/notifications.d.ts.map +1 -0
  35. package/dist/svelte/notifications.js +62 -0
  36. package/dist/svelte/playground.d.ts +34 -0
  37. package/dist/svelte/playground.d.ts.map +1 -1
  38. package/dist/svelte/playground.js +9 -0
  39. package/package.json +9 -9
  40. package/dist/chunks/__smrt-register__-DUoO196-.js +0 -6
  41. package/dist/chunks/__smrt-register__-DUoO196-.js.map +0 -1
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-messages",
5
- "packageVersion": "0.55.9",
5
+ "packageVersion": "0.55.11",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-messages:AccountCollection": {
8
8
  "name": "accountcollection",
@@ -11245,6 +11245,204 @@
11245
11245
  }
11246
11246
  },
11247
11247
  "moduleType": "smrt",
11248
+ "recipes": [
11249
+ {
11250
+ "id": "messages.mailbox",
11251
+ "className": "MailboxRecipe",
11252
+ "label": "Mailbox",
11253
+ "summary": "Read and compose email from your connected accounts.",
11254
+ "synonyms": [
11255
+ "email",
11256
+ "inbox",
11257
+ "mail"
11258
+ ],
11259
+ "models": [
11260
+ "@happyvertical/smrt-messages:Email",
11261
+ "@happyvertical/smrt-messages:EmailAccount"
11262
+ ],
11263
+ "nav": [
11264
+ {
11265
+ "label": "Mailbox",
11266
+ "model": "@happyvertical/smrt-messages:Email",
11267
+ "icon": "folder",
11268
+ "description": "Read email from your connected accounts.",
11269
+ "key": "mailbox",
11270
+ "noun": "email"
11271
+ },
11272
+ {
11273
+ "label": "Failed sends",
11274
+ "model": "@happyvertical/smrt-messages:Email",
11275
+ "icon": "fileText",
11276
+ "description": "Review email whose last send attempt failed.",
11277
+ "key": "failed-sends",
11278
+ "noun": "email",
11279
+ "filter": {
11280
+ "field": "sendStatus",
11281
+ "value": "failed"
11282
+ }
11283
+ }
11284
+ ],
11285
+ "requires": [],
11286
+ "group": {
11287
+ "id": "messages",
11288
+ "label": "Messaging",
11289
+ "summary": "Choose email and personal updates independently."
11290
+ },
11291
+ "section": {
11292
+ "id": "messages",
11293
+ "label": "Messaging",
11294
+ "icon": "folder",
11295
+ "description": "Read email and keep up with updates addressed to you."
11296
+ },
11297
+ "help": {
11298
+ "markdown": "## Your mailbox\nRead messages, open a conversation, or compose an email using a connected account.\nChoose the sender account, add recipients, and check the subject and message before sending.\n\n## Failed sends\nUse Failed sends to review email whose last send attempt failed. Returning to the mailbox shows all email again.\nCheck the failure and sender connection before retrying through your application. This view does not resend email automatically.\n\n## Preview\nThe playground uses fictional messages. Sending and saving are mocked and never contact a mail server.\n\n## Connect an account\nYour application administrator connects an authorized email provider on the server. Real sending and mailbox synchronization require that connection; a preview does not verify delivery.\n",
11299
+ "fieldRefs": []
11300
+ },
11301
+ "surfaces": [
11302
+ {
11303
+ "kind": "route",
11304
+ "path": "/messages/mailbox",
11305
+ "export": "@happyvertical/smrt-messages/svelte#MessageList",
11306
+ "label": "Mailbox"
11307
+ },
11308
+ {
11309
+ "kind": "playground",
11310
+ "export": "@happyvertical/smrt-messages/svelte#MailboxDemo",
11311
+ "label": "Mailbox with mocked sending"
11312
+ }
11313
+ ],
11314
+ "providers": [
11315
+ {
11316
+ "id": "email-inbox",
11317
+ "kind": "email",
11318
+ "options": [
11319
+ "imap",
11320
+ "pop3",
11321
+ "gmail"
11322
+ ],
11323
+ "required": true
11324
+ },
11325
+ {
11326
+ "id": "email-send",
11327
+ "kind": "email",
11328
+ "options": [
11329
+ "smtp",
11330
+ "gmail"
11331
+ ],
11332
+ "required": false
11333
+ }
11334
+ ],
11335
+ "runtime": "both",
11336
+ "demoSeed": {
11337
+ "data": {
11338
+ "accounts": [
11339
+ {
11340
+ "id": "demo-account",
11341
+ "name": "Demo Inbox",
11342
+ "providerType": "email",
11343
+ "email": "you@example.com",
11344
+ "isActive": true
11345
+ }
11346
+ ],
11347
+ "messages": [
11348
+ {
11349
+ "id": "demo-welcome",
11350
+ "type": "email",
11351
+ "accountId": "demo-account",
11352
+ "subject": "Welcome to your mailbox",
11353
+ "body": "Fictional mail. Sending is mocked; nothing leaves this browser.",
11354
+ "senderName": "Demo colleague",
11355
+ "senderAddress": "colleague@example.com",
11356
+ "recipientAddresses": [
11357
+ {
11358
+ "address": "you@example.com"
11359
+ }
11360
+ ],
11361
+ "date": "2026-01-01T12:00:00Z",
11362
+ "isRead": false,
11363
+ "isFlagged": false,
11364
+ "hasAttachments": false
11365
+ }
11366
+ ]
11367
+ }
11368
+ },
11369
+ "demo": {
11370
+ "mode": "server",
11371
+ "reasons": [
11372
+ "Needs a server because its package depends on @happyvertical/smrt-profiles, @happyvertical/smrt-secrets, @happyvertical/smrt-tenancy, @happyvertical/smrt-users, which do not build for a browser (#3617, #3624, #3626, #3627)."
11373
+ ]
11374
+ }
11375
+ },
11376
+ {
11377
+ "id": "messages.notifications",
11378
+ "className": "NotificationsRecipe",
11379
+ "label": "Notifications",
11380
+ "summary": "See updates addressed to you and mark them read.",
11381
+ "synonyms": [
11382
+ "alerts",
11383
+ "notification bell"
11384
+ ],
11385
+ "models": [
11386
+ "@happyvertical/smrt-messages:UserNotification"
11387
+ ],
11388
+ "nav": [],
11389
+ "requires": [],
11390
+ "group": {
11391
+ "id": "messages",
11392
+ "label": "Messaging",
11393
+ "summary": "Choose email and personal updates independently."
11394
+ },
11395
+ "section": {
11396
+ "id": "messages",
11397
+ "label": "Messaging",
11398
+ "icon": "folder",
11399
+ "description": "Read email and keep up with updates addressed to you."
11400
+ },
11401
+ "help": {
11402
+ "markdown": "## Notifications\nOpen the notification bell to see updates addressed to you. Unread updates have a visible marker.\nChoose Mark read for one update or Mark all read for every unread update in your authorized accounts.\nFollow a notification link to open its related record when one is available.\n\n## Availability\nNotifications are scoped to the signed-in person. Your application connects the notification provider and may enable live updates. If loading fails, try again after the connection returns.\n",
11403
+ "fieldRefs": []
11404
+ },
11405
+ "surfaces": [
11406
+ {
11407
+ "kind": "shell-widget",
11408
+ "slot": "header.end",
11409
+ "export": "@happyvertical/smrt-svelte/notifications#NotificationBell",
11410
+ "label": "Notifications"
11411
+ }
11412
+ ],
11413
+ "providers": [
11414
+ {
11415
+ "id": "notifications",
11416
+ "kind": "notifications",
11417
+ "options": [
11418
+ "user-notification-service"
11419
+ ],
11420
+ "required": true
11421
+ }
11422
+ ],
11423
+ "runtime": "both",
11424
+ "demoSeed": {
11425
+ "data": {
11426
+ "items": [
11427
+ {
11428
+ "id": "demo-notification",
11429
+ "title": "You were mentioned",
11430
+ "body": "A fictional update for the demo user.",
11431
+ "occurredAt": "2026-01-01T12:00:00Z",
11432
+ "severity": "info",
11433
+ "readAt": null
11434
+ }
11435
+ ]
11436
+ }
11437
+ },
11438
+ "demo": {
11439
+ "mode": "server",
11440
+ "reasons": [
11441
+ "Needs a server because its package depends on @happyvertical/smrt-profiles, @happyvertical/smrt-secrets, @happyvertical/smrt-tenancy, @happyvertical/smrt-users, which do not build for a browser (#3617, #3624, #3626, #3627)."
11442
+ ]
11443
+ }
11444
+ }
11445
+ ],
11248
11446
  "smrtDependencies": [
11249
11447
  "@happyvertical/smrt-core",
11250
11448
  "@happyvertical/smrt-ledgers",
@@ -76,6 +76,15 @@ var playground_default = {
76
76
  description: MESSAGES_MODULE_META.description,
77
77
  moduleMeta: MESSAGES_MODULE_META,
78
78
  entries: [
79
+ {
80
+ id: "mailbox",
81
+ title: "Mailbox",
82
+ description: "Interactive fictional inbox. Compose and send are mocked; no mail is delivered.",
83
+ loadComponent: () => import("./svelte/components/MailboxDemo.svelte"),
84
+ order: 0,
85
+ props: {},
86
+ modes: { mock: { label: "Mock sending" } }
87
+ },
79
88
  {
80
89
  id: "account-list",
81
90
  title: "Account List",
@@ -1 +1 @@
1
- {"version":3,"file":"playground.js","names":[],"sources":["../src/svelte/playground.ts"],"sourcesContent":["import { MESSAGES_MODULE_META } from '../ui.js';\n\nconst noop = () => {};\n\nconst sampleAccounts = [\n {\n id: 'account-editorial',\n name: 'Editorial Inbox',\n email: 'editorial@example.com',\n providerType: 'email',\n isActive: true,\n unreadCount: 12,\n totalCount: 438,\n lastSyncAt: '2026-03-21T16:12:00.000Z',\n },\n {\n id: 'account-social',\n name: 'Community Slack',\n providerType: 'slack',\n isActive: true,\n unreadCount: 3,\n totalCount: 91,\n lastSyncAt: '2026-03-21T16:05:00.000Z',\n },\n];\n\nconst sampleAttachments = [\n {\n id: 'attachment-proof',\n filename: 'proofing-notes.pdf',\n contentType: 'application/pdf',\n size: 248512,\n },\n];\n\nconst sampleMessages = [\n {\n id: 'message-1',\n type: 'email',\n accountId: 'account-editorial',\n subject: 'Governance review complete',\n body: 'The editorial governance review is complete and the draft is ready for publication.',\n senderName: 'Taylor Rowan',\n senderAddress: 'taylor@example.com',\n recipientAddresses: [\n { address: 'editorial@example.com', name: 'Editorial Desk' },\n ],\n ccAddresses: [{ address: 'governance@example.com', name: 'Governance' }],\n threadId: 'thread-1',\n isRead: true,\n isFlagged: false,\n hasAttachments: true,\n attachments: sampleAttachments,\n date: '2026-03-21T15:30:00.000Z',\n folderPath: 'Inbox',\n labels: ['governance', 'release'],\n sendStatus: 'sent',\n },\n {\n id: 'message-2',\n type: 'slack',\n accountId: 'account-social',\n subject: 'Release coordination',\n body: 'Can we confirm the package rollout order for this afternoon?',\n senderName: 'Jordan Lee',\n senderAddress: 'jordan@example.com',\n recipientAddresses: [{ address: '#release-coordination' }],\n isRead: false,\n isFlagged: true,\n hasAttachments: false,\n date: '2026-03-21T16:02:00.000Z',\n folderPath: 'Slack / release-coordination',\n meta: {\n channelName: 'release-coordination',\n },\n },\n];\n\nconst loadAccountList = () => import('./components/AccountList.svelte');\nconst loadComposeForm = () => import('./components/ComposeForm.svelte');\nconst loadMessageDetail = () => import('./components/MessageDetail.svelte');\nconst loadMessageList = () => import('./components/MessageList.svelte');\n\nexport default {\n packageName: '@happyvertical/smrt-messages',\n displayName: MESSAGES_MODULE_META.displayName,\n description: MESSAGES_MODULE_META.description,\n moduleMeta: MESSAGES_MODULE_META,\n entries: [\n {\n id: 'account-list',\n title: 'Account List',\n description:\n 'Connected messaging accounts with sync state and unread counts.',\n loadComponent: loadAccountList,\n order: 1,\n props: {\n accounts: sampleAccounts,\n onaccountclick: noop,\n onsync: noop,\n onremove: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'message-list',\n title: 'Message List',\n description:\n 'Inbox-style message listing with selection, account context, and type-aware cards.',\n loadComponent: loadMessageList,\n order: 2,\n props: {\n messages: sampleMessages,\n activeMessageId: 'message-1',\n accounts: sampleAccounts,\n showAccount: true,\n onmessageclick: noop,\n onselect: noop,\n onflag: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'message-detail',\n title: 'Message Detail',\n description:\n 'Full message view for reading, attachments, and follow-up actions.',\n loadComponent: loadMessageDetail,\n order: 3,\n props: {\n message: sampleMessages[0],\n attachments: sampleAttachments,\n account: sampleAccounts[0],\n onreply: noop,\n onforward: noop,\n ondelete: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'compose-form',\n title: 'Compose Form',\n description:\n 'Channel-aware compose experience for email, Slack, and short-form posts.',\n loadComponent: loadComposeForm,\n order: 4,\n props: {\n type: 'email',\n accounts: sampleAccounts,\n initialState: {\n accountId: 'account-editorial',\n to: [\n { address: 'ops@example.com', name: 'Operations', isValid: true },\n ],\n subject: 'Launch checklist follow-up',\n body: 'Please confirm the remaining package rollout items for issue #1047.',\n },\n onsend: noop,\n onsavedraft: noop,\n ondiscard: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n ],\n};\n"],"mappings":";;AAEA,IAAM,aAAa,CAAC;AAEpB,IAAM,iBAAiB,CACrB;CACE,IAAI;CACJ,MAAM;CACN,OAAO;CACP,cAAc;CACd,UAAU;CACV,aAAa;CACb,YAAY;CACZ,YAAY;AACd,GACA;CACE,IAAI;CACJ,MAAM;CACN,cAAc;CACd,UAAU;CACV,aAAa;CACb,YAAY;CACZ,YAAY;AACd,CACF;AAEA,IAAM,oBAAoB,CACxB;CACE,IAAI;CACJ,UAAU;CACV,aAAa;CACb,MAAM;AACR,CACF;AAEA,IAAM,iBAAiB,CACrB;CACE,IAAI;CACJ,MAAM;CACN,WAAW;CACX,SAAS;CACT,MAAM;CACN,YAAY;CACZ,eAAe;CACf,oBAAoB,CAClB;EAAE,SAAS;EAAyB,MAAM;CAAiB,CAC7D;CACA,aAAa,CAAC;EAAE,SAAS;EAA0B,MAAM;CAAa,CAAC;CACvE,UAAU;CACV,QAAQ;CACR,WAAW;CACX,gBAAgB;CAChB,aAAa;CACb,MAAM;CACN,YAAY;CACZ,QAAQ,CAAC,cAAc,SAAS;CAChC,YAAY;AACd,GACA;CACE,IAAI;CACJ,MAAM;CACN,WAAW;CACX,SAAS;CACT,MAAM;CACN,YAAY;CACZ,eAAe;CACf,oBAAoB,CAAC,EAAE,SAAS,wBAAwB,CAAC;CACzD,QAAQ;CACR,WAAW;CACX,gBAAgB;CAChB,MAAM;CACN,YAAY;CACZ,MAAM,EACJ,aAAa,uBACf;AACF,CACF;AAEA,IAAM,wBAAwB,OAAO;AACrC,IAAM,wBAAwB,OAAO;AACrC,IAAM,0BAA0B,OAAO;AACvC,IAAM,wBAAwB,OAAO;AAErC,IAAA,qBAAe;CACb,aAAa;CACb,aAAa,qBAAqB;CAClC,aAAa,qBAAqB;CAClC,YAAY;CACZ,SAAS;EACP;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,eAAe;GACf,OAAO;GACP,OAAO;IACL,UAAU;IACV,gBAAgB;IAChB,QAAQ;IACR,UAAU;GACZ;GACA,OAAO,EACL,MAAM,EACJ,OAAO,OACT,EACF;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,eAAe;GACf,OAAO;GACP,OAAO;IACL,UAAU;IACV,iBAAiB;IACjB,UAAU;IACV,aAAa;IACb,gBAAgB;IAChB,UAAU;IACV,QAAQ;GACV;GACA,OAAO,EACL,MAAM,EACJ,OAAO,OACT,EACF;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,eAAe;GACf,OAAO;GACP,OAAO;IACL,SAAS,eAAe;IACxB,aAAa;IACb,SAAS,eAAe;IACxB,SAAS;IACT,WAAW;IACX,UAAU;GACZ;GACA,OAAO,EACL,MAAM,EACJ,OAAO,OACT,EACF;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,eAAe;GACf,OAAO;GACP,OAAO;IACL,MAAM;IACN,UAAU;IACV,cAAc;KACZ,WAAW;KACX,IAAI,CACF;MAAE,SAAS;MAAmB,MAAM;MAAc,SAAS;KAAK,CAClE;KACA,SAAS;KACT,MAAM;IACR;IACA,QAAQ;IACR,aAAa;IACb,WAAW;GACb;GACA,OAAO,EACL,MAAM,EACJ,OAAO,OACT,EACF;EACF;CACF;AACF"}
1
+ {"version":3,"file":"playground.js","names":[],"sources":["../src/svelte/playground.ts"],"sourcesContent":["import { MESSAGES_MODULE_META } from '../ui.js';\n\nconst noop = () => {};\n\nconst sampleAccounts = [\n {\n id: 'account-editorial',\n name: 'Editorial Inbox',\n email: 'editorial@example.com',\n providerType: 'email',\n isActive: true,\n unreadCount: 12,\n totalCount: 438,\n lastSyncAt: '2026-03-21T16:12:00.000Z',\n },\n {\n id: 'account-social',\n name: 'Community Slack',\n providerType: 'slack',\n isActive: true,\n unreadCount: 3,\n totalCount: 91,\n lastSyncAt: '2026-03-21T16:05:00.000Z',\n },\n];\n\nconst sampleAttachments = [\n {\n id: 'attachment-proof',\n filename: 'proofing-notes.pdf',\n contentType: 'application/pdf',\n size: 248512,\n },\n];\n\nconst sampleMessages = [\n {\n id: 'message-1',\n type: 'email',\n accountId: 'account-editorial',\n subject: 'Governance review complete',\n body: 'The editorial governance review is complete and the draft is ready for publication.',\n senderName: 'Taylor Rowan',\n senderAddress: 'taylor@example.com',\n recipientAddresses: [\n { address: 'editorial@example.com', name: 'Editorial Desk' },\n ],\n ccAddresses: [{ address: 'governance@example.com', name: 'Governance' }],\n threadId: 'thread-1',\n isRead: true,\n isFlagged: false,\n hasAttachments: true,\n attachments: sampleAttachments,\n date: '2026-03-21T15:30:00.000Z',\n folderPath: 'Inbox',\n labels: ['governance', 'release'],\n sendStatus: 'sent',\n },\n {\n id: 'message-2',\n type: 'slack',\n accountId: 'account-social',\n subject: 'Release coordination',\n body: 'Can we confirm the package rollout order for this afternoon?',\n senderName: 'Jordan Lee',\n senderAddress: 'jordan@example.com',\n recipientAddresses: [{ address: '#release-coordination' }],\n isRead: false,\n isFlagged: true,\n hasAttachments: false,\n date: '2026-03-21T16:02:00.000Z',\n folderPath: 'Slack / release-coordination',\n meta: {\n channelName: 'release-coordination',\n },\n },\n];\n\nconst loadAccountList = () => import('./components/AccountList.svelte');\nconst loadComposeForm = () => import('./components/ComposeForm.svelte');\nconst loadMessageDetail = () => import('./components/MessageDetail.svelte');\nconst loadMessageList = () => import('./components/MessageList.svelte');\n\nexport default {\n packageName: '@happyvertical/smrt-messages',\n displayName: MESSAGES_MODULE_META.displayName,\n description: MESSAGES_MODULE_META.description,\n moduleMeta: MESSAGES_MODULE_META,\n entries: [\n {\n id: 'mailbox',\n title: 'Mailbox',\n description:\n 'Interactive fictional inbox. Compose and send are mocked; no mail is delivered.',\n loadComponent: () => import('./components/MailboxDemo.svelte'),\n order: 0,\n props: {},\n modes: { mock: { label: 'Mock sending' } },\n },\n {\n id: 'account-list',\n title: 'Account List',\n description:\n 'Connected messaging accounts with sync state and unread counts.',\n loadComponent: loadAccountList,\n order: 1,\n props: {\n accounts: sampleAccounts,\n onaccountclick: noop,\n onsync: noop,\n onremove: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'message-list',\n title: 'Message List',\n description:\n 'Inbox-style message listing with selection, account context, and type-aware cards.',\n loadComponent: loadMessageList,\n order: 2,\n props: {\n messages: sampleMessages,\n activeMessageId: 'message-1',\n accounts: sampleAccounts,\n showAccount: true,\n onmessageclick: noop,\n onselect: noop,\n onflag: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'message-detail',\n title: 'Message Detail',\n description:\n 'Full message view for reading, attachments, and follow-up actions.',\n loadComponent: loadMessageDetail,\n order: 3,\n props: {\n message: sampleMessages[0],\n attachments: sampleAttachments,\n account: sampleAccounts[0],\n onreply: noop,\n onforward: noop,\n ondelete: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'compose-form',\n title: 'Compose Form',\n description:\n 'Channel-aware compose experience for email, Slack, and short-form posts.',\n loadComponent: loadComposeForm,\n order: 4,\n props: {\n type: 'email',\n accounts: sampleAccounts,\n initialState: {\n accountId: 'account-editorial',\n to: [\n { address: 'ops@example.com', name: 'Operations', isValid: true },\n ],\n subject: 'Launch checklist follow-up',\n body: 'Please confirm the remaining package rollout items for issue #1047.',\n },\n onsend: noop,\n onsavedraft: noop,\n ondiscard: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n ],\n};\n"],"mappings":";;AAEA,IAAM,aAAa,CAAC;AAEpB,IAAM,iBAAiB,CACrB;CACE,IAAI;CACJ,MAAM;CACN,OAAO;CACP,cAAc;CACd,UAAU;CACV,aAAa;CACb,YAAY;CACZ,YAAY;AACd,GACA;CACE,IAAI;CACJ,MAAM;CACN,cAAc;CACd,UAAU;CACV,aAAa;CACb,YAAY;CACZ,YAAY;AACd,CACF;AAEA,IAAM,oBAAoB,CACxB;CACE,IAAI;CACJ,UAAU;CACV,aAAa;CACb,MAAM;AACR,CACF;AAEA,IAAM,iBAAiB,CACrB;CACE,IAAI;CACJ,MAAM;CACN,WAAW;CACX,SAAS;CACT,MAAM;CACN,YAAY;CACZ,eAAe;CACf,oBAAoB,CAClB;EAAE,SAAS;EAAyB,MAAM;CAAiB,CAC7D;CACA,aAAa,CAAC;EAAE,SAAS;EAA0B,MAAM;CAAa,CAAC;CACvE,UAAU;CACV,QAAQ;CACR,WAAW;CACX,gBAAgB;CAChB,aAAa;CACb,MAAM;CACN,YAAY;CACZ,QAAQ,CAAC,cAAc,SAAS;CAChC,YAAY;AACd,GACA;CACE,IAAI;CACJ,MAAM;CACN,WAAW;CACX,SAAS;CACT,MAAM;CACN,YAAY;CACZ,eAAe;CACf,oBAAoB,CAAC,EAAE,SAAS,wBAAwB,CAAC;CACzD,QAAQ;CACR,WAAW;CACX,gBAAgB;CAChB,MAAM;CACN,YAAY;CACZ,MAAM,EACJ,aAAa,uBACf;AACF,CACF;AAEA,IAAM,wBAAwB,OAAO;AACrC,IAAM,wBAAwB,OAAO;AACrC,IAAM,0BAA0B,OAAO;AACvC,IAAM,wBAAwB,OAAO;AAErC,IAAA,qBAAe;CACb,aAAa;CACb,aAAa,qBAAqB;CAClC,aAAa,qBAAqB;CAClC,YAAY;CACZ,SAAS;EACP;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,qBAAqB,OAAO;GAC5B,OAAO;GACP,OAAO,CAAC;GACR,OAAO,EAAE,MAAM,EAAE,OAAO,eAAe,EAAE;EAC3C;EACA;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,eAAe;GACf,OAAO;GACP,OAAO;IACL,UAAU;IACV,gBAAgB;IAChB,QAAQ;IACR,UAAU;GACZ;GACA,OAAO,EACL,MAAM,EACJ,OAAO,OACT,EACF;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,eAAe;GACf,OAAO;GACP,OAAO;IACL,UAAU;IACV,iBAAiB;IACjB,UAAU;IACV,aAAa;IACb,gBAAgB;IAChB,UAAU;IACV,QAAQ;GACV;GACA,OAAO,EACL,MAAM,EACJ,OAAO,OACT,EACF;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,eAAe;GACf,OAAO;GACP,OAAO;IACL,SAAS,eAAe;IACxB,aAAa;IACb,SAAS,eAAe;IACxB,SAAS;IACT,WAAW;IACX,UAAU;GACZ;GACA,OAAO,EACL,MAAM,EACJ,OAAO,OACT,EACF;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,aACE;GACF,eAAe;GACf,OAAO;GACP,OAAO;IACL,MAAM;IACN,UAAU;IACV,cAAc;KACZ,WAAW;KACX,IAAI,CACF;MAAE,SAAS;MAAmB,MAAM;MAAc,SAAS;KAAK,CAClE;KACA,SAAS;KACT,MAAM;IACR;IACA,QAAQ;IACR,aAAa;IACb,WAAW;GACb;GACA,OAAO,EACL,MAAM,EACJ,OAAO,OACT,EACF;EACF;CACF;AACF"}
@@ -0,0 +1,135 @@
1
+ import { SmrtRecipe } from '@happyvertical/smrt-core';
2
+ import { Email } from './models/Email.js';
3
+ import { EmailAccount } from './models/EmailAccount.js';
4
+ import { UserNotification } from './models/UserNotification.js';
5
+ /** Email reading and composing with application-owned transport. */
6
+ export declare class MailboxRecipe extends SmrtRecipe {
7
+ static id: string;
8
+ static label: string;
9
+ static summary: string;
10
+ static synonyms: string[];
11
+ static group: {
12
+ id: string;
13
+ label: string;
14
+ summary: string;
15
+ };
16
+ static section: {
17
+ id: string;
18
+ label: string;
19
+ icon: string;
20
+ description: string;
21
+ };
22
+ static models: (typeof Email | typeof EmailAccount)[];
23
+ static runtime: "both";
24
+ static surfaces: readonly [{
25
+ readonly kind: "route";
26
+ readonly path: "/messages/mailbox";
27
+ readonly export: "@happyvertical/smrt-messages/svelte#MessageList";
28
+ readonly label: "Mailbox";
29
+ }, {
30
+ readonly kind: "playground";
31
+ readonly export: "@happyvertical/smrt-messages/svelte#MailboxDemo";
32
+ readonly label: "Mailbox with mocked sending";
33
+ }];
34
+ static providers: {
35
+ id: string;
36
+ kind: string;
37
+ options: string[];
38
+ required: boolean;
39
+ }[];
40
+ static demoSeed: {
41
+ data: {
42
+ accounts: {
43
+ id: string;
44
+ name: string;
45
+ providerType: string;
46
+ email: string;
47
+ isActive: boolean;
48
+ }[];
49
+ messages: {
50
+ id: string;
51
+ type: string;
52
+ accountId: string;
53
+ subject: string;
54
+ body: string;
55
+ senderName: string;
56
+ senderAddress: string;
57
+ recipientAddresses: {
58
+ address: string;
59
+ }[];
60
+ date: string;
61
+ isRead: boolean;
62
+ isFlagged: boolean;
63
+ hasAttachments: boolean;
64
+ }[];
65
+ };
66
+ };
67
+ static nav: ({
68
+ label: string;
69
+ model: typeof Email;
70
+ key: string;
71
+ icon: string;
72
+ noun: string;
73
+ description: string;
74
+ filter?: undefined;
75
+ } | {
76
+ label: string;
77
+ model: typeof Email;
78
+ key: string;
79
+ icon: string;
80
+ noun: string;
81
+ description: string;
82
+ filter: {
83
+ field: string;
84
+ value: string;
85
+ };
86
+ })[];
87
+ static help: string;
88
+ }
89
+ /** Recipient-scoped in-app notification bell. */
90
+ export declare class NotificationsRecipe extends SmrtRecipe {
91
+ static id: string;
92
+ static label: string;
93
+ static summary: string;
94
+ static synonyms: string[];
95
+ static group: {
96
+ id: string;
97
+ label: string;
98
+ summary: string;
99
+ };
100
+ static section: {
101
+ id: string;
102
+ label: string;
103
+ icon: string;
104
+ description: string;
105
+ };
106
+ static models: (typeof UserNotification)[];
107
+ static runtime: "both";
108
+ static surfaces: readonly [{
109
+ readonly kind: "shell-widget";
110
+ readonly slot: "header.end";
111
+ readonly export: "@happyvertical/smrt-svelte/notifications#NotificationBell";
112
+ readonly label: "Notifications";
113
+ }];
114
+ static providers: {
115
+ id: string;
116
+ kind: string;
117
+ options: string[];
118
+ required: boolean;
119
+ }[];
120
+ static demoSeed: {
121
+ data: {
122
+ items: {
123
+ id: string;
124
+ title: string;
125
+ body: string;
126
+ occurredAt: string;
127
+ severity: string;
128
+ readAt: null;
129
+ }[];
130
+ };
131
+ };
132
+ static nav: never[];
133
+ static help: string;
134
+ }
135
+ //# sourceMappingURL=recipes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipes.d.ts","sourceRoot":"","sources":["../src/recipes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,oEAAoE;AACpE,qBAAa,aAAc,SAAQ,UAAU;IAC3C,MAAM,CAAC,EAAE,SAAsB;IAC/B,MAAM,CAAC,KAAK,SAAa;IACzB,MAAM,CAAC,OAAO,SAA0D;IACxE,MAAM,CAAC,QAAQ,WAA8B;IAC7C,MAAM,CAAC,KAAK;;;;MAIV;IACF,MAAM,CAAC,OAAO;;;;;MAKZ;IACF,MAAM,CAAC,MAAM,yCAAyB;IACtC,MAAM,CAAC,OAAO,EAAG,MAAM,CAAU;IACjC,MAAM,CAAC,QAAQ;;;;;;;;;OAYJ;IACX,MAAM,CAAC,SAAS;;;;;QAad;IACF,MAAM,CAAC,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;MA4Bb;IACF,MAAM,CAAC,GAAG;;;;;;;;;;;;;;;;;;;SAkBR;IACF,MAAM,CAAC,IAAI,SAAuB;CACnC;AAED,iDAAiD;AACjD,qBAAa,mBAAoB,SAAQ,UAAU;IACjD,MAAM,CAAC,EAAE,SAA4B;IACrC,MAAM,CAAC,KAAK,SAAmB;IAC/B,MAAM,CAAC,OAAO,SAAsD;IACpE,MAAM,CAAC,QAAQ,WAAmC;IAClD,MAAM,CAAC,KAAK;;;;MAIV;IACF,MAAM,CAAC,OAAO;;;;;MAKZ;IACF,MAAM,CAAC,MAAM,8BAAsB;IACnC,MAAM,CAAC,OAAO,EAAG,MAAM,CAAU;IACjC,MAAM,CAAC,QAAQ;;;;;OAOJ;IACX,MAAM,CAAC,SAAS;;;;;QAOd;IACF,MAAM,CAAC,QAAQ;;;;;;;;;;;MAab;IAEF,MAAM,CAAC,GAAG,UAAM;IAChB,MAAM,CAAC,IAAI,SAA6B;CACzC"}
@@ -3,12 +3,12 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-messages",
6
- "packageVersion": "0.55.9",
6
+ "packageVersion": "0.55.11",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "680a388dbd99d90cd1c624e1c369702b73ecef7bec0a64894c59475c889acf1e",
11
- "packageJson": "e6460c33ef22f7664d5666220b0eb04af74db27989a482a33e2b6e8d7ccb7937",
10
+ "manifest": "eadf03866882986943a242212d58981754af80a451cf17f4fc2910eafa5d65bc",
11
+ "packageJson": "5fe49b181fba9ee82dbb01ad3f18000c1c8bb5e9c531703de47ac21db64c9bfb",
12
12
  "agents": "f2bbd8f6d74a68c2ab949153f2051c7a906bd2e4ba547873b3641d0779491c59"
13
13
  },
14
14
  "exports": [
@@ -15160,6 +15160,204 @@
15160
15160
  "uuidColumns": 96
15161
15161
  },
15162
15162
  "agentDoc": "# @happyvertical/smrt-messages\n\nMulti-channel messaging with STI hierarchies for both messages and accounts. Credential encryption via smrt-secrets.\n\n## STI Hierarchies\n\n**Messages** (share `messages` table):\n- `Message` (base): accountId, personaId, endpointId, correlationId, threadId, subject, body, fromAddress, toAddresses (JSON), sendStatus (draft/sending/sent/failed), retryCount\n- `Email`: messageId (RFC 822), inReplyTo, ccAddresses, bccAddresses, htmlBody, textBody, folderId, labels, headers\n- `Tweet`: tweetId, retweetCount, likeCount, mediaUrls, hashtags, mentions\n- `SlackMessage`: channelId, slackTs, slackThreadTs, reactions, blocks\n\n**Accounts** (share `accounts` table):\n- `Account` (base): channelType, providerType, public configuration,\n credentialSecretId, isActive, lastSyncAt, deprecated sensitive settings\n- `EmailAccount`, `TwitterAccount`, `SlackAccount`, `ZulipAccount`,\n `TelegramAccount`: provider-specific identity/sender behavior\n\n## Persona messaging\n\n- `MessagingEndpoint`: tenant-owned, write-only destination JSON with masked\n display helper.\n- `PersonaMessageRoute`: persona → account + endpoint, selected by purpose and\n descending priority.\n- `PersonaMessagingService`: persists and sends through an enabled route.\n- Provider registry: public setup descriptors + optional sender factory. Keep\n channel (`sms`) separate from provider (`twilio`).\n- Permissions: `messages.send`, `messages.manage-routes`,\n `messages.manage-credentials`.\n- `MessagingSettingsService` is the permissioned server boundary;\n its host-supplied `resolvePersonaTenantId` proves cross-package ownership.\n `MessagingSettingsPanel` is the callback-driven Svelte surface.\n- Account, endpoint, and route generated surfaces are read-only. Do not add\n generated mutations around the settings service or make secret fields writable.\n\n## In-app notifications (`UserNotification`)\n\nThe in-app channel: one stored row per person, with read state.\n`user_notifications`: `tenantId` (required), `recipientUserId`\n(`@crossPackageRef` smrt-users:User, uuid), `kind`, `title`, `body`, `href`,\n`severity` (info/success/warning/error), `sourceRef`, `occurredAt`, `readAt`,\n`dismissedAt`. Conflict identity `(tenant_id, recipient_user_id, source_ref)`.\n\n- `UserNotificationService` is the only access path: `notify()` /\n `notifyMany()` (dedupe on `sourceRef`, existing row returned untouched;\n a unique ref is generated when omitted), `listForUser()` / `countUnread()`\n across explicit `tenantIds` (each read under `withTenant`), `markRead()`,\n `dismiss()` (also marks read), `markAllRead()`. Every write filters on the\n recipient, so another user's id matches nothing.\n- Generated REST/MCP/CLI are off (`api`/`mcp`/`cli: false`): a tenant-scoped\n list would expose every member's rows. Hosts expose their own routes that\n pass the signed-in user's id, never a request-chosen one.\n- Hosts decide who is told (e.g. `SocialPost.createdByUserId` for a failed\n post). New table: consumers run `db:migrate`.\n\n## Credential Security\n\nAccount credentials stored via tenant-bound `credentialSecretId` →\nsmrt-secrets. Use `setCredentials()`/`getCredentials()` — never store passwords\ndirectly. Credential descriptor schemas contain field definitions, never values.\n\n## Send Lifecycle\n\n`message.send()`: resolves account → creates provider sender → updates sendStatus. Retry support with `maxRetries` budget.\n\n## Provider entry points (bundle boundary, #1979)\n\nThe package root is provider-neutral: models, collections, services,\npermissions, and the provider registry carry **zero provider-SDK weight**.\nProvider SDK wrappers (`@happyvertical/email`, `@happyvertical/messages`) are\nreachable only through explicit entry points, imported once at server startup:\n\n```ts\nimport '@happyvertical/smrt-messages/providers/email'; // smtp/imap/pop3/gmail\nimport '@happyvertical/smrt-messages/providers/slack';\nimport '@happyvertical/smrt-messages/providers/twitter';\nimport '@happyvertical/smrt-messages/providers/all'; // all of the above\n```\n\n- Without the matching entry, `EmailAccount.createClient()` (send + mailbox\n sync) throws an actionable error and `SlackSender`/`TweetSender` return a\n failure result naming the entry to import. Telegram and Zulip are\n fetch-based and always work from the root.\n- Builtin registry definitions stay metadata-only (setup fields for UIs); the\n entries upgrade them with `createEmailClient`/`createMessageClient`/\n `createSender` hooks. Never import a provider SDK from any module reachable\n from `src/index.ts` — the consumer bundle gate (`packages/bundle-gate`)\n fails CI when one becomes reachable.\n- `Attachment.readContent()` loads `@happyvertical/files` through core's\n `importOptionalDependency` boundary and keeps its null-on-failure contract\n in builds where the SDK is absent.\n\n## Gotchas\n\n- **Manifest before decorators**: every decorated model imports\n `../__smrt-register__.js`, and `package.json#sideEffects` lists\n `./src/__smrt-register__.ts`. Without both, the library build dropped or\n reordered the self-registration, so dist classes registered with only their\n decorated fields and could adopt smrt-ledgers' same-named `Account` (#3098).\n- **`Account` is not unique**: smrt-ledgers also declares `Account` (on\n `ledger_accounts`). Resolve by constructor or qualified name; the\n coexistence tests (`ledger-account-identity-*`, and the PostgreSQL lane\n `pnpm test:postgres`) load both packages in both orders.\n- **STI `_meta_type`**: qualified format `@happyvertical/smrt-messages:Email`\n- **JSON fields**: all address/metadata fields are JSON strings with `getX()`/`setX()` helpers\n- **RFC 822 threading**: Email uses `inReplyTo`/`messageId`/`references` — manual management required\n- **Attachment.messageId**: use this field (not `emailId`); old getter/setter mapped via deprecation wrapper\n- **Optional tenancy**: `@TenantScoped({ mode: 'optional' })` on Message, Account, Attachment\n- **Required tenancy**: endpoints and persona routes are always tenant scoped\n- **Secrets are write-only**: never serialize credentials or endpoint.address to an app\n\n## Intake byte snapshots\n\n`EmailAccount.readIntakeMessage(providerLookup, maxBytes, imapIdentity?)` is the authorized host seam for\nopt-in ingestion. It copies full-message attachment bytes from the registered\nemail provider and fails when only attachment metadata is available; it never\nreads provider-supplied paths or advances sync checkpoints. Keep this path\nprovider-neutral and exclude arbitrary headers/credentials from its snapshot.\nIMAP lookup must include folder/UIDVALIDITY/UID verification; sender Message-ID\nis a lookup hint, never the durable delivery identity.\n",
15163
+ "recipes": [
15164
+ {
15165
+ "id": "messages.mailbox",
15166
+ "className": "MailboxRecipe",
15167
+ "label": "Mailbox",
15168
+ "summary": "Read and compose email from your connected accounts.",
15169
+ "synonyms": [
15170
+ "email",
15171
+ "inbox",
15172
+ "mail"
15173
+ ],
15174
+ "models": [
15175
+ "@happyvertical/smrt-messages:Email",
15176
+ "@happyvertical/smrt-messages:EmailAccount"
15177
+ ],
15178
+ "nav": [
15179
+ {
15180
+ "label": "Mailbox",
15181
+ "model": "@happyvertical/smrt-messages:Email",
15182
+ "icon": "folder",
15183
+ "description": "Read email from your connected accounts.",
15184
+ "key": "mailbox",
15185
+ "noun": "email"
15186
+ },
15187
+ {
15188
+ "label": "Failed sends",
15189
+ "model": "@happyvertical/smrt-messages:Email",
15190
+ "icon": "fileText",
15191
+ "description": "Review email whose last send attempt failed.",
15192
+ "key": "failed-sends",
15193
+ "noun": "email",
15194
+ "filter": {
15195
+ "field": "sendStatus",
15196
+ "value": "failed"
15197
+ }
15198
+ }
15199
+ ],
15200
+ "requires": [],
15201
+ "group": {
15202
+ "id": "messages",
15203
+ "label": "Messaging",
15204
+ "summary": "Choose email and personal updates independently."
15205
+ },
15206
+ "section": {
15207
+ "id": "messages",
15208
+ "label": "Messaging",
15209
+ "icon": "folder",
15210
+ "description": "Read email and keep up with updates addressed to you."
15211
+ },
15212
+ "help": {
15213
+ "markdown": "## Your mailbox\nRead messages, open a conversation, or compose an email using a connected account.\nChoose the sender account, add recipients, and check the subject and message before sending.\n\n## Failed sends\nUse Failed sends to review email whose last send attempt failed. Returning to the mailbox shows all email again.\nCheck the failure and sender connection before retrying through your application. This view does not resend email automatically.\n\n## Preview\nThe playground uses fictional messages. Sending and saving are mocked and never contact a mail server.\n\n## Connect an account\nYour application administrator connects an authorized email provider on the server. Real sending and mailbox synchronization require that connection; a preview does not verify delivery.\n",
15214
+ "fieldRefs": []
15215
+ },
15216
+ "surfaces": [
15217
+ {
15218
+ "kind": "route",
15219
+ "path": "/messages/mailbox",
15220
+ "export": "@happyvertical/smrt-messages/svelte#MessageList",
15221
+ "label": "Mailbox"
15222
+ },
15223
+ {
15224
+ "kind": "playground",
15225
+ "export": "@happyvertical/smrt-messages/svelte#MailboxDemo",
15226
+ "label": "Mailbox with mocked sending"
15227
+ }
15228
+ ],
15229
+ "providers": [
15230
+ {
15231
+ "id": "email-inbox",
15232
+ "kind": "email",
15233
+ "options": [
15234
+ "imap",
15235
+ "pop3",
15236
+ "gmail"
15237
+ ],
15238
+ "required": true
15239
+ },
15240
+ {
15241
+ "id": "email-send",
15242
+ "kind": "email",
15243
+ "options": [
15244
+ "smtp",
15245
+ "gmail"
15246
+ ],
15247
+ "required": false
15248
+ }
15249
+ ],
15250
+ "runtime": "both",
15251
+ "demoSeed": {
15252
+ "data": {
15253
+ "accounts": [
15254
+ {
15255
+ "id": "demo-account",
15256
+ "name": "Demo Inbox",
15257
+ "providerType": "email",
15258
+ "email": "you@example.com",
15259
+ "isActive": true
15260
+ }
15261
+ ],
15262
+ "messages": [
15263
+ {
15264
+ "id": "demo-welcome",
15265
+ "type": "email",
15266
+ "accountId": "demo-account",
15267
+ "subject": "Welcome to your mailbox",
15268
+ "body": "Fictional mail. Sending is mocked; nothing leaves this browser.",
15269
+ "senderName": "Demo colleague",
15270
+ "senderAddress": "colleague@example.com",
15271
+ "recipientAddresses": [
15272
+ {
15273
+ "address": "you@example.com"
15274
+ }
15275
+ ],
15276
+ "date": "2026-01-01T12:00:00Z",
15277
+ "isRead": false,
15278
+ "isFlagged": false,
15279
+ "hasAttachments": false
15280
+ }
15281
+ ]
15282
+ }
15283
+ },
15284
+ "demo": {
15285
+ "mode": "server",
15286
+ "reasons": [
15287
+ "Needs a server because its package depends on @happyvertical/smrt-profiles, @happyvertical/smrt-secrets, @happyvertical/smrt-tenancy, @happyvertical/smrt-users, which do not build for a browser (#3617, #3624, #3626, #3627)."
15288
+ ]
15289
+ }
15290
+ },
15291
+ {
15292
+ "id": "messages.notifications",
15293
+ "className": "NotificationsRecipe",
15294
+ "label": "Notifications",
15295
+ "summary": "See updates addressed to you and mark them read.",
15296
+ "synonyms": [
15297
+ "alerts",
15298
+ "notification bell"
15299
+ ],
15300
+ "models": [
15301
+ "@happyvertical/smrt-messages:UserNotification"
15302
+ ],
15303
+ "nav": [],
15304
+ "requires": [],
15305
+ "group": {
15306
+ "id": "messages",
15307
+ "label": "Messaging",
15308
+ "summary": "Choose email and personal updates independently."
15309
+ },
15310
+ "section": {
15311
+ "id": "messages",
15312
+ "label": "Messaging",
15313
+ "icon": "folder",
15314
+ "description": "Read email and keep up with updates addressed to you."
15315
+ },
15316
+ "help": {
15317
+ "markdown": "## Notifications\nOpen the notification bell to see updates addressed to you. Unread updates have a visible marker.\nChoose Mark read for one update or Mark all read for every unread update in your authorized accounts.\nFollow a notification link to open its related record when one is available.\n\n## Availability\nNotifications are scoped to the signed-in person. Your application connects the notification provider and may enable live updates. If loading fails, try again after the connection returns.\n",
15318
+ "fieldRefs": []
15319
+ },
15320
+ "surfaces": [
15321
+ {
15322
+ "kind": "shell-widget",
15323
+ "slot": "header.end",
15324
+ "export": "@happyvertical/smrt-svelte/notifications#NotificationBell",
15325
+ "label": "Notifications"
15326
+ }
15327
+ ],
15328
+ "providers": [
15329
+ {
15330
+ "id": "notifications",
15331
+ "kind": "notifications",
15332
+ "options": [
15333
+ "user-notification-service"
15334
+ ],
15335
+ "required": true
15336
+ }
15337
+ ],
15338
+ "runtime": "both",
15339
+ "demoSeed": {
15340
+ "data": {
15341
+ "items": [
15342
+ {
15343
+ "id": "demo-notification",
15344
+ "title": "You were mentioned",
15345
+ "body": "A fictional update for the demo user.",
15346
+ "occurredAt": "2026-01-01T12:00:00Z",
15347
+ "severity": "info",
15348
+ "readAt": null
15349
+ }
15350
+ ]
15351
+ }
15352
+ },
15353
+ "demo": {
15354
+ "mode": "server",
15355
+ "reasons": [
15356
+ "Needs a server because its package depends on @happyvertical/smrt-profiles, @happyvertical/smrt-secrets, @happyvertical/smrt-tenancy, @happyvertical/smrt-users, which do not build for a browser (#3617, #3624, #3626, #3627)."
15357
+ ]
15358
+ }
15359
+ }
15360
+ ],
15163
15361
  "browser": {
15164
15362
  "status": "server-only",
15165
15363
  "issues": [