@happyvertical/smrt-messages 0.55.7 → 0.55.8

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/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { t as __exportAll } from "./chunks/rolldown-runtime-D7D4PA-g.js";
2
- import "./chunks/__smrt-register__-DyB0ALdL.js";
2
+ import "./chunks/__smrt-register__-k26r-4c4.js";
3
3
  import { a as registerMessagingProvider, n as getMessagingProvider, o as ZulipSender, r as listMessagingProviders, s as TelegramSender, t as ensureBuiltinMessagingProvidersRegistered } from "./chunks/providers-4iLula-V.js";
4
- import { r as Account, t as AccountCollection } from "./chunks/AccountCollection-D0jYNESQ.js";
5
- import { t as Message } from "./chunks/Message-CSv9rJva.js";
6
- import { t as MessageCollection } from "./chunks/MessageCollection-4yzuqVl4.js";
7
- import { t as Email } from "./chunks/Email-hneqk2_l.js";
8
- import { t as EmailFolder } from "./chunks/EmailFolder-CFd0haPW.js";
4
+ import { r as Account, t as AccountCollection } from "./chunks/AccountCollection-BzB9_1K5.js";
5
+ import { t as Message } from "./chunks/Message-m5TaReki.js";
6
+ import { t as MessageCollection } from "./chunks/MessageCollection-BKmQiDUy.js";
7
+ import { t as Email } from "./chunks/Email-ehe9wBwT.js";
8
+ import { t as EmailFolder } from "./chunks/EmailFolder-DmtOt_iW.js";
9
9
  import { t as SlackSender } from "./chunks/SlackSender-CjSvwY1K.js";
10
10
  import { t as TweetSender } from "./chunks/TweetSender-CcLPNNi1.js";
11
11
  import { SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, importOptionalDependency, isUniqueViolationError, smrt } from "@happyvertical/smrt-core";
