@happyvertical/smrt-content 0.55.7 → 0.55.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,12 +3,12 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-content",
6
- "packageVersion": "0.55.7",
6
+ "packageVersion": "0.55.8",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "81c909bea493838e8664e190f0e19f52a20ba541d689e28d609b2e412f2d7382",
11
- "packageJson": "1d4cc86589400475c0fe4577e3a2f4ef0d2e1a127e4ed3236b15b4c07b41786e",
10
+ "manifest": "6e45e451fe4beb0f7a3461a9f047d806eff1750bf74b1a3038d69bb0d6bf5651",
11
+ "packageJson": "81f49874494bc4b0d198cbd951bb6d81606fcf890723959e2013d9924f631c84",
12
12
  "agents": "dffe54f5b13fa274d24056c6dc48179bd3bb4ef93c4e47670651f27b67523826",
13
13
  "moduleDoc:agents/content-list.md": "e5e990d6688f2a89fe521741e9af6e202dad5fa827307c727cfb5db92a83145a"
14
14
  },
@@ -14237,5 +14237,29 @@
14237
14237
  "module": "content-list",
14238
14238
  "content": "<!-- Module doc for packages/content/AGENTS.md. -->\n\n# ContentList contracts\n\nRead for changes to `src/svelte/content-list-*.ts`, `ContentList.svelte`, or the\nserver content-query/action adapters. Browser exports come from `/svelte`;\nprincipal-bound query/action factories come from `/server`.\n\n## Ownership and integration\n\n- `content-list-controller.ts` is the shared adapter over `DataTableController`.\n Search, filters, sort, paging, selection, columns, and action eligibility have\n one implementation across grid, detailed, and compact presentations. Controller\n modes are manual. Local arrays use `toContentListRows`, `selectContentListRows`,\n then `paginateContentListRows`; server rows must never be transformed again.\n- `query`, `urlState`, `savedViews`, `lifecycle`, `jobs`, and `dataSurface` are\n optional bindings. Without query, rows come from `contents`; with it, contents\n is ignored. `type` locks/hides the type filter; `defaultViewMode` seeds once.\n Existing callbacks (`onEdit`, `onDelete`, `onAdd`, `getViewHref`) remain usable.\n- `query.bind()` runs once during component initialization so a structural\n `remoteQuery(collection, transport)` binding registers teardown in that scope.\n Do not import smrt-svelte/web or its browser data runtime into the content\n Svelte barrel: public content pages depend on that code-split boundary.\n- The default query transport targets `POST /api/v1/contents/query`.\n `CONTENT_LIST_QUERY_FIELDS` maps column IDs to server fields;\n `ROW_FIELD_TO_CONTENT_KEY` maps response fields to ContentData. For example,\n column `updated`, client `updatedAt`, and server `updated_at` differ.\n `publish` maps to `publish_date`. Derived `site` comes from url/source and has\n no server field; server filtering/sorting on it is dropped and reported.\n- Missing/duplicate durable IDs still render with positional keys but are\n `identified: false`. Disable and explain their selection controls. Page select\n all and normalization exclude synthetic IDs; server selection must survive\n page changes, so current-page membership is not a durability test.\n- Compact uses content-owned `select` and `actions` columns, included in\n `CONTENT_LIST_TABLE_COLUMN_IDS`. DataTable's generic selection cannot enforce\n per-row eligibility. Resolve links/actions through the shared adapter.\n\n## Paging and freshness\n\nContentList owns the pager in every presentation and passes no `totalRows` to\nDataTable, whose independent clamp would mutate the shared controller without\nknowing which query produced a count.\n\n- Clamp on the local full-array count or an exact total for the active settled\n server query only. Never clamp on an estimate, unavailable total, page length,\n previous-query response, or before the current response arrives. An estimate\n may still drive the displayed pager. Test paging in grid and compact modes.\n- Resolve one page-size ceiling with `resolveContentListMaxPageSize`: the minimum\n of configured limits and schema limit (default 200). Use it for controller\n seed, URL/saved-view sanitizers, translator, and live state. Server seed defaults\n to 50; null page size becomes the seed and oversized values become the ceiling,\n with reported drops. Local mode may remain unpaginated. Omitted URL size must\n restore the server seed. `setPageSize` resets page.\n- Offset only; maximum offset is 1,000,000. Report capping and update the marker\n to `effectivePage`; retain the notice until the operator leaves that page.\n Pager maximum is `floor(MAX_OFFSET / pageSize) + 1`, while clamp uses the true\n total so crafted out-of-range pages receive the explanatory notice.\n- Subscribe after the first request; query changes rebind the exact subscription.\n Offline retains usable stale rows. Online calls live `reconnect()` (refresh\n before resubscription), otherwise `refresh()`. Refresh errors are inline over\n retained rows. Show loading, retry, refreshing, last update, offline, truncation,\n and warnings across presentations. Read completeness flags from retry envelopes\n as well as execute envelopes; a successful retry replaces old flags.\n\n## Query authority and protocol\n\n`executeContentQuery()` applies tenancy, failing closed to global rows. Host\napplication scope comes from authenticated context, never request body; caller\nfilters only narrow it. Omitted scope means no extra application restriction;\n`scope: []` means no permitted rows (`id IS NULL`). AND scope into every query\nbranch alongside tenancy. Empty object conditions are configuration errors.\n\nKeep field maps, projectable fields, operator/search vocabulary, and mirrored\nlimits asserted against `buildContentQuerySchema()` and core constants or their\nobservable acceptance boundaries.\n\n- No cursor paging, body queries, metadata-path filters, or ETag/version slot.\n Read body through GET by ID; use queryFingerprint/freshness.asOf for freshness.\n- Search emits an `any` of `like` over title/description/author, escaping caller\n `%`/`_`. Drop and report unsupported `notContains`, datetime LIKE operators,\n invalid datetime inputs, unknown projection fields, and derived site queries.\n- Bound normalized request bytes, including default sort. Always emit sort\n (fall back to `CONTENT_LIST_QUERY_DEFAULT_SORT`) so client accounting is not\n smaller than the normalizer's. Limits: 100 list values, 50 filter nodes\n (containers count; search costs four), 128 DNF branches, 50 projection fields\n with 1–256-character IDs, 128-character request ID, 4096 UTF-16 units per scalar,\n 100,000 serialized request bytes. Count escapes and surrogate pairs without\n splitting code points. DNF costs include null unions and De Morgan negation.\n- Preserve comparands exactly or omit/report the filter. Oversized/unusable `in`\n entries may be removed as a reported subset (`out-of-range`/`unsupported-value`).\n Never partially apply `notIn`: drop/report `filter-widened`. Shed conjuncts for\n node/branch/byte budgets with that same report. Shortened LIKE/search patterns\n report widening; retain leading code points for contains/startsWith and trailing\n ones for endsWith. Never shorten scalar eq/ne/ordered comparands into a value\n the caller did not name. Every change is either exact, a reported superset,\n a reported subset, or a reported omitted predicate.\n- Datetimes require a real calendar day, four-digit year, T separator and an\n offset when time is present. Date-only means midnight UTC; minutes without\n seconds and lowercase t/z are accepted. Trim and uppercase before parsing,\n validate that same string, and calendar-round-trip to reject rolled dates.\n\n### Comparison semantics and dialect limits\n\nFold token filter values (type/status/state); preserve free-text case. Local\ntext comparison is case-insensitive; server free-text matching follows its SQL\noperator/dialect. PostgreSQL/DuckDB LIKE is case-sensitive; SQLite LIKE is ASCII\ncase-insensitive. Do not promise uniform free-text matching.\n\nSQLite's LIKE lacks the default backslash escape used by PostgreSQL/DuckDB;\nescaped wildcards can fail closed there. Fixing portability needs SQL-boundary\nESCAPE support. Null placement is likewise dialect-dependent: local sorts absent\nlast ascending/first descending, matching PostgreSQL/DuckDB; SQLite defaults\noppositely. The query sort grammar cannot express NULLS FIRST/LAST.\n\n- Read absence from original ContentData, not flattened display text. Type's\n `content` and title's `Untitled content` fallbacks are presentation only; missing\n values compare/search as null, genuinely blank strings remain present.\n- eq/in/LIKE exclude absent values unless null is explicitly listed. ne of a\n non-null value and notIn without null include absence. notIn containing null\n excludes absence. eq/ne null lower to IS NULL/IS NOT NULL. Direct ordered\n comparisons exclude absence; their negations include it. Every supported\n predicate and its negation must partition rows without gaps or overlap,\n including nested all/any and double negation. Negated LIKE is refused.\n- Preserve literal null through sanitization, saved views, translation and local\n evaluation; only undefined denotes unusable input. Test null, false, zero and\n empty strings. Blank scalar clears a filter; an empty entry within a list is\n real text, but a wholly empty list parameter is refused/reported.\n\n## Result budgets\n\nCall `assertContentQuerySchema(schema)` at configuration time. Every executor\nmode, including count, rejects maxResultBytes below\n`CONTENT_QUERY_MIN_RESULT_BYTES`; this is a host error, not caller validation.\n\n- Never drop rows to fit bytes: offset advances by requested limit, so omitted\n rows would become unreachable. Seat every row's irreducible floor first, then\n distribute surplus max-min fairly by appetite (cost minus floor).\n `allocateRowBytes` guarantees a page whenever floors fit; otherwise fail loudly.\n Preserve `floor <= cost` and refund the final unused array separator at exact\n byte boundaries.\n- Within rows use one sorted water-filling walk. Strings may shorten; datetime\n and JSON values are all-or-nothing (null only if smaller). Numbers, booleans,\n null, and identity never shrink. Prefer shortening free text before losing a\n format-constrained value; new constrained types are all-or-nothing by default.\n Report shortening with truncated/warnings.\n- Bound JSON documents before result normalization: strings 65,536 characters,\n containers 1,000 items, depth 16; finite numbers, no cycles, plain values only.\n Drop forbidden __proto__/constructor/prototype keys and build with null\n prototypes. Report truncation rather than allowing one stored document to\n invalidate an entire page.\n- Facets share the result byte budget; drop excess facet values and flag both\n facet and result. Per-value caps alone do not bound the envelope.\n\n## URL state and saved views\n\nRead urlState.params once; later onChange(params, state) preserves foreign\nparameters and lets the host own routing. `applyContentListViewState` is the\npublic application boundary: sanitize every patch, including raw saved snapshots,\nthen merge over current state without resetting restored page. Sanitize the patch,\nnot the merged result, because selection is intentionally absent from sanitizer\noutput. Keep raw saved-view payloads so stale-field drops remain reportable.\n\n- Escape list separators and double literal backslashes. List null uses the\n collision-free `\\0` token; a literal backslash-zero string is doubled. Scalar\n null serializes through isNull/isNotNull. Preserve foreign parameters by base\n name, even when they have a known operator suffix; unknown suffixed columns\n may still be reported as refused without being deleted.\n- The type lock applies to live state, including agent reset/filter commands.\n Fold it into restored patches to preserve paging. Clear it only on an actual\n lock-removal transition, not every unlocked render.\n- Toolbar selects must state the live predicate honestly. Unlisted equals values\n render as extra options and produce a notice. Lists, non-equals operators, and\n multiple predicates render a disabled summary and notice. Use operator-aware\n `readContentListSelectFilter`, not value-only `readContentListFilter`.\n Choosing a real option replaces all filters on that column. Summary sentinel\n uses U+001F; NUL changes during HTML parsing and breaks hydration.\n- Review is an ordinary status; deleted belongs exclusively to opt-in trash\n mode. Type options are display vocabulary, not the freeform model domain.\n Restore/translation refusals appear in one dismissible notice; stale state\n should still open with the refused parts omitted.\n\n## Shared mutations and lifecycle\n\nHuman transports and agent/bulk callers terminate at the same\n`createContentListActionAdapter()` instance. Preview/apply is principal-bound;\nrendered rows are never mutation authority.\n\n- Supported workflows: trash, draft, review submission, publish, archive, restore,\n automated review, formatting, categorization, optimization. Applications inject\n formatting/optimization handlers; handlers mutate supplied objects but must\n not save them because the adapter owns guarded writes.\n- Explicit/current-page/all-matching selections share a default 200-row cap.\n Match server and browser maxSelectionSize. All-matching is canonical query,\n fingerprint and exact count, never browser-page expansion. Above-cap requests\n fail closed, including forged/agent requests; UI asks the operator to narrow.\n- Read-only preview returns resolved scope/count/labels/eligibility/consequences.\n Apply uses opaque token and idempotency key, re-resolves query under live\n principal/tenant, rechecks tool/operation permissions and eligibility, and\n compares aggregate updated_at revision. Query/count/membership/row drift fails\n before mutation. Each save also guards updated_at atomically at UPDATE.\n Required projection: id, title, status, updated_at, even under host overrides.\n- Publication workflows require every snapshot read permission, explicitly\n including contentassets:read and assets:read. Keep assertions aligned with\n `ContentVersion.createSnapshot()`; embedded adapters rely on them without RLS.\n- Declare workflowStorage capability. PostgreSQL, SQLite, ordinary DuckDB and\n non-immediate exported-file modes are supported. JSON default/immediate and\n DuckDB immediate writes are rejected at setup because exports cannot roll back.\n- Partial results separate accepted/skipped/failed rows; clear only accepted IDs.\n Failures retain selection. Refresh the exact query and expose progress,\n exceptions, representative labels, resourceType/resourceId and auditReference.\n\nLifecycle binding enables trash controls; trash mode locks deleted and hides\nordinary status/edit/delete controls. Without it legacy onDelete remains.\n`createContentListLifecycleRoute()` mounts POST /api/v1/contents/lifecycle;\nits host authenticates every native Request and supplies current action context.\nOnly move-to-trash, restore, permanent-delete are accepted; malformed/auth/internal\nfailures use bounded envelopes without private error text.\n\n| Action | Eligible state | Contract |\n|---|---|---|\n| move-to-trash | not deleted | soft deletion |\n| restore | deleted | draft/review/published; recheck permissions and publication readiness |\n| permanent-delete | deleted | type exact server count; irreversible |\n\nPermanent DELETE binds updated_at in PostgreSQL's predicate with transactional\ncascade; embedded adapters compare under the shared write queue before cascade.\nRaces return row_revision_drifted. Empty-trash requires exact server count plus\ncanonical query. Query/selection changes invalidate previews; expiry, stale\nrevision, row/query/count drift or token failures require new preview. Preview,\ninitial apply and replay each get distinct attempt request IDs; apply/replay keep\nconfirmation/idempotency authority, and auditReference identifies original execution.\n\n## Jobs and agent surfaces\n\n- Automated review/formatting/optimization return job IDs. Queue callbacks repeat\n guarded apply with idempotency. Hosts must provide resolveDeferredPrincipal to\n re-resolve the complete live persona/TenantAgent binding; absent, mismatched or\n incomplete bindings fail closed. Authenticated jobStatusPath or client.status\n keeps identical intents locked while running, reconciles terminal outcomes,\n and allows failed/cancelled retry. Disable selection during status requests and\n recheck captured intent before reconciling responses.\n- `createContentListJobController().submit({ actionId, submissionKey, target },\n start)` coalesces duplicate active keys; rejected submissions stay failed until\n retry. update(job) cannot regress terminal state. Pending row work disables\n selection/edit/delete. Only succeeded transitions refresh: row targets require\n an affected visible row; query targets require the active request key. Failed\n jobs show error/retry and never masquerade as success.\n- Register dataSurface once at ContentList boundary across presentations and\n loading/empty/error states. Publish rendered columns plus required id (hidden\n description stays search-only), explicit fieldName mapping, available operators,\n query fingerprint/total, normalized selection, presentation and freshness.\n Derived site becomes read-only in server mode. Expose only mounted executable\n workflow/lifecycle actions. Context changes advance the same revision stream;\n stale revisions and disconnected registry commands are refused. set-view\n acknowledgements describe accepted state before renderer changes.\n- Silent reads use server `createContentListDataSurfaceDefinition({ collection,\n scope })` in createDataSurfaceTools. Resolve collection/scope from live principal;\n executeContentQuery owns rows/counts/facets/offset continuation. Exclude tenant,\n hidden and sensitive fields from discovery/projection. Durable agent mutations\n use the action adapter, never browser registry authority.\n\n## Validation\n\nUse package `pnpm test` (which generates routes through SvelteKit sync), never\nbare Vitest. Narrow with `-- <test-file>` to the affected content-list, query,\naction, lifecycle or component tests; include both grid and compact paging\nscenarios for reachability changes. Run package `pnpm typecheck` for Svelte\nchanges and root knowledge checks for this module documentation.\n"
