@happyvertical/smrt-comments 0.56.0 → 0.56.1
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 +1 -1
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/smrt-knowledge.json +3 -3
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ObjectRegistry, SmrtCollection, SmrtPolymorphicAssociation, SmrtRecipe, crossPackageRef, digestRunOnceContent, field, runOnce, smrt } from "@happyvertical/smrt-core";
|
|
2
2
|
import { TenantIsolationError, TenantScoped, getCurrentTenant, tenantId, withTenant } from "@happyvertical/smrt-tenancy";
|
|
3
3
|
//#region src/__smrt-register__.ts
|
|
4
|
-
ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-comments","packageVersion":"0.56.0","objects":{"@happyvertical/smrt-comments:CommentCollection":{"name":"commentcollection","className":"CommentCollection","qualifiedName":"@happyvertical/smrt-comments:CommentCollection","collection":"comments","filePath":"/home/runner/work/smrt/smrt/packages/comments/src/collections/CommentCollection.ts","packageName":"@happyvertical/smrt-comments","fields":{},"methods":{"listForRecord":{"name":"listForRecord","async":true,"parameters":[{"name":"recordType","type":"string","optional":false},{"name":"recordId","type":"string","optional":false}],"returnType":"Promise<Comment[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"record_comments","api":false,"mcp":false,"cli":false},"extends":"SmrtCollection","extendsTypeArg":"Comment","exportName":"CommentCollection","collectionExportName":"CommentCollectionCollection","schema":{"tableName":"record_comments","ddl":"CREATE TABLE IF NOT EXISTS \\"record_comments\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"meta_type\\" TEXT NOT NULL,\\n \\"meta_id\\" TEXT NOT NULL,\\n \\"role\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER DEFAULT 0,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"author_user_id\\" UUID NOT NULL,\\n \\"body\\" TEXT NOT NULL,\\n \\"mentions\\" TEXT,\\n \\"idempotency_key\\" TEXT,\\n \\"retry_tenant_id\\" TEXT,\\n \\"request_digest\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"meta_type":{"type":"TEXT","notNull":true,"unique":false},"meta_id":{"type":"TEXT","notNull":true,"unique":false},"role":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"author_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false},"body":{"type":"TEXT","notNull":true,"unique":false},"mentions":{"type":"TEXT","notNull":false,"unique":false},"idempotency_key":{"type":"TEXT","notNull":false,"unique":false},"retry_tenant_id":{"type":"TEXT","notNull":false,"unique":false},"request_digest":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"record_comments_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"record_comments_tenant_request_key","columns":["retry_tenant_id","idempotency_key"],"unique":true},{"name":"record_comments_record_created_idx","columns":["tenant_id","meta_type","meta_id","created_at"]},{"name":"record_comments_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"record_comments_meta_type_meta_id_idx","columns":["meta_type","meta_id"]},{"name":"record_comments_author_user_id_idx","columns":["author_user_id"]}],"version":"5095dfc9"},"importPath":"@happyvertical/smrt-comments"},"@happyvertical/smrt-comments:Comment":{"name":"comment","className":"Comment","qualifiedName":"@happyvertical/smrt-comments:Comment","collection":"comments","filePath":"/home/runner/work/smrt/smrt/packages/comments/src/models/Comment.ts","packageName":"@happyvertical/smrt-comments","fields":{"metaType":{"type":"text","required":true,"_meta":{"required":true}},"metaId":{"type":"text","required":true,"_meta":{"required":true}},"role":{"type":"text","required":true,"_meta":{"required":true}},"sortOrder":{"type":"integer","required":false,"default":0},"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"authorUserId":{"type":"crossPackageRef","required":true,"related":"@happyvertical/smrt-users:User"},"body":{"type":"text","required":true,"_meta":{"required":true}},"mentions":{"type":"text","required":false},"idempotencyKey":{"type":"text","required":false,"_meta":{"nullable":true,"readonly":true},"readonly":true},"retryTenantId":{"type":"text","required":false,"_meta":{"nullable":true,"readonly":true},"readonly":true},"requestDigest":{"type":"text","required":false,"_meta":{"nullable":true,"readonly":true},"readonly":true}},"methods":{"hydrate":{"name":"hydrate","async":true,"parameters":[],"returnType":"Promise<T | null>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"record_comments","api":false,"mcp":false,"cli":false,"indexes":[{"name":"record_comments_tenant_request_key","columns":["retryTenantId","idempotencyKey"],"unique":true},{"name":"record_comments_record_created_idx","columns":["tenantId","metaType","metaId","createdAt"]}],"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtPolymorphicAssociation","exportName":"Comment","collectionExportName":"CommentCollection","validationRules":[{"field":"metaType","rule":"required","fieldType":"text"},{"field":"metaId","rule":"required","fieldType":"text"},{"field":"role","rule":"required","fieldType":"text"},{"field":"authorUserId","rule":"required","fieldType":"crossPackageRef"},{"field":"body","rule":"required","fieldType":"text"}],"schema":{"tableName":"record_comments","ddl":"CREATE TABLE IF NOT EXISTS \\"record_comments\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"meta_type\\" TEXT NOT NULL,\\n \\"meta_id\\" TEXT NOT NULL,\\n \\"role\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER DEFAULT 0,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"author_user_id\\" UUID NOT NULL,\\n \\"body\\" TEXT NOT NULL,\\n \\"mentions\\" TEXT,\\n \\"idempotency_key\\" TEXT,\\n \\"retry_tenant_id\\" TEXT,\\n \\"request_digest\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"meta_type":{"type":"TEXT","notNull":true,"unique":false},"meta_id":{"type":"TEXT","notNull":true,"unique":false},"role":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"author_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false},"body":{"type":"TEXT","notNull":true,"unique":false},"mentions":{"type":"TEXT","notNull":false,"unique":false},"idempotency_key":{"type":"TEXT","notNull":false,"unique":false},"retry_tenant_id":{"type":"TEXT","notNull":false,"unique":false},"request_digest":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"record_comments_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"record_comments_tenant_request_key","columns":["retry_tenant_id","idempotency_key"],"unique":true},{"name":"record_comments_record_created_idx","columns":["tenant_id","meta_type","meta_id","created_at"]},{"name":"record_comments_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"record_comments_meta_type_meta_id_idx","columns":["meta_type","meta_id"]},{"name":"record_comments_author_user_id_idx","columns":["author_user_id"]}],"version":"5095dfc9"},"importPath":"@happyvertical/smrt-comments"}},"moduleType":"smrt","recipes":[{"id":"comments.records","className":"RecordCommentsRecipe","label":"Record comments","summary":"Discuss work directly on the records it concerns.","synonyms":["comments","mentions","discussion"],"models":["@happyvertical/smrt-comments:Comment"],"nav":[],"requires":[],"group":{"id":"comments","label":"Comments","summary":"Keep discussions alongside the records your team works on."},"help":{"markdown":"## Overview\\n\\nRecord comments keep a discussion next to the work it concerns. Open a record\\nyou can access to read its discussion or add a comment. Comments are part of\\nthe record page, rather than a separate list of every discussion.\\n\\n## Tasks\\n\\n### Add a comment\\n\\nOpen the record, find Comments, write your message and choose Post comment.\\nYour app controls who can read the record and who can contribute to its discussion.\\n\\n### Mention someone\\n\\nIf your app provides mention selection, choose a teammate who can access the\\nrecord. When mention notifications are connected, that person receives a\\nnotification. Typing a name alone does not select a recipient.\\n\\n### Check a failed post\\n\\nIf posting reports an error, refresh the discussion before trying again. A\\ncomment may have been saved even when its mention notification could not be\\ndelivered. If it appears in the discussion, do not post it a second time.\\n","fieldRefs":[]},"surfaces":[{"kind":"playground","export":"@happyvertical/smrt-comments/svelte#RecordCommentsPlayground","label":"Record discussion preview"}],"runtime":"both","demoSeed":{"export":"@happyvertical/smrt-comments/svelte#recordCommentsDemo"},"demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}}],"smrtDependencies":["@happyvertical/smrt-core","@happyvertical/smrt-messages","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624"],"via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
|
|
4
|
+
ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-comments","packageVersion":"0.56.1","objects":{"@happyvertical/smrt-comments:CommentCollection":{"name":"commentcollection","className":"CommentCollection","qualifiedName":"@happyvertical/smrt-comments:CommentCollection","collection":"comments","filePath":"/home/runner/work/smrt/smrt/packages/comments/src/collections/CommentCollection.ts","packageName":"@happyvertical/smrt-comments","fields":{},"methods":{"listForRecord":{"name":"listForRecord","async":true,"parameters":[{"name":"recordType","type":"string","optional":false},{"name":"recordId","type":"string","optional":false}],"returnType":"Promise<Comment[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"record_comments","api":false,"mcp":false,"cli":false},"extends":"SmrtCollection","extendsTypeArg":"Comment","exportName":"CommentCollection","collectionExportName":"CommentCollectionCollection","schema":{"tableName":"record_comments","ddl":"CREATE TABLE IF NOT EXISTS \\"record_comments\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"meta_type\\" TEXT NOT NULL,\\n \\"meta_id\\" TEXT NOT NULL,\\n \\"role\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER DEFAULT 0,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"author_user_id\\" UUID NOT NULL,\\n \\"body\\" TEXT NOT NULL,\\n \\"mentions\\" TEXT,\\n \\"idempotency_key\\" TEXT,\\n \\"retry_tenant_id\\" TEXT,\\n \\"request_digest\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"meta_type":{"type":"TEXT","notNull":true,"unique":false},"meta_id":{"type":"TEXT","notNull":true,"unique":false},"role":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"author_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false},"body":{"type":"TEXT","notNull":true,"unique":false},"mentions":{"type":"TEXT","notNull":false,"unique":false},"idempotency_key":{"type":"TEXT","notNull":false,"unique":false},"retry_tenant_id":{"type":"TEXT","notNull":false,"unique":false},"request_digest":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"record_comments_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"record_comments_tenant_request_key","columns":["retry_tenant_id","idempotency_key"],"unique":true},{"name":"record_comments_record_created_idx","columns":["tenant_id","meta_type","meta_id","created_at"]},{"name":"record_comments_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"record_comments_meta_type_meta_id_idx","columns":["meta_type","meta_id"]},{"name":"record_comments_author_user_id_idx","columns":["author_user_id"]}],"version":"5095dfc9"},"importPath":"@happyvertical/smrt-comments"},"@happyvertical/smrt-comments:Comment":{"name":"comment","className":"Comment","qualifiedName":"@happyvertical/smrt-comments:Comment","collection":"comments","filePath":"/home/runner/work/smrt/smrt/packages/comments/src/models/Comment.ts","packageName":"@happyvertical/smrt-comments","fields":{"metaType":{"type":"text","required":true,"_meta":{"required":true}},"metaId":{"type":"text","required":true,"_meta":{"required":true}},"role":{"type":"text","required":true,"_meta":{"required":true}},"sortOrder":{"type":"integer","required":false,"default":0},"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"authorUserId":{"type":"crossPackageRef","required":true,"related":"@happyvertical/smrt-users:User"},"body":{"type":"text","required":true,"_meta":{"required":true}},"mentions":{"type":"text","required":false},"idempotencyKey":{"type":"text","required":false,"_meta":{"nullable":true,"readonly":true},"readonly":true},"retryTenantId":{"type":"text","required":false,"_meta":{"nullable":true,"readonly":true},"readonly":true},"requestDigest":{"type":"text","required":false,"_meta":{"nullable":true,"readonly":true},"readonly":true}},"methods":{"hydrate":{"name":"hydrate","async":true,"parameters":[],"returnType":"Promise<T | null>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"record_comments","api":false,"mcp":false,"cli":false,"indexes":[{"name":"record_comments_tenant_request_key","columns":["retryTenantId","idempotencyKey"],"unique":true},{"name":"record_comments_record_created_idx","columns":["tenantId","metaType","metaId","createdAt"]}],"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtPolymorphicAssociation","exportName":"Comment","collectionExportName":"CommentCollection","validationRules":[{"field":"metaType","rule":"required","fieldType":"text"},{"field":"metaId","rule":"required","fieldType":"text"},{"field":"role","rule":"required","fieldType":"text"},{"field":"authorUserId","rule":"required","fieldType":"crossPackageRef"},{"field":"body","rule":"required","fieldType":"text"}],"schema":{"tableName":"record_comments","ddl":"CREATE TABLE IF NOT EXISTS \\"record_comments\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"meta_type\\" TEXT NOT NULL,\\n \\"meta_id\\" TEXT NOT NULL,\\n \\"role\\" TEXT NOT NULL,\\n \\"sort_order\\" INTEGER DEFAULT 0,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"author_user_id\\" UUID NOT NULL,\\n \\"body\\" TEXT NOT NULL,\\n \\"mentions\\" TEXT,\\n \\"idempotency_key\\" TEXT,\\n \\"retry_tenant_id\\" TEXT,\\n \\"request_digest\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"meta_type":{"type":"TEXT","notNull":true,"unique":false},"meta_id":{"type":"TEXT","notNull":true,"unique":false},"role":{"type":"TEXT","notNull":true,"unique":false},"sort_order":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"author_user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":true,"unique":false},"body":{"type":"TEXT","notNull":true,"unique":false},"mentions":{"type":"TEXT","notNull":false,"unique":false},"idempotency_key":{"type":"TEXT","notNull":false,"unique":false},"retry_tenant_id":{"type":"TEXT","notNull":false,"unique":false},"request_digest":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"record_comments_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"record_comments_tenant_request_key","columns":["retry_tenant_id","idempotency_key"],"unique":true},{"name":"record_comments_record_created_idx","columns":["tenant_id","meta_type","meta_id","created_at"]},{"name":"record_comments_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"record_comments_meta_type_meta_id_idx","columns":["meta_type","meta_id"]},{"name":"record_comments_author_user_id_idx","columns":["author_user_id"]}],"version":"5095dfc9"},"importPath":"@happyvertical/smrt-comments"}},"moduleType":"smrt","recipes":[{"id":"comments.records","className":"RecordCommentsRecipe","label":"Record comments","summary":"Discuss work directly on the records it concerns.","synonyms":["comments","mentions","discussion"],"models":["@happyvertical/smrt-comments:Comment"],"nav":[],"requires":[],"group":{"id":"comments","label":"Comments","summary":"Keep discussions alongside the records your team works on."},"help":{"markdown":"## Overview\\n\\nRecord comments keep a discussion next to the work it concerns. Open a record\\nyou can access to read its discussion or add a comment. Comments are part of\\nthe record page, rather than a separate list of every discussion.\\n\\n## Tasks\\n\\n### Add a comment\\n\\nOpen the record, find Comments, write your message and choose Post comment.\\nYour app controls who can read the record and who can contribute to its discussion.\\n\\n### Mention someone\\n\\nIf your app provides mention selection, choose a teammate who can access the\\nrecord. When mention notifications are connected, that person receives a\\nnotification. Typing a name alone does not select a recipient.\\n\\n### Check a failed post\\n\\nIf posting reports an error, refresh the discussion before trying again. A\\ncomment may have been saved even when its mention notification could not be\\ndelivered. If it appears in the discussion, do not post it a second time.\\n","fieldRefs":[]},"surfaces":[{"kind":"playground","export":"@happyvertical/smrt-comments/svelte#RecordCommentsPlayground","label":"Record discussion preview"}],"runtime":"both","demoSeed":{"export":"@happyvertical/smrt-comments/svelte#recordCommentsDemo"},"demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}}],"smrtDependencies":["@happyvertical/smrt-core","@happyvertical/smrt-messages","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624"],"via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
|
|
5
5
|
//#endregion
|
|
6
6
|
//#region src/models/Comment.ts
|
|
7
7
|
var __defProp = Object.defineProperty;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["row"],"sources":["../src/__smrt-register__.ts","../src/models/Comment.ts","../src/collections/CommentCollection.ts","../src/recipes.ts","../src/services/CommentService.ts","../src/services/mentionNotifications.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-comments\\\",\\\"packageVersion\\\":\\\"0.56.0\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-comments:CommentCollection\\\":{\\\"name\\\":\\\"commentcollection\\\",\\\"className\\\":\\\"CommentCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-comments:CommentCollection\\\",\\\"collection\\\":\\\"comments\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/comments/src/collections/CommentCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-comments\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"listForRecord\\\":{\\\"name\\\":\\\"listForRecord\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"recordType\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"recordId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Comment[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"record_comments\\\",\\\"api\\\":false,\\\"mcp\\\":false,\\\"cli\\\":false},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Comment\\\",\\\"exportName\\\":\\\"CommentCollection\\\",\\\"collectionExportName\\\":\\\"CommentCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"record_comments\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"record_comments\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"meta_type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"meta_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"role\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"sort_order\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"author_user_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"body\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"mentions\\\\\\\" TEXT,\\\\n \\\\\\\"idempotency_key\\\\\\\" TEXT,\\\\n \\\\\\\"retry_tenant_id\\\\\\\" TEXT,\\\\n \\\\\\\"request_digest\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"meta_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"meta_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"role\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"sort_order\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"author_user_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"body\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"mentions\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"idempotency_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"retry_tenant_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"request_digest\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"record_comments_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_tenant_request_key\\\",\\\"columns\\\":[\\\"retry_tenant_id\\\",\\\"idempotency_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_record_created_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"meta_type\\\",\\\"meta_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"record_comments_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"record_comments_meta_type_meta_id_idx\\\",\\\"columns\\\":[\\\"meta_type\\\",\\\"meta_id\\\"]},{\\\"name\\\":\\\"record_comments_author_user_id_idx\\\",\\\"columns\\\":[\\\"author_user_id\\\"]}],\\\"version\\\":\\\"5095dfc9\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-comments\\\"},\\\"@happyvertical/smrt-comments:Comment\\\":{\\\"name\\\":\\\"comment\\\",\\\"className\\\":\\\"Comment\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-comments:Comment\\\",\\\"collection\\\":\\\"comments\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/comments/src/models/Comment.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-comments\\\",\\\"fields\\\":{\\\"metaType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"metaId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"role\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"sortOrder\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":true,\\\"autoPopulate\\\":true,\\\"nullable\\\":false,\\\"mode\\\":\\\"required\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"authorUserId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":true,\\\"related\\\":\\\"@happyvertical/smrt-users:User\\\"},\\\"body\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"mentions\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"idempotencyKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"retryTenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requestDigest\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true}},\\\"methods\\\":{\\\"hydrate\\\":{\\\"name\\\":\\\"hydrate\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<T | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"record_comments\\\",\\\"api\\\":false,\\\"mcp\\\":false,\\\"cli\\\":false,\\\"indexes\\\":[{\\\"name\\\":\\\"record_comments_tenant_request_key\\\",\\\"columns\\\":[\\\"retryTenantId\\\",\\\"idempotencyKey\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_record_created_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"metaType\\\",\\\"metaId\\\",\\\"createdAt\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"required\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtPolymorphicAssociation\\\",\\\"exportName\\\":\\\"Comment\\\",\\\"collectionExportName\\\":\\\"CommentCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"metaType\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"metaId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"role\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"authorUserId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"crossPackageRef\\\"},{\\\"field\\\":\\\"body\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"record_comments\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"record_comments\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"meta_type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"meta_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"role\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"sort_order\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"author_user_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"body\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"mentions\\\\\\\" TEXT,\\\\n \\\\\\\"idempotency_key\\\\\\\" TEXT,\\\\n \\\\\\\"retry_tenant_id\\\\\\\" TEXT,\\\\n \\\\\\\"request_digest\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"meta_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"meta_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"role\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"sort_order\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"author_user_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"body\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"mentions\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"idempotency_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"retry_tenant_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"request_digest\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"record_comments_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_tenant_request_key\\\",\\\"columns\\\":[\\\"retry_tenant_id\\\",\\\"idempotency_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_record_created_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"meta_type\\\",\\\"meta_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"record_comments_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"record_comments_meta_type_meta_id_idx\\\",\\\"columns\\\":[\\\"meta_type\\\",\\\"meta_id\\\"]},{\\\"name\\\":\\\"record_comments_author_user_id_idx\\\",\\\"columns\\\":[\\\"author_user_id\\\"]}],\\\"version\\\":\\\"5095dfc9\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-comments\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"recipes\\\":[{\\\"id\\\":\\\"comments.records\\\",\\\"className\\\":\\\"RecordCommentsRecipe\\\",\\\"label\\\":\\\"Record comments\\\",\\\"summary\\\":\\\"Discuss work directly on the records it concerns.\\\",\\\"synonyms\\\":[\\\"comments\\\",\\\"mentions\\\",\\\"discussion\\\"],\\\"models\\\":[\\\"@happyvertical/smrt-comments:Comment\\\"],\\\"nav\\\":[],\\\"requires\\\":[],\\\"group\\\":{\\\"id\\\":\\\"comments\\\",\\\"label\\\":\\\"Comments\\\",\\\"summary\\\":\\\"Keep discussions alongside the records your team works on.\\\"},\\\"help\\\":{\\\"markdown\\\":\\\"## Overview\\\\n\\\\nRecord comments keep a discussion next to the work it concerns. Open a record\\\\nyou can access to read its discussion or add a comment. Comments are part of\\\\nthe record page, rather than a separate list of every discussion.\\\\n\\\\n## Tasks\\\\n\\\\n### Add a comment\\\\n\\\\nOpen the record, find Comments, write your message and choose Post comment.\\\\nYour app controls who can read the record and who can contribute to its discussion.\\\\n\\\\n### Mention someone\\\\n\\\\nIf your app provides mention selection, choose a teammate who can access the\\\\nrecord. When mention notifications are connected, that person receives a\\\\nnotification. Typing a name alone does not select a recipient.\\\\n\\\\n### Check a failed post\\\\n\\\\nIf posting reports an error, refresh the discussion before trying again. A\\\\ncomment may have been saved even when its mention notification could not be\\\\ndelivered. If it appears in the discussion, do not post it a second time.\\\\n\\\",\\\"fieldRefs\\\":[]},\\\"surfaces\\\":[{\\\"kind\\\":\\\"playground\\\",\\\"export\\\":\\\"@happyvertical/smrt-comments/svelte#RecordCommentsPlayground\\\",\\\"label\\\":\\\"Record discussion preview\\\"}],\\\"runtime\\\":\\\"both\\\",\\\"demoSeed\\\":{\\\"export\\\":\\\"@happyvertical/smrt-comments/svelte#recordCommentsDemo\\\"},\\\"demo\\\":{\\\"mode\\\":\\\"server\\\",\\\"reasons\\\":[\\\"Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624).\\\"]}}],\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-messages\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\"],\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","import {\n crossPackageRef,\n field,\n SmrtPolymorphicAssociation,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { CommentOptions } from '../types.js';\n\nconst MAX_MENTIONS = 50;\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'record_comments',\n api: false,\n mcp: false,\n cli: false,\n indexes: [\n {\n name: 'record_comments_tenant_request_key',\n columns: ['retryTenantId', 'idempotencyKey'],\n unique: true,\n },\n {\n name: 'record_comments_record_created_idx',\n columns: ['tenantId', 'metaType', 'metaId', 'createdAt'],\n },\n ],\n})\nexport class Comment extends SmrtPolymorphicAssociation { static __smrtPackage__ = \"@happyvertical/smrt-comments\";\n @tenantId()\n tenantId = '';\n\n @crossPackageRef('@happyvertical/smrt-users:User', { required: true })\n authorUserId = '';\n\n @field({ required: true })\n body = '';\n\n /** JSON array of referenced User UUIDs; use mentionUserIds for validation. */\n mentions = '[]';\n\n /** Service-owned binding retained after generic runOnce claim retention. */\n @field({ type: 'text', nullable: true, readonly: true })\n idempotencyKey: string | null = null;\n\n /** Canonical retry namespace; never rewrites stored tenant/user references. */\n @field({ type: 'text', nullable: true, readonly: true })\n retryTenantId: string | null = null;\n\n /** Digest of the original authenticated author, parent and normalized payload. */\n @field({ type: 'text', nullable: true, readonly: true })\n requestDigest: string | null = null;\n\n constructor(options: CommentOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.authorUserId !== undefined)\n this.authorUserId = options.authorUserId;\n if (options.body !== undefined) this.body = options.body;\n if (options.idempotencyKey !== undefined)\n this.idempotencyKey = options.idempotencyKey;\n if (options.retryTenantId !== undefined)\n this.retryTenantId = options.retryTenantId;\n if (options.requestDigest !== undefined)\n this.requestDigest = options.requestDigest;\n const mentions = options.mentions as unknown;\n if (Array.isArray(mentions)) this.mentionUserIds = mentions;\n else if (typeof mentions === 'string') this.mentions = mentions;\n }\n\n get mentionUserIds(): string[] {\n try {\n const parsed: unknown = JSON.parse(this.mentions);\n return Array.isArray(parsed) &&\n parsed.every((value) => typeof value === 'string')\n ? parsed\n : [];\n } catch {\n return [];\n }\n }\n\n set mentionUserIds(value: readonly string[]) {\n const unique = [...new Set(value.map((id) => id.trim()).filter(Boolean))];\n if (unique.length > MAX_MENTIONS || unique.some((id) => !UUID.test(id))) {\n throw new TypeError(\n 'Comment mentions must contain at most 50 user UUIDs.',\n );\n }\n this.mentions = JSON.stringify(unique);\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport {\n getCurrentTenant,\n TenantIsolationError,\n} from '@happyvertical/smrt-tenancy';\nimport { Comment } from '../models/Comment.js';\n\nexport class CommentCollection extends SmrtCollection<Comment> {\n static readonly _itemClass = Comment;\n\n async listForRecord(\n recordType: string,\n recordId: string,\n ): Promise<Comment[]> {\n const tenantId = getCurrentTenant()?.tenantId;\n if (!tenantId) {\n throw new TenantIsolationError(\n 'Record comments require a tenant context.',\n );\n }\n return this.list({\n where: { tenantId, metaType: recordType, metaId: recordId },\n orderBy: ['createdAt ASC'],\n });\n }\n}\n","import { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Comment } from './models/Comment.js';\n\n/** Discussion attached to any authorized business record. */\nexport class RecordCommentsRecipe extends SmrtRecipe {\n static id = 'comments.records';\n static label = 'Record comments';\n static summary = 'Discuss work directly on the records it concerns.';\n static synonyms = ['comments', 'mentions', 'discussion'];\n static group = {\n id: 'comments',\n label: 'Comments',\n summary: 'Keep discussions alongside the records your team works on.',\n };\n static models = [Comment];\n // Record discussions need an authorized parent record, not a global list.\n static nav = [];\n static runtime = 'both' as const;\n static surfaces = [\n {\n kind: 'playground',\n export: '@happyvertical/smrt-comments/svelte#RecordCommentsPlayground',\n label: 'Record discussion preview',\n },\n ] as const;\n static demoSeed = {\n export: '@happyvertical/smrt-comments/svelte#recordCommentsDemo',\n } as const;\n static help = './comments.records.recipe.md';\n}\n","import {\n digestRunOnceContent,\n runOnce,\n type SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport { CommentCollection } from '../collections/CommentCollection.js';\nimport { Comment } from '../models/Comment.js';\nimport type {\n CommentActorContext,\n CommentMentionNotificationAdapter,\n CommentRecordAccess,\n CreateCommentInput,\n} from '../types.js';\n\n// Native UUID columns canonicalize case; identity and digests must agree with them.\nconst canonicalUuid = (value: string) =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)\n ? value.toLowerCase()\n : value;\n\n/** A reused request differs, or its retained comment is no longer available. */\nexport class CommentIdempotencyError extends Error {\n constructor(\n readonly code: 'COMMENT_REQUEST_CONFLICT' | 'COMMENT_REQUEST_UNAVAILABLE',\n ) {\n super(\n code === 'COMMENT_REQUEST_CONFLICT'\n ? 'Comment request key already used with different content.'\n : 'Comment request no longer has an unchanged comment.',\n );\n this.name = 'CommentIdempotencyError';\n }\n}\n\nexport class CommentService {\n constructor(\n private readonly options: {\n db: SmrtClassOptions['db'];\n actor: CommentActorContext;\n authorizeRecord: (access: CommentRecordAccess) => Promise<boolean>;\n mentionNotifications?: CommentMentionNotificationAdapter;\n },\n ) {}\n\n private async authorize(\n recordType: string,\n recordId: string,\n action: 'read' | 'comment',\n ) {\n const { actor } = this.options;\n if (\n !actor.tenantId ||\n !actor.userId ||\n !recordType ||\n !recordId ||\n !(await this.options.authorizeRecord({\n ...actor,\n recordType,\n recordId,\n action,\n }))\n ) {\n throw new Error('Comment record access denied.');\n }\n }\n\n async listForRecord(\n recordType: string,\n recordId: string,\n ): Promise<Comment[]> {\n await this.authorize(recordType, recordId, 'read');\n const tenantId = this.options.actor.tenantId;\n const binding = canonicalUuid(tenantId);\n const rows = await withTenant({ tenantId }, async () =>\n (await CommentCollection.create({ db: this.options.db })).listForRecord(\n recordType,\n recordId,\n ),\n );\n const collection = await withTenant({ tenantId }, () =>\n CommentCollection.create({ db: this.options.db }),\n );\n // The canonical retry namespace is separate from legacy reference spelling.\n // This query is tenant/parent-bound before any scoped hydration.\n const bound = await collection.db.query(\n `SELECT CAST(id AS TEXT) AS id, CAST(tenant_id AS TEXT) AS tenant_id FROM \"${collection.tableName.replace(/\"/g, '\"\"')}\" WHERE retry_tenant_id = ? AND meta_type = ? AND meta_id = ? AND idempotency_key IS NOT NULL`,\n binding,\n recordType,\n recordId,\n );\n for (const stored of bound.rows) {\n const row = await this.loadBoundComment(collection.db, stored, binding);\n if (row.metaType !== recordType || row.metaId !== recordId) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n rows.push(row);\n }\n for (const row of rows) {\n if (row.idempotencyKey !== null && row.retryTenantId !== binding) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n }\n return [...new Map(rows.map((row) => [row.id, row])).values()].sort(\n (a, b) =>\n (a.created_at?.getTime() ?? 0) - (b.created_at?.getTime() ?? 0) ||\n (a.id ?? '').localeCompare(b.id ?? ''),\n );\n }\n\n private async loadBoundComment(\n db: CommentCollection['db'],\n stored: { [key: string]: unknown },\n binding: string,\n ): Promise<Comment> {\n const id = stored.id;\n const tenantId = stored.tenant_id;\n if (\n typeof id !== 'string' ||\n typeof tenantId !== 'string' ||\n canonicalUuid(tenantId) !== binding\n ) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n // This is the original spelling of the same authorized tenant, not a bypass.\n const row = await withTenant({ tenantId }, async () =>\n (await CommentCollection.create({ db })).get(id),\n );\n if (\n !row ||\n canonicalUuid(row.tenantId) !== binding ||\n row.retryTenantId !== binding ||\n row.idempotencyKey === null\n ) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n return row;\n }\n\n async create(commentOptions: CreateCommentInput): Promise<Comment> {\n const {\n tenantId: inputTenantId,\n authorUserId: inputAuthorUserId,\n metaType,\n metaId,\n body,\n mentions,\n idempotencyKey,\n } = commentOptions;\n if (!inputTenantId || !inputAuthorUserId) {\n throw new TypeError('Comments require a tenant and author.');\n }\n if (\n canonicalUuid(inputTenantId) !==\n canonicalUuid(this.options.actor.tenantId) ||\n canonicalUuid(inputAuthorUserId) !==\n canonicalUuid(this.options.actor.userId)\n ) {\n throw new Error('Comment actor context mismatch.');\n }\n // Preserve the trusted context's stored spelling on text-backed databases.\n const tenantId = this.options.actor.tenantId;\n const authorUserId = this.options.actor.userId;\n await this.authorize(metaType ?? '', metaId ?? '', 'comment');\n if (!body?.trim()) throw new TypeError('Comment body is required.');\n // Validate through the model's public setter before collection.create()\n // persists. Supply its normalized JSON in that single insert.\n const prepared = new Comment();\n if (mentions !== undefined) prepared.mentionUserIds = mentions;\n if (\n idempotencyKey !== undefined &&\n (typeof idempotencyKey !== 'string' ||\n !idempotencyKey.trim() ||\n idempotencyKey !== idempotencyKey.trim() ||\n idempotencyKey.length > 200)\n ) {\n throw new TypeError(\n 'Comment idempotencyKey must be a nonempty trimmed string of at most 200 characters.',\n );\n }\n const normalizedMentions = [...prepared.mentionUserIds].sort();\n const requestDigest = digestRunOnceContent({\n tenantId: canonicalUuid(tenantId),\n authorUserId: canonicalUuid(authorUserId),\n metaType,\n metaId,\n body,\n mentions: normalizedMentions,\n });\n const comment = await withTenant({ tenantId }, async () => {\n const collection = await CommentCollection.create({\n db: this.options.db,\n });\n const insert = async (target: CommentCollection) => {\n const id = crypto.randomUUID();\n return target.create({\n tenantId,\n authorUserId,\n metaType,\n metaId,\n body,\n id,\n slug: id,\n context: '',\n _insertOnly: true,\n mentions: prepared.mentions,\n idempotencyKey: idempotencyKey ?? null,\n requestDigest: idempotencyKey === undefined ? null : requestDigest,\n retryTenantId:\n idempotencyKey === undefined ? null : canonicalUuid(tenantId),\n });\n };\n if (idempotencyKey === undefined) return insert(collection);\n // The internal actor is an arbitration namespace, NOT the authenticated\n // author. All authors sharing a tenant/key must contend on the same claim.\n // Actual author and payload are bound by the independently checked digest.\n const receipt = await runOnce(\n {\n db: collection.db,\n tenantId: canonicalUuid(tenantId),\n actor: 'smrt-comments.create:v1',\n token: idempotencyKey,\n content: 'comment-request-binding:v1',\n },\n async (tx) => {\n const scoped = await CommentCollection.create({ db: tx });\n const matches = await tx.query(\n `SELECT CAST(id AS TEXT) AS id, CAST(tenant_id AS TEXT) AS tenant_id FROM \"${scoped.tableName.replace(/\"/g, '\"\"')}\" WHERE retry_tenant_id = ? AND idempotency_key = ?`,\n canonicalUuid(tenantId),\n idempotencyKey,\n );\n if (matches.rows.length > 1) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n const row = matches.rows[0]\n ? await this.loadBoundComment(\n tx,\n matches.rows[0],\n canonicalUuid(tenantId),\n )\n : await insert(scoped);\n return {\n id: row.id,\n digest: row.requestDigest,\n tenant_id: row.tenantId,\n };\n },\n );\n if (receipt.digest !== requestDigest)\n throw new CommentIdempotencyError('COMMENT_REQUEST_CONFLICT');\n const row = await this.loadBoundComment(\n collection.db,\n receipt,\n canonicalUuid(tenantId),\n );\n if (\n !row ||\n canonicalUuid(row.tenantId) !== canonicalUuid(tenantId) ||\n row.idempotencyKey !== idempotencyKey ||\n row.requestDigest !== requestDigest ||\n digestRunOnceContent({\n tenantId: canonicalUuid(row.tenantId),\n authorUserId: canonicalUuid(row.authorUserId),\n metaType: row.metaType,\n metaId: row.metaId,\n body: row.body,\n mentions: [...row.mentionUserIds].sort(),\n }) !== requestDigest\n ) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n return row;\n });\n if (!this.options.mentionNotifications || !comment.id) return comment;\n for (const recipientUserId of comment.mentionUserIds) {\n if (\n canonicalUuid(recipientUserId) === canonicalUuid(comment.authorUserId)\n )\n continue;\n await this.options.mentionNotifications.notifyMention({\n commentId: comment.id,\n tenantId: comment.tenantId,\n authorUserId: comment.authorUserId,\n recipientUserId,\n recordType: comment.metaType,\n recordId: comment.metaId,\n body: comment.body,\n });\n }\n return comment;\n }\n}\n","import type {\n CommentMention,\n CommentMentionNotificationAdapter,\n} from '../types.js';\n\n/** Structural subset implemented by smrt-messages UserNotificationService. */\nexport interface CommentNotificationService {\n notify(input: {\n tenantId: string;\n recipientUserId: string;\n kind: string;\n title: string;\n body: string;\n sourceRef: string;\n }): Promise<unknown>;\n}\n\n/** Hosts must check recipient membership AND access to the referenced record. */\nexport function createCommentMentionNotifications(options: {\n notifications: CommentNotificationService;\n canNotify: (mention: CommentMention) => Promise<boolean>;\n}): CommentMentionNotificationAdapter {\n return {\n async notifyMention(mention) {\n if (!(await options.canNotify(mention))) return;\n await options.notifications.notify({\n tenantId: mention.tenantId,\n recipientUserId: mention.recipientUserId,\n kind: 'comments.mention',\n title: 'You were mentioned in a comment',\n body: mention.body,\n sourceRef: `comments.mention:${mention.commentId}`,\n });\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["row"],"sources":["../src/__smrt-register__.ts","../src/models/Comment.ts","../src/collections/CommentCollection.ts","../src/recipes.ts","../src/services/CommentService.ts","../src/services/mentionNotifications.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-comments\\\",\\\"packageVersion\\\":\\\"0.56.1\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-comments:CommentCollection\\\":{\\\"name\\\":\\\"commentcollection\\\",\\\"className\\\":\\\"CommentCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-comments:CommentCollection\\\",\\\"collection\\\":\\\"comments\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/comments/src/collections/CommentCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-comments\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"listForRecord\\\":{\\\"name\\\":\\\"listForRecord\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"recordType\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"recordId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Comment[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"record_comments\\\",\\\"api\\\":false,\\\"mcp\\\":false,\\\"cli\\\":false},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Comment\\\",\\\"exportName\\\":\\\"CommentCollection\\\",\\\"collectionExportName\\\":\\\"CommentCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"record_comments\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"record_comments\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"meta_type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"meta_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"role\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"sort_order\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"author_user_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"body\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"mentions\\\\\\\" TEXT,\\\\n \\\\\\\"idempotency_key\\\\\\\" TEXT,\\\\n \\\\\\\"retry_tenant_id\\\\\\\" TEXT,\\\\n \\\\\\\"request_digest\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"meta_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"meta_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"role\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"sort_order\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"author_user_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"body\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"mentions\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"idempotency_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"retry_tenant_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"request_digest\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"record_comments_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_tenant_request_key\\\",\\\"columns\\\":[\\\"retry_tenant_id\\\",\\\"idempotency_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_record_created_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"meta_type\\\",\\\"meta_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"record_comments_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"record_comments_meta_type_meta_id_idx\\\",\\\"columns\\\":[\\\"meta_type\\\",\\\"meta_id\\\"]},{\\\"name\\\":\\\"record_comments_author_user_id_idx\\\",\\\"columns\\\":[\\\"author_user_id\\\"]}],\\\"version\\\":\\\"5095dfc9\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-comments\\\"},\\\"@happyvertical/smrt-comments:Comment\\\":{\\\"name\\\":\\\"comment\\\",\\\"className\\\":\\\"Comment\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-comments:Comment\\\",\\\"collection\\\":\\\"comments\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/comments/src/models/Comment.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-comments\\\",\\\"fields\\\":{\\\"metaType\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"metaId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"role\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"sortOrder\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":true,\\\"autoPopulate\\\":true,\\\"nullable\\\":false,\\\"mode\\\":\\\"required\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"authorUserId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":true,\\\"related\\\":\\\"@happyvertical/smrt-users:User\\\"},\\\"body\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"mentions\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"idempotencyKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"retryTenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true},\\\"requestDigest\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true,\\\"readonly\\\":true},\\\"readonly\\\":true}},\\\"methods\\\":{\\\"hydrate\\\":{\\\"name\\\":\\\"hydrate\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<T | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"record_comments\\\",\\\"api\\\":false,\\\"mcp\\\":false,\\\"cli\\\":false,\\\"indexes\\\":[{\\\"name\\\":\\\"record_comments_tenant_request_key\\\",\\\"columns\\\":[\\\"retryTenantId\\\",\\\"idempotencyKey\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_record_created_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"metaType\\\",\\\"metaId\\\",\\\"createdAt\\\"]}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"required\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtPolymorphicAssociation\\\",\\\"exportName\\\":\\\"Comment\\\",\\\"collectionExportName\\\":\\\"CommentCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"metaType\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"metaId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"role\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"authorUserId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"crossPackageRef\\\"},{\\\"field\\\":\\\"body\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"record_comments\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"record_comments\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"meta_type\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"meta_id\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"role\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"sort_order\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"author_user_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"body\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"mentions\\\\\\\" TEXT,\\\\n \\\\\\\"idempotency_key\\\\\\\" TEXT,\\\\n \\\\\\\"retry_tenant_id\\\\\\\" TEXT,\\\\n \\\\\\\"request_digest\\\\\\\" TEXT\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"meta_type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"meta_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"role\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"sort_order\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"author_user_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"body\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"mentions\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"idempotency_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"retry_tenant_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"request_digest\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false}},\\\"indexes\\\":[{\\\"name\\\":\\\"record_comments_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_tenant_request_key\\\",\\\"columns\\\":[\\\"retry_tenant_id\\\",\\\"idempotency_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"record_comments_record_created_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"meta_type\\\",\\\"meta_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"record_comments_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"record_comments_meta_type_meta_id_idx\\\",\\\"columns\\\":[\\\"meta_type\\\",\\\"meta_id\\\"]},{\\\"name\\\":\\\"record_comments_author_user_id_idx\\\",\\\"columns\\\":[\\\"author_user_id\\\"]}],\\\"version\\\":\\\"5095dfc9\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-comments\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"recipes\\\":[{\\\"id\\\":\\\"comments.records\\\",\\\"className\\\":\\\"RecordCommentsRecipe\\\",\\\"label\\\":\\\"Record comments\\\",\\\"summary\\\":\\\"Discuss work directly on the records it concerns.\\\",\\\"synonyms\\\":[\\\"comments\\\",\\\"mentions\\\",\\\"discussion\\\"],\\\"models\\\":[\\\"@happyvertical/smrt-comments:Comment\\\"],\\\"nav\\\":[],\\\"requires\\\":[],\\\"group\\\":{\\\"id\\\":\\\"comments\\\",\\\"label\\\":\\\"Comments\\\",\\\"summary\\\":\\\"Keep discussions alongside the records your team works on.\\\"},\\\"help\\\":{\\\"markdown\\\":\\\"## Overview\\\\n\\\\nRecord comments keep a discussion next to the work it concerns. Open a record\\\\nyou can access to read its discussion or add a comment. Comments are part of\\\\nthe record page, rather than a separate list of every discussion.\\\\n\\\\n## Tasks\\\\n\\\\n### Add a comment\\\\n\\\\nOpen the record, find Comments, write your message and choose Post comment.\\\\nYour app controls who can read the record and who can contribute to its discussion.\\\\n\\\\n### Mention someone\\\\n\\\\nIf your app provides mention selection, choose a teammate who can access the\\\\nrecord. When mention notifications are connected, that person receives a\\\\nnotification. Typing a name alone does not select a recipient.\\\\n\\\\n### Check a failed post\\\\n\\\\nIf posting reports an error, refresh the discussion before trying again. A\\\\ncomment may have been saved even when its mention notification could not be\\\\ndelivered. If it appears in the discussion, do not post it a second time.\\\\n\\\",\\\"fieldRefs\\\":[]},\\\"surfaces\\\":[{\\\"kind\\\":\\\"playground\\\",\\\"export\\\":\\\"@happyvertical/smrt-comments/svelte#RecordCommentsPlayground\\\",\\\"label\\\":\\\"Record discussion preview\\\"}],\\\"runtime\\\":\\\"both\\\",\\\"demoSeed\\\":{\\\"export\\\":\\\"@happyvertical/smrt-comments/svelte#recordCommentsDemo\\\"},\\\"demo\\\":{\\\"mode\\\":\\\"server\\\",\\\"reasons\\\":[\\\"Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624).\\\"]}}],\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-messages\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\"],\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","import {\n crossPackageRef,\n field,\n SmrtPolymorphicAssociation,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { CommentOptions } from '../types.js';\n\nconst MAX_MENTIONS = 50;\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'record_comments',\n api: false,\n mcp: false,\n cli: false,\n indexes: [\n {\n name: 'record_comments_tenant_request_key',\n columns: ['retryTenantId', 'idempotencyKey'],\n unique: true,\n },\n {\n name: 'record_comments_record_created_idx',\n columns: ['tenantId', 'metaType', 'metaId', 'createdAt'],\n },\n ],\n})\nexport class Comment extends SmrtPolymorphicAssociation { static __smrtPackage__ = \"@happyvertical/smrt-comments\";\n @tenantId()\n tenantId = '';\n\n @crossPackageRef('@happyvertical/smrt-users:User', { required: true })\n authorUserId = '';\n\n @field({ required: true })\n body = '';\n\n /** JSON array of referenced User UUIDs; use mentionUserIds for validation. */\n mentions = '[]';\n\n /** Service-owned binding retained after generic runOnce claim retention. */\n @field({ type: 'text', nullable: true, readonly: true })\n idempotencyKey: string | null = null;\n\n /** Canonical retry namespace; never rewrites stored tenant/user references. */\n @field({ type: 'text', nullable: true, readonly: true })\n retryTenantId: string | null = null;\n\n /** Digest of the original authenticated author, parent and normalized payload. */\n @field({ type: 'text', nullable: true, readonly: true })\n requestDigest: string | null = null;\n\n constructor(options: CommentOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.authorUserId !== undefined)\n this.authorUserId = options.authorUserId;\n if (options.body !== undefined) this.body = options.body;\n if (options.idempotencyKey !== undefined)\n this.idempotencyKey = options.idempotencyKey;\n if (options.retryTenantId !== undefined)\n this.retryTenantId = options.retryTenantId;\n if (options.requestDigest !== undefined)\n this.requestDigest = options.requestDigest;\n const mentions = options.mentions as unknown;\n if (Array.isArray(mentions)) this.mentionUserIds = mentions;\n else if (typeof mentions === 'string') this.mentions = mentions;\n }\n\n get mentionUserIds(): string[] {\n try {\n const parsed: unknown = JSON.parse(this.mentions);\n return Array.isArray(parsed) &&\n parsed.every((value) => typeof value === 'string')\n ? parsed\n : [];\n } catch {\n return [];\n }\n }\n\n set mentionUserIds(value: readonly string[]) {\n const unique = [...new Set(value.map((id) => id.trim()).filter(Boolean))];\n if (unique.length > MAX_MENTIONS || unique.some((id) => !UUID.test(id))) {\n throw new TypeError(\n 'Comment mentions must contain at most 50 user UUIDs.',\n );\n }\n this.mentions = JSON.stringify(unique);\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport {\n getCurrentTenant,\n TenantIsolationError,\n} from '@happyvertical/smrt-tenancy';\nimport { Comment } from '../models/Comment.js';\n\nexport class CommentCollection extends SmrtCollection<Comment> {\n static readonly _itemClass = Comment;\n\n async listForRecord(\n recordType: string,\n recordId: string,\n ): Promise<Comment[]> {\n const tenantId = getCurrentTenant()?.tenantId;\n if (!tenantId) {\n throw new TenantIsolationError(\n 'Record comments require a tenant context.',\n );\n }\n return this.list({\n where: { tenantId, metaType: recordType, metaId: recordId },\n orderBy: ['createdAt ASC'],\n });\n }\n}\n","import { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Comment } from './models/Comment.js';\n\n/** Discussion attached to any authorized business record. */\nexport class RecordCommentsRecipe extends SmrtRecipe {\n static id = 'comments.records';\n static label = 'Record comments';\n static summary = 'Discuss work directly on the records it concerns.';\n static synonyms = ['comments', 'mentions', 'discussion'];\n static group = {\n id: 'comments',\n label: 'Comments',\n summary: 'Keep discussions alongside the records your team works on.',\n };\n static models = [Comment];\n // Record discussions need an authorized parent record, not a global list.\n static nav = [];\n static runtime = 'both' as const;\n static surfaces = [\n {\n kind: 'playground',\n export: '@happyvertical/smrt-comments/svelte#RecordCommentsPlayground',\n label: 'Record discussion preview',\n },\n ] as const;\n static demoSeed = {\n export: '@happyvertical/smrt-comments/svelte#recordCommentsDemo',\n } as const;\n static help = './comments.records.recipe.md';\n}\n","import {\n digestRunOnceContent,\n runOnce,\n type SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport { withTenant } from '@happyvertical/smrt-tenancy';\nimport { CommentCollection } from '../collections/CommentCollection.js';\nimport { Comment } from '../models/Comment.js';\nimport type {\n CommentActorContext,\n CommentMentionNotificationAdapter,\n CommentRecordAccess,\n CreateCommentInput,\n} from '../types.js';\n\n// Native UUID columns canonicalize case; identity and digests must agree with them.\nconst canonicalUuid = (value: string) =>\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)\n ? value.toLowerCase()\n : value;\n\n/** A reused request differs, or its retained comment is no longer available. */\nexport class CommentIdempotencyError extends Error {\n constructor(\n readonly code: 'COMMENT_REQUEST_CONFLICT' | 'COMMENT_REQUEST_UNAVAILABLE',\n ) {\n super(\n code === 'COMMENT_REQUEST_CONFLICT'\n ? 'Comment request key already used with different content.'\n : 'Comment request no longer has an unchanged comment.',\n );\n this.name = 'CommentIdempotencyError';\n }\n}\n\nexport class CommentService {\n constructor(\n private readonly options: {\n db: SmrtClassOptions['db'];\n actor: CommentActorContext;\n authorizeRecord: (access: CommentRecordAccess) => Promise<boolean>;\n mentionNotifications?: CommentMentionNotificationAdapter;\n },\n ) {}\n\n private async authorize(\n recordType: string,\n recordId: string,\n action: 'read' | 'comment',\n ) {\n const { actor } = this.options;\n if (\n !actor.tenantId ||\n !actor.userId ||\n !recordType ||\n !recordId ||\n !(await this.options.authorizeRecord({\n ...actor,\n recordType,\n recordId,\n action,\n }))\n ) {\n throw new Error('Comment record access denied.');\n }\n }\n\n async listForRecord(\n recordType: string,\n recordId: string,\n ): Promise<Comment[]> {\n await this.authorize(recordType, recordId, 'read');\n const tenantId = this.options.actor.tenantId;\n const binding = canonicalUuid(tenantId);\n const rows = await withTenant({ tenantId }, async () =>\n (await CommentCollection.create({ db: this.options.db })).listForRecord(\n recordType,\n recordId,\n ),\n );\n const collection = await withTenant({ tenantId }, () =>\n CommentCollection.create({ db: this.options.db }),\n );\n // The canonical retry namespace is separate from legacy reference spelling.\n // This query is tenant/parent-bound before any scoped hydration.\n const bound = await collection.db.query(\n `SELECT CAST(id AS TEXT) AS id, CAST(tenant_id AS TEXT) AS tenant_id FROM \"${collection.tableName.replace(/\"/g, '\"\"')}\" WHERE retry_tenant_id = ? AND meta_type = ? AND meta_id = ? AND idempotency_key IS NOT NULL`,\n binding,\n recordType,\n recordId,\n );\n for (const stored of bound.rows) {\n const row = await this.loadBoundComment(collection.db, stored, binding);\n if (row.metaType !== recordType || row.metaId !== recordId) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n rows.push(row);\n }\n for (const row of rows) {\n if (row.idempotencyKey !== null && row.retryTenantId !== binding) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n }\n return [...new Map(rows.map((row) => [row.id, row])).values()].sort(\n (a, b) =>\n (a.created_at?.getTime() ?? 0) - (b.created_at?.getTime() ?? 0) ||\n (a.id ?? '').localeCompare(b.id ?? ''),\n );\n }\n\n private async loadBoundComment(\n db: CommentCollection['db'],\n stored: { [key: string]: unknown },\n binding: string,\n ): Promise<Comment> {\n const id = stored.id;\n const tenantId = stored.tenant_id;\n if (\n typeof id !== 'string' ||\n typeof tenantId !== 'string' ||\n canonicalUuid(tenantId) !== binding\n ) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n // This is the original spelling of the same authorized tenant, not a bypass.\n const row = await withTenant({ tenantId }, async () =>\n (await CommentCollection.create({ db })).get(id),\n );\n if (\n !row ||\n canonicalUuid(row.tenantId) !== binding ||\n row.retryTenantId !== binding ||\n row.idempotencyKey === null\n ) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n return row;\n }\n\n async create(commentOptions: CreateCommentInput): Promise<Comment> {\n const {\n tenantId: inputTenantId,\n authorUserId: inputAuthorUserId,\n metaType,\n metaId,\n body,\n mentions,\n idempotencyKey,\n } = commentOptions;\n if (!inputTenantId || !inputAuthorUserId) {\n throw new TypeError('Comments require a tenant and author.');\n }\n if (\n canonicalUuid(inputTenantId) !==\n canonicalUuid(this.options.actor.tenantId) ||\n canonicalUuid(inputAuthorUserId) !==\n canonicalUuid(this.options.actor.userId)\n ) {\n throw new Error('Comment actor context mismatch.');\n }\n // Preserve the trusted context's stored spelling on text-backed databases.\n const tenantId = this.options.actor.tenantId;\n const authorUserId = this.options.actor.userId;\n await this.authorize(metaType ?? '', metaId ?? '', 'comment');\n if (!body?.trim()) throw new TypeError('Comment body is required.');\n // Validate through the model's public setter before collection.create()\n // persists. Supply its normalized JSON in that single insert.\n const prepared = new Comment();\n if (mentions !== undefined) prepared.mentionUserIds = mentions;\n if (\n idempotencyKey !== undefined &&\n (typeof idempotencyKey !== 'string' ||\n !idempotencyKey.trim() ||\n idempotencyKey !== idempotencyKey.trim() ||\n idempotencyKey.length > 200)\n ) {\n throw new TypeError(\n 'Comment idempotencyKey must be a nonempty trimmed string of at most 200 characters.',\n );\n }\n const normalizedMentions = [...prepared.mentionUserIds].sort();\n const requestDigest = digestRunOnceContent({\n tenantId: canonicalUuid(tenantId),\n authorUserId: canonicalUuid(authorUserId),\n metaType,\n metaId,\n body,\n mentions: normalizedMentions,\n });\n const comment = await withTenant({ tenantId }, async () => {\n const collection = await CommentCollection.create({\n db: this.options.db,\n });\n const insert = async (target: CommentCollection) => {\n const id = crypto.randomUUID();\n return target.create({\n tenantId,\n authorUserId,\n metaType,\n metaId,\n body,\n id,\n slug: id,\n context: '',\n _insertOnly: true,\n mentions: prepared.mentions,\n idempotencyKey: idempotencyKey ?? null,\n requestDigest: idempotencyKey === undefined ? null : requestDigest,\n retryTenantId:\n idempotencyKey === undefined ? null : canonicalUuid(tenantId),\n });\n };\n if (idempotencyKey === undefined) return insert(collection);\n // The internal actor is an arbitration namespace, NOT the authenticated\n // author. All authors sharing a tenant/key must contend on the same claim.\n // Actual author and payload are bound by the independently checked digest.\n const receipt = await runOnce(\n {\n db: collection.db,\n tenantId: canonicalUuid(tenantId),\n actor: 'smrt-comments.create:v1',\n token: idempotencyKey,\n content: 'comment-request-binding:v1',\n },\n async (tx) => {\n const scoped = await CommentCollection.create({ db: tx });\n const matches = await tx.query(\n `SELECT CAST(id AS TEXT) AS id, CAST(tenant_id AS TEXT) AS tenant_id FROM \"${scoped.tableName.replace(/\"/g, '\"\"')}\" WHERE retry_tenant_id = ? AND idempotency_key = ?`,\n canonicalUuid(tenantId),\n idempotencyKey,\n );\n if (matches.rows.length > 1) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n const row = matches.rows[0]\n ? await this.loadBoundComment(\n tx,\n matches.rows[0],\n canonicalUuid(tenantId),\n )\n : await insert(scoped);\n return {\n id: row.id,\n digest: row.requestDigest,\n tenant_id: row.tenantId,\n };\n },\n );\n if (receipt.digest !== requestDigest)\n throw new CommentIdempotencyError('COMMENT_REQUEST_CONFLICT');\n const row = await this.loadBoundComment(\n collection.db,\n receipt,\n canonicalUuid(tenantId),\n );\n if (\n !row ||\n canonicalUuid(row.tenantId) !== canonicalUuid(tenantId) ||\n row.idempotencyKey !== idempotencyKey ||\n row.requestDigest !== requestDigest ||\n digestRunOnceContent({\n tenantId: canonicalUuid(row.tenantId),\n authorUserId: canonicalUuid(row.authorUserId),\n metaType: row.metaType,\n metaId: row.metaId,\n body: row.body,\n mentions: [...row.mentionUserIds].sort(),\n }) !== requestDigest\n ) {\n throw new CommentIdempotencyError('COMMENT_REQUEST_UNAVAILABLE');\n }\n return row;\n });\n if (!this.options.mentionNotifications || !comment.id) return comment;\n for (const recipientUserId of comment.mentionUserIds) {\n if (\n canonicalUuid(recipientUserId) === canonicalUuid(comment.authorUserId)\n )\n continue;\n await this.options.mentionNotifications.notifyMention({\n commentId: comment.id,\n tenantId: comment.tenantId,\n authorUserId: comment.authorUserId,\n recipientUserId,\n recordType: comment.metaType,\n recordId: comment.metaId,\n body: comment.body,\n });\n }\n return comment;\n }\n}\n","import type {\n CommentMention,\n CommentMentionNotificationAdapter,\n} from '../types.js';\n\n/** Structural subset implemented by smrt-messages UserNotificationService. */\nexport interface CommentNotificationService {\n notify(input: {\n tenantId: string;\n recipientUserId: string;\n kind: string;\n title: string;\n body: string;\n sourceRef: string;\n }): Promise<unknown>;\n}\n\n/** Hosts must check recipient membership AND access to the referenced record. */\nexport function createCommentMentionNotifications(options: {\n notifications: CommentNotificationService;\n canNotify: (mention: CommentMention) => Promise<boolean>;\n}): CommentMentionNotificationAdapter {\n return {\n async notifyMention(mention) {\n if (!(await options.canNotify(mention))) return;\n await options.notifications.notify({\n tenantId: mention.tenantId,\n recipientUserId: mention.recipientUserId,\n kind: 'comments.mention',\n title: 'You were mentioned in a comment',\n body: mention.body,\n sourceRef: `comments.mention:${mention.commentId}`,\n });\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/manifest.json
CHANGED
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-comments",
|
|
6
|
-
"packageVersion": "0.56.
|
|
6
|
+
"packageVersion": "0.56.1",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
10
|
+
"manifest": "cb69173bb12667f5bc844a8e2cdea58279959833e083b989466bc61286b1de22",
|
|
11
|
+
"packageJson": "171d16ce547d42dfbfccc11a6d98e7ba7de7b76008b5af884f9216d3a7e91abf",
|
|
12
12
|
"agents": "3e82791ea4a860351e1be18ee8cee07902b99643bd9c53d4859e1f18683979ec",
|
|
13
13
|
"moduleDoc:agents/test-design.md": "df07180c4186d6358a841e23c806cd521f772a98582676e7f0ab73035d5cbb53",
|
|
14
14
|
"moduleDoc:agents/idempotent-create.md": "97043e654f93fe59f1c2bbc2f5f3adbfad616e2741756c69fa5ca7ff6d84250f"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-comments",
|
|
3
|
-
"version": "0.56.
|
|
3
|
+
"version": "0.56.1",
|
|
4
4
|
"description": "Record comments and mention hooks for SMRT applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"./manifest.json": "./dist/manifest.json"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@happyvertical/smrt-core": "0.56.
|
|
28
|
-
"@happyvertical/smrt-tenancy": "0.56.
|
|
27
|
+
"@happyvertical/smrt-core": "0.56.1",
|
|
28
|
+
"@happyvertical/smrt-tenancy": "0.56.1"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"svelte": "^5.57.0"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"directory": "packages/comments"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@happyvertical/smrt-vitest": "0.56.
|
|
46
|
+
"@happyvertical/smrt-vitest": "0.56.1",
|
|
47
47
|
"@sveltejs/package": "^2.5.8",
|
|
48
48
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
49
49
|
"@testing-library/svelte": "^5.4.2",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"typescript": "6.0.3",
|
|
54
54
|
"vite": "8.1.4",
|
|
55
55
|
"vitest": "4.1.10",
|
|
56
|
-
"@happyvertical/smrt-messages": "0.56.
|
|
56
|
+
"@happyvertical/smrt-messages": "0.56.1"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "vite build --mode library && svelte-package -i src/svelte -o dist/svelte --tsconfig tsconfig.svelte.json && node ../../scripts/prune-svelte-package-artifacts.js dist",
|