@@ -98,7 +98,7 @@ var Attachment = class extends SmrtObject {
98
98
  */
99
99
  async getMessage() {
100
100
  if (!this.messageId) return null;
101
- const { MessageCollection } = await import("./chunks/MessageCollection-4yzuqVl4.js").then((n) => n.n);
101
+ const { MessageCollection } = await import("./chunks/MessageCollection-BKmQiDUy.js").then((n) => n.n);
102
102
  return await (await MessageCollection.create(this.options)).get({ id: this.messageId });
103
103
  }
104
104
  /**
@@ -670,7 +670,7 @@ var EmailAccount = class extends Account {
670
670
  for (const folderName of foldersToSync) try {
671
671
  let folder = await folderCollection.getByPath(accountId, folderName);
672
672
  if (!folder) {
673
- const { EmailFolder } = await import("./chunks/EmailFolder-CFd0haPW.js").then((n) => n.n);
673
+ const { EmailFolder } = await import("./chunks/EmailFolder-DmtOt_iW.js").then((n) => n.n);
674
674
  folder = new EmailFolder({
675
675
  ...this.childOptions(),
676
676
  accountId,
@@ -695,7 +695,7 @@ var EmailAccount = class extends Account {
695
695
  result.messagesSkipped++;
696
696
  continue;
697
697
  }
698
- const { Email } = await import("./chunks/Email-hneqk2_l.js").then((n) => n.n);
698
+ const { Email } = await import("./chunks/Email-ehe9wBwT.js").then((n) => n.n);
699
699
  let email = existingEmail;
700
700
  if (!email) {
701
701
  email = new Email({
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-messages",
5
- "packageVersion": "0.55.7",
5
+ "packageVersion": "0.55.8",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-messages:AccountCollection": {
8
8
  "name": "accountcollection",
@@ -11252,5 +11252,20 @@
11252
11252
  "@happyvertical/smrt-tenancy",
11253
11253
  "@happyvertical/smrt-users"
11254
11254
  ],
11255
+ "browser": {
11256
+ "status": "server-only",
11257
+ "issues": [
11258
+ "#3617",
11259
+ "#3624",
11260
+ "#3626",
11261
+ "#3627"
11262
+ ],
11263
+ "via": [
11264
+ "@happyvertical/smrt-profiles",
11265
+ "@happyvertical/smrt-secrets",
11266
+ "@happyvertical/smrt-tenancy",
11267
+ "@happyvertical/smrt-users"
11268
+ ]
11269
+ },
11255
11270
  "stampsConstructors": true
11256
11271
  }
@@ -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.7",
6
+ "packageVersion": "0.55.8",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "659c7f9d8ac03578b8941f7ed4d51bfd694d4d8935fdfc6fdc6ad2d4ba2c7ea0",
11
- "packageJson": "a78822c0a563fc3c3f4f3814e7a513206b07e2a913fb6383acebc99a2a6fe50b",
10
+ "manifest": "10ea9828d81d9db0078a101d10dbf24578abb3dc95b89014ce7a3bab78b3a554",
11
+ "packageJson": "58ff83eda7d70f47622624659fbfc6023382eeace89ba878ab15e1c26911806c",
12
12
  "agents": "f2bbd8f6d74a68c2ab949153f2051c7a906bd2e4ba547873b3641d0779491c59"
13
13
  },
14
14
  "exports": [
@@ -15159,5 +15159,20 @@
15159
15159
  "polymorphicAssociations": 0,
15160
15160
  "uuidColumns": 96
15161
15161
  },
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"
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
+ "browser": {
15164
+ "status": "server-only",
15165
+ "issues": [
15166
+ "#3617",
15167
+ "#3624",
15168
+ "#3626",
15169
+ "#3627"
15170
+ ],
15171
+ "via": [
15172
+ "@happyvertical/smrt-profiles",
15173
+ "@happyvertical/smrt-secrets",
15174
+ "@happyvertical/smrt-tenancy",
15175
+ "@happyvertical/smrt-users"
15176
+ ]
15177
+ }
15163
15178
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-messages",
3
- "version": "0.55.7",
3
+ "version": "0.55.8",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Unified multi-channel messaging with STI-based hierarchies",
6
6
  "type": "module",
@@ -58,18 +58,18 @@
58
58
  "./dist/svelte/index.js"
59
59
  ],
60
60
  "dependencies": {
61
- "@happyvertical/email": "^0.102.5",
62
- "@happyvertical/files": "^0.102.5",
63
- "@happyvertical/logger": "^0.102.5",
64
- "@happyvertical/messages": "^0.102.5",
65
- "@happyvertical/smrt-core": "0.55.7",
66
- "@happyvertical/smrt-types": "0.55.7",
67
- "@happyvertical/smrt-secrets": "0.55.7",
68
- "@happyvertical/smrt-tenancy": "0.55.7",
69
- "@happyvertical/smrt-ui": "0.55.7",
70
- "@happyvertical/smrt-users": "0.55.7",
71
- "@happyvertical/sql": "^0.102.5",
72
- "@happyvertical/utils": "^0.102.5"
61
+ "@happyvertical/email": "^0.103.1",
62
+ "@happyvertical/files": "^0.103.1",
63
+ "@happyvertical/logger": "^0.103.1",
64
+ "@happyvertical/messages": "^0.103.1",
65
+ "@happyvertical/smrt-core": "0.55.8",
66
+ "@happyvertical/smrt-types": "0.55.8",
67
+ "@happyvertical/smrt-secrets": "0.55.8",
68
+ "@happyvertical/smrt-tenancy": "0.55.8",
69
+ "@happyvertical/smrt-ui": "0.55.8",
70
+ "@happyvertical/smrt-users": "0.55.8",
71
+ "@happyvertical/sql": "^0.103.1",
72
+ "@happyvertical/utils": "^0.103.1"
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@happyvertical/encryption": "*",
@@ -84,8 +84,8 @@
84
84
  }
85
85
  },
86
86
  "devDependencies": {
87
- "@happyvertical/smrt-ledgers": "0.55.7",
88
- "@happyvertical/smrt-vitest": "0.55.7",
87
+ "@happyvertical/smrt-ledgers": "0.55.8",
88
+ "@happyvertical/smrt-vitest": "0.55.8",
89
89
  "@sveltejs/package": "^2.5.8",
90
90
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
91
91
  "@types/node": "24.13.6",