@happyvertical/smrt-content 0.43.9 → 0.43.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/agents/content-list.md +69 -0
  2. package/dist/chunks/content-corrections-BxfA3tW1.js +107 -0
  3. package/dist/chunks/content-corrections-BxfA3tW1.js.map +1 -0
  4. package/dist/chunks/content-query-4w62u5_0.js +4092 -0
  5. package/dist/chunks/content-query-4w62u5_0.js.map +1 -0
  6. package/dist/chunks/content-reviews-BWrYEQc6.js +124 -0
  7. package/dist/chunks/content-reviews-BWrYEQc6.js.map +1 -0
  8. package/dist/chunks/content-versions-Di3vcTgb.js +284 -0
  9. package/dist/chunks/content-versions-Di3vcTgb.js.map +1 -0
  10. package/dist/chunks/contents-BV8RoP_R.js +612 -0
  11. package/dist/chunks/contents-BV8RoP_R.js.map +1 -0
  12. package/dist/chunks/rolldown-runtime-D7D4PA-g.js +13 -0
  13. package/dist/content-chat-handlers.d.ts +1 -1
  14. package/dist/content-chat-handlers.d.ts.map +1 -1
  15. package/dist/content-governance.d.ts +2 -0
  16. package/dist/content-governance.d.ts.map +1 -1
  17. package/dist/content.d.ts +2 -2
  18. package/dist/content.d.ts.map +1 -1
  19. package/dist/index.js +142 -4717
  20. package/dist/index.js.map +1 -1
  21. package/dist/manifest.json +142 -5
  22. package/dist/server/content-list-actions.d.ts +123 -0
  23. package/dist/server/content-list-actions.d.ts.map +1 -0
  24. package/dist/server.d.ts +6 -0
  25. package/dist/server.d.ts.map +1 -0
  26. package/dist/server.js +874 -0
  27. package/dist/server.js.map +1 -0
  28. package/dist/smrt-knowledge.json +96 -9
  29. package/dist/svelte/components/ContentList.svelte +1028 -24
  30. package/dist/svelte/components/ContentList.svelte.d.ts +3 -0
  31. package/dist/svelte/components/ContentList.svelte.d.ts.map +1 -1
  32. package/dist/svelte/content-list-controller.d.ts +3 -1
  33. package/dist/svelte/content-list-controller.d.ts.map +1 -1
  34. package/dist/svelte/content-list-controller.js +15 -1
  35. package/dist/svelte/content-list-workflows.d.ts +87 -0
  36. package/dist/svelte/content-list-workflows.d.ts.map +1 -0
  37. package/dist/svelte/content-list-workflows.js +199 -0
  38. package/dist/svelte/i18n.contribution.d.ts +109 -0
  39. package/dist/svelte/i18n.contribution.d.ts.map +1 -1
  40. package/dist/svelte/i18n.contribution.js +109 -0
  41. package/dist/svelte/index.d.ts +1 -0
  42. package/dist/svelte/index.d.ts.map +1 -1
  43. package/dist/svelte/index.js +2 -0
  44. package/package.json +19 -14
  45. package/dist/chunks/content-transparency-Bh6axaZj.js +0 -606
  46. package/dist/chunks/content-transparency-Bh6axaZj.js.map +0 -1
@@ -43,6 +43,75 @@ visible with their error and retry affordance, so error recovery cannot report
43
43
  success or refresh as though the action applied. The tracker is exported from
44
44
  `@happyvertical/smrt-content/svelte` for the bulk-action slice to reuse rather
45
45
  than creating a second pending-state machine.