14239
14239
  }
14240
- ]
14240
+ ],
14241
+ "browser": {
14242
+ "status": "server-only",
14243
+ "issues": [
14244
+ "#3615",
14245
+ "#3617",
14246
+ "#3624",
14247
+ "#3625",
14248
+ "#3626",
14249
+ "#3627",
14250
+ "#3628"
14251
+ ],
14252
+ "reason": "node:crypto; documents/spider/files/images/ai SDK graph (crawlee, undici, googleapis, native addons); CJS parse error",
14253
+ "via": [
14254
+ "@happyvertical/smrt-agents",
14255
+ "@happyvertical/smrt-chat",
14256
+ "@happyvertical/smrt-images",
14257
+ "@happyvertical/smrt-jobs",
14258
+ "@happyvertical/smrt-profiles",
14259
+ "@happyvertical/smrt-reports",
14260
+ "@happyvertical/smrt-secrets",
14261
+ "@happyvertical/smrt-tenancy",
14262
+ "@happyvertical/smrt-users"
14263
+ ]
14264
+ }
14241
14265
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-content",
3
- "version": "0.55.7",
3
+ "version": "0.55.8",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Content processing module for SMRT framework - handles documents, web content, and media",
6
6
  "type": "module",
@@ -47,29 +47,29 @@
47
47
  }