46
+ ## Cross-page bulk workflows (#2453)
47
+
48
+ Server-backed lists can opt into one shared preview/apply workflow contract for
49
+ human and agent callers. The browser integration is exported from
50
+ `@happyvertical/smrt-content/svelte`; the principal-bound adapter is exported
51
+ from `@happyvertical/smrt-content/server`.
52
+
53
+ The supported workflows are move to trash, mark draft, submit for review,
54
+ publish, archive, restore, automated review, body formatting, categorization,
55
+ and optimization. Applications inject body-formatting and optimization
56
+ handlers because those AI pipelines are application-owned; the content package
57
+ does not guess a model or rewrite policy.
58
+
59
+ Important invariants:
60
+
61
+ - `all-matching` is the canonical server query plus its query fingerprint and
62
+ exact count. It is never expanded from the IDs loaded in the browser.
63
+ - Preview is read-only and returns the resolved scope, exact count,
64
+ representative labels, eligibility outcomes, and consequences. Apply uses
65
+ the opaque preview token and an idempotency key.
66
+ - Apply resolves the query again under the same principal and tenant scope,
67
+ rechecks tool/operation authorization and eligibility, and compares the
68
+ aggregate `updated_at` row revision. Every content save also includes that
69
+ revision in its database `UPDATE`, so an edit racing the final write fails
70
+ atomically instead of being overwritten. Application formatting/optimization
71
+ handlers mutate the supplied object but must not call `save()`; the adapter
72
+ owns the guarded save. Query, count, membership, or row drift returns a stale
73
+ failure before mutation.
74
+ - Publication-producing workflows require every read used to construct their
75
+ version snapshot, including `contentassets:read` and `assets:read`. Keep those
76
+ explicit catalog assertions in sync with `ContentVersion.createSnapshot()`;
77
+ they are the authorization boundary on adapters without PostgreSQL RLS.
78
+ - Workflow queries must project `id`, `title`, `status`, and `updated_at` so the
79
+ server can bind labels, eligibility, and row revisions. The standard
80
+ ContentList query projection already includes them; a host-supplied projection
81
+ override must retain them.
82
+ - The default workflow cap is 200 rows across explicit, current-page, and
83
+ all-matching scopes. Set the same `maxSelectionSize` on the server adapter and
84
+ browser workflow binding when overriding it. The UI does not offer
85
+ all-matching selection above that cap, and the server returns
86
+ `limit_exceeded` for forged or agent requests above it.
87
+ - Automated review, formatting, and optimization are background actions. A
88
+ successful apply returns a job ID; the queue callback repeats the guarded
89
+ apply, and idempotency prevents duplicate execution. Hosts must supply
90
+ `resolveDeferredPrincipal` to re-resolve the complete live persona/TenantAgent
91
+ binding before queued mutations; missing, mismatched, or incomplete bindings
92
+ fail closed. Hosts can configure the
93
+ authenticated `jobStatusPath` transport (or supply `client.status`) so the
94
+ list can keep an identical intent locked while queued/running, reconcile
95
+ terminal row outcomes, and unlock a failed or cancelled intent for retry.
96
+ Selection controls are disabled while a status request is in flight, and the
97
+ captured intent is rechecked before any returned outcomes are reconciled.
98
+ - Foreground results report accepted, skipped, and failed rows separately. The
99
+ client clears only accepted IDs; a failed request never reports success or
100
+ clears selection.
101
+
102
+ `createContentListWorkflowTransport()` supplies the default JSON transport.
103
+ Hosts that already have an RPC layer can instead provide a structural workflow
104
+ client with the same `preview(request)` and `apply(request)` methods, plus the
105
+ optional `status(jobId)` method when background progress is shown. Both paths
106
+ must terminate at the same `createContentListActionAdapter()` instance used by
107
+ agent actions; separate human-only mutation handlers would bypass the shared
108
+ preview and authorization contract.
109
+
110
+ The server adapter also requires a `workflowStorage` capability declaration.
111
+ PostgreSQL, SQLite, ordinary DuckDB, and non-immediate exported-file modes are
112
+ supported. JSON's default/immediate mode and DuckDB `writeStrategy:
113
+ 'immediate'` fail before adapter setup because those SDK modes export writes
114
+ before the surrounding transaction commits and cannot roll the file back.
46
115
 
47
116
  ## ContentList migration (#2451)
48
117
 
@@ -0,0 +1,107 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { SmrtCollection, SmrtObject, crossPackageRef, foreignKey, smrt } from "@happyvertical/smrt-core";
3
+ import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
4
+ //#region src/content-correction.ts
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __decorateClass = (decorators, target, key, kind) => {
8
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
9
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
10
+ if (kind && result) __defProp(target, key, result);
11
+ return result;
12
+ };
13
+ var ContentCorrection = class extends SmrtObject {
14
+ contentId = "";
15
+ contentVersionId = "";
16
+ factId = "";
17
+ replacementFactId = "";
18
+ correctionType = "fact";
19
+ status = "draft";
20
+ summary = "";
21
+ incorrectText = "";
22
+ correctedText = "";
23
+ publicNote = "";
24
+ metadata = "";
25
+ tenantId = null;
26
+ publishedAt = null;
27
+ createdAt = /* @__PURE__ */ new Date();
28
+ updatedAt = /* @__PURE__ */ new Date();
29
+ constructor(options = {}) {
30
+ super(options);
31
+ if (options.contentId) this.contentId = options.contentId;
32
+ if (options.contentVersionId !== void 0) this.contentVersionId = options.contentVersionId;
33
+ if (options.factId !== void 0) this.factId = options.factId;
34
+ if (options.replacementFactId !== void 0) this.replacementFactId = options.replacementFactId;
35
+ if (options.correctionType !== void 0) this.correctionType = options.correctionType;
36
+ if (options.status !== void 0) this.status = options.status;
37
+ if (options.summary !== void 0) this.summary = options.summary;
38
+ if (options.incorrectText !== void 0) this.incorrectText = options.incorrectText;
39
+ if (options.correctedText !== void 0) this.correctedText = options.correctedText;
40
+ if (options.publicNote !== void 0) this.publicNote = options.publicNote;
41
+ if (options.tenantId !== void 0) this.tenantId = options.tenantId;
42
+ if (options.publishedAt !== void 0) this.publishedAt = options.publishedAt;
43
+ if (options.createdAt) this.createdAt = options.createdAt;
44
+ if (options.updatedAt) this.updatedAt = options.updatedAt;
45
+ if (options.metadata !== void 0) this.metadata = typeof options.metadata === "string" ? options.metadata : JSON.stringify(options.metadata);
46
+ }
47
+ getMetadata() {
48
+ try {
49
+ return this.metadata ? JSON.parse(this.metadata) : {};
50
+ } catch {
51
+ return {};
52
+ }
53
+ }
54
+ };
55
+ __decorateClass([foreignKey("Content", { required: true })], ContentCorrection.prototype, "contentId", 2);
56
+ __decorateClass([foreignKey("ContentVersion")], ContentCorrection.prototype, "contentVersionId", 2);
57
+ __decorateClass([crossPackageRef("@happyvertical/smrt-facts:Fact")], ContentCorrection.prototype, "factId", 2);
58
+ __decorateClass([crossPackageRef("@happyvertical/smrt-facts:Fact")], ContentCorrection.prototype, "replacementFactId", 2);
59
+ __decorateClass([tenantId({ nullable: true })], ContentCorrection.prototype, "tenantId", 2);
60
+ ContentCorrection = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
61
+ tableName: "content_corrections",
62
+ api: { include: [
63
+ "list",
64
+ "get",
65
+ "create",
66
+ "update"
67
+ ] },
68
+ mcp: { include: [
69
+ "list",
70
+ "get",
71
+ "create",
72
+ "update"
73
+ ] },
74
+ cli: true
75
+ })], ContentCorrection);
76
+ //#endregion
77
+ //#region src/content-corrections.ts
78
+ var content_corrections_exports = /* @__PURE__ */ __exportAll({ ContentCorrectionCollection: () => ContentCorrectionCollection });
79
+ var ContentCorrectionCollection = class extends SmrtCollection {
80
+ static _itemClass = ContentCorrection;
81
+ async listForContent(contentId) {
82
+ return this.list({
83
+ where: { contentId },
84
+ orderBy: "created_at DESC"
85
+ });
86
+ }
87
+ async getPublishedForContent(contentId) {
88
+ return this.list({
89
+ where: {
90
+ contentId,
91
+ status: "published"
92
+ },
93
+ orderBy: "published_at DESC"
94
+ });
95
+ }
96
+ async issue(options) {
97
+ if (!options) return this.create({});
98
+ return this.create({
99
+ ...options,
100
+ metadata: typeof options.metadata === "string" ? options.metadata : options.metadata ? JSON.stringify(options.metadata) : void 0
101
+ });
102
+ }
103
+ };
104
+ //#endregion
105
+ export { content_corrections_exports as n, ContentCorrection as r, ContentCorrectionCollection as t };
106
+
107
+ //# sourceMappingURL=content-corrections-BxfA3tW1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-corrections-BxfA3tW1.js","names":[],"sources":["../../src/content-correction.ts","../../src/content-corrections.ts"],"sourcesContent":["import type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport {\n crossPackageRef,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n ContentCorrectionStatus,\n ContentCorrectionType,\n} from './content-governance';\n\nexport interface ContentCorrectionOptions extends SmrtObjectOptions {\n contentId?: string;\n contentVersionId?: string;\n factId?: string;\n replacementFactId?: string;\n correctionType?: ContentCorrectionType;\n status?: ContentCorrectionStatus;\n summary?: string;\n incorrectText?: string;\n correctedText?: string;\n publicNote?: string;\n metadata?: string | Record<string, unknown>;\n tenantId?: string | null;\n publishedAt?: Date | null;\n createdAt?: Date;\n updatedAt?: Date;\n}\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'content_corrections',\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get', 'create', 'update'] },\n cli: true,\n})\nexport class ContentCorrection extends SmrtObject {\n @foreignKey('Content', { required: true })\n contentId = '';\n\n @foreignKey('ContentVersion')\n contentVersionId = '';\n\n @crossPackageRef('@happyvertical/smrt-facts:Fact')\n factId = '';\n\n @crossPackageRef('@happyvertical/smrt-facts:Fact')\n replacementFactId = '';\n correctionType: ContentCorrectionType = 'fact';\n status: ContentCorrectionStatus = 'draft';\n summary = '';\n incorrectText = '';\n correctedText = '';\n publicNote = '';\n metadata = '';\n\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n publishedAt: Date | null = null;\n createdAt = new Date();\n updatedAt = new Date();\n\n constructor(options: ContentCorrectionOptions = {}) {\n super(options);\n if (options.contentId) this.contentId = options.contentId;\n if (options.contentVersionId !== undefined)\n this.contentVersionId = options.contentVersionId;\n if (options.factId !== undefined) this.factId = options.factId;\n if (options.replacementFactId !== undefined)\n this.replacementFactId = options.replacementFactId;\n if (options.correctionType !== undefined)\n this.correctionType = options.correctionType;\n if (options.status !== undefined) this.status = options.status;\n if (options.summary !== undefined) this.summary = options.summary;\n if (options.incorrectText !== undefined)\n this.incorrectText = options.incorrectText;\n if (options.correctedText !== undefined)\n this.correctedText = options.correctedText;\n if (options.publicNote !== undefined) this.publicNote = options.publicNote;\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.publishedAt !== undefined)\n this.publishedAt = options.publishedAt;\n if (options.createdAt) this.createdAt = options.createdAt;\n if (options.updatedAt) this.updatedAt = options.updatedAt;\n\n if (options.metadata !== undefined) {\n this.metadata =\n typeof options.metadata === 'string'\n ? options.metadata\n : JSON.stringify(options.metadata);\n }\n }\n\n getMetadata(): Record<string, unknown> {\n try {\n return this.metadata ? JSON.parse(this.metadata) : {};\n } catch {\n return {};\n }\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { ContentCorrection } from './content-correction';\n\nexport class ContentCorrectionCollection extends SmrtCollection<ContentCorrection> {\n static readonly _itemClass = ContentCorrection;\n\n async listForContent(contentId: string): Promise<ContentCorrection[]> {\n return this.list({\n where: { contentId },\n orderBy: 'created_at DESC',\n });\n }\n\n async getPublishedForContent(\n contentId: string,\n ): Promise<ContentCorrection[]> {\n return this.list({\n where: { contentId, status: 'published' },\n orderBy: 'published_at DESC',\n });\n }\n\n async issue(\n options: ConstructorParameters<typeof ContentCorrection>[0],\n ): Promise<ContentCorrection> {\n if (!options) {\n return this.create({});\n }\n\n return this.create({\n ...options,\n metadata:\n typeof options.metadata === 'string'\n ? options.metadata\n : options.metadata\n ? JSON.stringify(options.metadata)\n : undefined,\n });\n }\n}\n"],"mappings":"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"}