48
48
  },
49
49
  "dependencies": {
50
- "@happyvertical/ai": "^0.102.5",
51
- "@happyvertical/documents": "^0.102.5",
52
- "@happyvertical/files": "^0.102.5",
53
- "@happyvertical/geo": "^0.102.5",
54
- "@happyvertical/images": "^0.102.5",
55
- "@happyvertical/logger": "^0.102.5",
50
+ "@happyvertical/ai": "^0.103.1",
51
+ "@happyvertical/documents": "^0.103.1",
52
+ "@happyvertical/files": "^0.103.1",
53
+ "@happyvertical/geo": "^0.103.1",
54
+ "@happyvertical/images": "^0.103.1",
55
+ "@happyvertical/logger": "^0.103.1",
56
56
  "@happyvertical/ocr": "^0.61.6",
57
57
  "@happyvertical/pdf": "^0.65.9",
58
- "@happyvertical/smrt-assets": "0.55.7",
59
- "@happyvertical/smrt-agents": "0.55.7",
60
- "@happyvertical/smrt-chat": "0.55.7",
61
- "@happyvertical/smrt-core": "0.55.7",
62
- "@happyvertical/smrt-facts": "0.55.7",
63
- "@happyvertical/smrt-images": "0.55.7",
64
- "@happyvertical/smrt-messages": "0.55.7",
65
- "@happyvertical/smrt-prompts": "0.55.7",
66
- "@happyvertical/smrt-profiles": "0.55.7",
67
- "@happyvertical/smrt-tenancy": "0.55.7",
68
- "@happyvertical/smrt-types": "0.55.7",
69
- "@happyvertical/smrt-ui": "0.55.7",
58
+ "@happyvertical/smrt-assets": "0.55.8",
59
+ "@happyvertical/smrt-agents": "0.55.8",
60
+ "@happyvertical/smrt-chat": "0.55.8",
61
+ "@happyvertical/smrt-core": "0.55.8",
62
+ "@happyvertical/smrt-facts": "0.55.8",
63
+ "@happyvertical/smrt-images": "0.55.8",
64
+ "@happyvertical/smrt-messages": "0.55.8",
65
+ "@happyvertical/smrt-prompts": "0.55.8",
66
+ "@happyvertical/smrt-profiles": "0.55.8",
67
+ "@happyvertical/smrt-tenancy": "0.55.8",
68
+ "@happyvertical/smrt-types": "0.55.8",
69
+ "@happyvertical/smrt-ui": "0.55.8",
70
70
  "@happyvertical/spider": "^1.1.13",
71
- "@happyvertical/sql": "^0.102.5",
72
- "@happyvertical/utils": "^0.102.5",
71
+ "@happyvertical/sql": "^0.103.1",
72
+ "@happyvertical/utils": "^0.103.1",
73
73
  "fast-xml-parser": "^5.11.1",
74
74
  "sanitize-html": "^2.17.7",
75
75
  "undici": "^7.29.1",
@@ -85,9 +85,9 @@
85
85
  },
86
86
  "devDependencies": {
87
87
  "@faker-js/faker": "^10.6.0",
88
- "@happyvertical/smrt-playground": "0.55.7",
89
- "@happyvertical/smrt-users": "0.55.7",
90
- "@happyvertical/smrt-vitest": "0.55.7",
88
+ "@happyvertical/smrt-playground": "0.55.8",
89
+ "@happyvertical/smrt-users": "0.55.8",
90
+ "@happyvertical/smrt-vitest": "0.55.8",
91
91
  "@sveltejs/kit": "2.69.1",
92
92
  "@sveltejs/package": "^2.5.8",
93
93
  "@sveltejs/vite-plugin-svelte": "^7.3.0",