@happyvertical/smrt-assets 0.55.6 → 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.
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-assets",
5
- "packageVersion": "0.55.6",
5
+ "packageVersion": "0.55.8",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-assets:AssetAssociation": {
8
8
  "name": "assetassociation",
@@ -3156,5 +3156,14 @@
3156
3156
  "@happyvertical/smrt-tags",
3157
3157
  "@happyvertical/smrt-tenancy"
3158
3158
  ],
3159
+ "browser": {
3160
+ "status": "server-only",
3161
+ "issues": [
3162
+ "#3624"
3163
+ ],
3164
+ "via": [
3165
+ "@happyvertical/smrt-tenancy"
3166
+ ]
3167
+ },
3159
3168
  "stampsConstructors": true
3160
3169
  }
@@ -3,12 +3,12 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-assets",
6
- "packageVersion": "0.55.6",
6
+ "packageVersion": "0.55.8",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "ec5f9340fb3b65f906ca3ffe5aef518b77488517edded7af41f1b2ceb5540335",
11
- "packageJson": "4fab0a0c13bf52f59df1cba98a631a6abd3e7ad457bc57f93d6bb5963d8bd9d6",
10
+ "manifest": "2e7a7ef90a299d20f111852f524ae5d06640ff5fa02a0b3d5da80ed4bb692738",
11
+ "packageJson": "a9a2aa4a6a73f253e1adfee3b4955e9f761507410f0d7b6ab79d72006e4fc212",
12
12
  "agents": "4e84d65324e346f9c6072da7ccee6753289efb95ffb2faf5e999081502189737"
13
13
  },
14
14
  "exports": [
@@ -4345,5 +4345,14 @@
4345
4345
  "polymorphicAssociations": 1,
4346
4346
  "uuidColumns": 40
4347
4347
  },
4348
- "agentDoc": "# @happyvertical/smrt-assets\n\nProvider-agnostic asset management with versioning, type classification, and generic/provenance associations.\n\n## Models\n\n- **Asset** (STI base): versioning via `primaryVersionId` chain + `version` number. `ownerProfileId`, `typeSlug`, `statusSlug`, `mimeType`, `sourceUri`. Derivation chain via `sourceAssetId` (R3-D — was `parentId` before the rename; column `source_asset_id`).\n- **AssetType** / **AssetStatus**: lookup tables for classification and lifecycle.\n- **AssetMetafield**: custom metadata field definitions with JSON validation rules.\n- **Folder**: hierarchical container for assets. Own `SmrtHierarchical` model with its own `folders` table (R3-D — was an STI subclass of Asset before). `Asset.folderId` points to the folder.\n- **AssetAssociation**: generic/provenance polymorphic join — `assetId` + `metaType` + `metaId` + `role` + `sortOrder`. Use it when a relationship is not owned by a base/domain model join table like `content_assets`, `profile_assets`, `event_assets`, `place_assets`, or `product_assets`.\n\n## Key Patterns\n\n- **Versioning**: `createNewVersion()` increments version, chains via `primaryVersionId`. `findVersions()` to retrieve history.\n- **Tag integration**: `addTag()`/`removeTag()` use raw `db.upsert()` on `asset_tags` join table (not a SMRT model).\n- **AssetStore**: abstraction for provider-agnostic file I/O (S3, local, etc.).\n `planFile(asset, opts)` resolves a recoverable URI before bytes are written;\n persist it before `preserveFile(asset, bytes, opts)`. Preservation adopts equal\n existing bytes and rejects changed bytes, changed resolver targets and read\n failures other than not-found. The caller owns receipt fencing/serialization.\n `removeFile(asset)` removes only bytes for recovery cleanup, including an\n already-pruned owner record; `remove(asset)` also deletes the owner record.\n- **Ownership rule**: base/domain-owned asset relationships should live on noun join tables such as `content_assets`, `profile_assets`, `event_assets`, `place_assets`, and `product_assets`; keep `AssetAssociation` for generic/provenance links like image derivation.\n\n## Runtime surface\n\nApps and agents should depend on the public **asset runtime** rather than hand-wiring a collection + store per-package (#1128).\n\n- `createAssetRuntime({ db, storage })` → `AssetRuntime` bundling `AssetCollection`, `AssetAssociationCollection`, and an initialized `AssetStore`.\n- `AssetRuntime.storeSourceAsset(name, data, opts)` — create a new source asset (record + bytes).\n- `AssetRuntime.storeDerivedAsset(source, name, data, opts)` — create a derivative with `sourceAssetId` set and (by default) a provenance `AssetAssociation` under a chosen role.\n- `AssetRuntime.linkDerivation(source, derivative, { role })` — record provenance without touching bytes.\n- `AssetRuntime.setExtractionStatus(asset, status, { error?, extractedAt? })` — write canonical extraction metadata into the asset's description JSON sidecar. Non-destructive: if `description` is free-form prose or non-object JSON, the original value is preserved under the reserved `text` key instead of being overwritten. Existing JSON objects are merged into.\n\nAgents that need asset I/O should accept an `AssetRuntimeLike` in their options rather than asking callers to pass a store + collection separately.\n\n## Serving contract\n\n- `serveAsset({ runtime, asset, tenantId?, disposition?, canAccess?, headers?, remoteMode? })` → standard Web `Response`.\n - `404` when the id doesn't resolve; `403` when the tenant mismatches or `canAccess` denies; `302` when `remoteMode: 'redirect'` and the asset's `sourceUri` is `http(s)`; `502` when `remoteMode: 'proxy'` and the origin fetch fails; `500` on store read errors or unexpected failures; `200` otherwise with `Content-Type`, `Content-Length`, and `Content-Disposition` set.\n - Assets whose `sourceUri` is `http(s)` are supported via `remoteMode`: `'proxy'` (default, fetch and return bytes), `'redirect'` (302 to the origin), or `'error'` (treat as misconfiguration). Pass `fetchImpl` to swap the fetch client.\n - `Content-Disposition` uses an ASCII-safe quoted `filename` fallback and retains the Unicode download name in UTF-8 `filename*` ([RFC 6266](https://www.rfc-editor.org/rfc/rfc6266#section-4.3), [RFC 8187](https://www.rfc-editor.org/rfc/rfc8187#section-3.2.1)). Both names strip C0/DEL/C1 controls and replace `\"` / `\\` / `/` to prevent header injection; isolated UTF-16 surrogates become U+FFFD before encoding, while valid pairs are preserved.\n - The 500 body is a generic `'Internal error serving asset'`; the underlying error is logged via `console.error` so operators can debug without leaking paths/bucket names to clients.\n - Works in SvelteKit `+server.ts` endpoints, Hono, and any runtime with a global `Response` (Node 18+). Pass `responseCtor` for older runtimes.\n- `resolveAssetForServing(options)` → `{ asset, data, contentType, filename, size }` when callers want to render their own framework response. Throws `AssetServeError(status)` on the same failure modes.\n\n## Source/derived vocabulary\n\nThe following roles are exported as `ASSET_ROLES` and should be preferred over ad-hoc strings when apps want cross-package tooling (serving, UI pickers) to agree on meaning:\n\n| Role | Use |\n|------|-----|\n| `source_document` | original upstream document (agenda PDF, minutes) |\n| `document_image` | page/extracted image derived from a source document |\n| `thumbnail` | preview rendition of another asset |\n| `proof` | non-canonical evidence asset backing a fact |\n| `derivation_source` | \"came from\" link on generated media |\n| `attachment` | generic owner-join link |\n| `hero` | primary/featured asset on an owner |\n\nCanonical metadata keys are exported as `ASSET_METADATA_KEYS`: `extractionStatus`, `extractionError`, `extractedAt`, `sourceUrl`, `sourceHash`, `pageNumber`. Extraction status values live in `ASSET_EXTRACTION_STATUS` (`pending | running | succeeded | failed`).\n\n## UI Registry\n\nThe `./ui` subpath exports `ASSETS_MODULE_META` and `ASSETS_UI_SLOTS` so registry-driven hosts (smrt-chat, dynamic admin shells) can discover the package's Svelte components without a hard import.\n\n```ts\nimport { ASSETS_MODULE_META, ASSETS_UI_SLOTS } from '@happyvertical/smrt-assets/ui';\nimport '@happyvertical/smrt-assets/svelte'; // side-effect: ModuleUIRegistry.register(...)\nimport { ModuleUIRegistry } from '@happyvertical/smrt-ui/registry';\n\nconst AssetManager = ModuleUIRegistry.get('@happyvertical/smrt-assets', 'asset-manager');\n```\n\nRegistered slots: `asset-manager` (admin), `asset-grid` / `asset-list` (list), `asset-detail` (detail), `asset-toolbar` / `asset-action-bar` (action), `asset-create-modal` (form). Slot IDs are stable contracts — host apps reference them by string.\n\n## Gotchas\n\n- **Files SDK is a lazy boundary (#1979)**: `AssetStore` loads `@happyvertical/files` through `src/files-runtime.ts` (bundler-invisible), because smrt-assets is reachable from provider-neutral consumer graphs via profiles. Node/tsx/vite-dev runtimes resolve it on first file operation; fully-bundled deployments import `@happyvertical/smrt-assets/filesystem` at startup. Never import the files SDK statically from modules reachable from `src/index.ts`.\n- **Version history manual**: `findVersions()` chaining required — no ORM shortcut\n- **Tag management uses raw SQL**: `asset_tags` is a join table, not an SMRT model\n- **Folder tree traversal**: via `SmrtHierarchical` (`getParent`/`getChildren`/`getAncestors`/`getDescendants`/`getHierarchy`/`moveTo`); `FolderCollection.getTree(rootId?)` and `getPath(folderId)` wrap these for convenience\n- **AssetAssociation polymorphic FK**: requires manual `metaType` string matching\n- **Optional tenancy**: assets can be global (tenantId=null) or tenant-scoped\n"
4348
+ "agentDoc": "# @happyvertical/smrt-assets\n\nProvider-agnostic asset management with versioning, type classification, and generic/provenance associations.\n\n## Models\n\n- **Asset** (STI base): versioning via `primaryVersionId` chain + `version` number. `ownerProfileId`, `typeSlug`, `statusSlug`, `mimeType`, `sourceUri`. Derivation chain via `sourceAssetId` (R3-D — was `parentId` before the rename; column `source_asset_id`).\n- **AssetType** / **AssetStatus**: lookup tables for classification and lifecycle.\n- **AssetMetafield**: custom metadata field definitions with JSON validation rules.\n- **Folder**: hierarchical container for assets. Own `SmrtHierarchical` model with its own `folders` table (R3-D — was an STI subclass of Asset before). `Asset.folderId` points to the folder.\n- **AssetAssociation**: generic/provenance polymorphic join — `assetId` + `metaType` + `metaId` + `role` + `sortOrder`. Use it when a relationship is not owned by a base/domain model join table like `content_assets`, `profile_assets`, `event_assets`, `place_assets`, or `product_assets`.\n\n## Key Patterns\n\n- **Versioning**: `createNewVersion()` increments version, chains via `primaryVersionId`. `findVersions()` to retrieve history.\n- **Tag integration**: `addTag()`/`removeTag()` use raw `db.upsert()` on `asset_tags` join table (not a SMRT model).\n- **AssetStore**: abstraction for provider-agnostic file I/O (S3, local, etc.).\n `planFile(asset, opts)` resolves a recoverable URI before bytes are written;\n persist it before `preserveFile(asset, bytes, opts)`. Preservation adopts equal\n existing bytes and rejects changed bytes, changed resolver targets and read\n failures other than not-found. The caller owns receipt fencing/serialization.\n `removeFile(asset)` removes only bytes for recovery cleanup, including an\n already-pruned owner record; `remove(asset)` also deletes the owner record.\n- **Ownership rule**: base/domain-owned asset relationships should live on noun join tables such as `content_assets`, `profile_assets`, `event_assets`, `place_assets`, and `product_assets`; keep `AssetAssociation` for generic/provenance links like image derivation.\n\n## Runtime surface\n\nApps and agents should depend on the public **asset runtime** rather than hand-wiring a collection + store per-package (#1128).\n\n- `createAssetRuntime({ db, storage })` → `AssetRuntime` bundling `AssetCollection`, `AssetAssociationCollection`, and an initialized `AssetStore`.\n- `AssetRuntime.storeSourceAsset(name, data, opts)` — create a new source asset (record + bytes).\n- `AssetRuntime.storeDerivedAsset(source, name, data, opts)` — create a derivative with `sourceAssetId` set and (by default) a provenance `AssetAssociation` under a chosen role.\n- `AssetRuntime.linkDerivation(source, derivative, { role })` — record provenance without touching bytes.\n- `AssetRuntime.setExtractionStatus(asset, status, { error?, extractedAt? })` — write canonical extraction metadata into the asset's description JSON sidecar. Non-destructive: if `description` is free-form prose or non-object JSON, the original value is preserved under the reserved `text` key instead of being overwritten. Existing JSON objects are merged into.\n\nAgents that need asset I/O should accept an `AssetRuntimeLike` in their options rather than asking callers to pass a store + collection separately.\n\n## Serving contract\n\n- `serveAsset({ runtime, asset, tenantId?, disposition?, canAccess?, headers?, remoteMode? })` → standard Web `Response`.\n - `404` when the id doesn't resolve; `403` when the tenant mismatches or `canAccess` denies; `302` when `remoteMode: 'redirect'` and the asset's `sourceUri` is `http(s)`; `502` when `remoteMode: 'proxy'` and the origin fetch fails; `500` on store read errors or unexpected failures; `200` otherwise with `Content-Type`, `Content-Length`, and `Content-Disposition` set.\n - Assets whose `sourceUri` is `http(s)` are supported via `remoteMode`: `'proxy'` (default, fetch and return bytes), `'redirect'` (302 to the origin), or `'error'` (treat as misconfiguration). Pass `fetchImpl` to swap the fetch client.\n - `Content-Disposition` uses an ASCII-safe quoted `filename` fallback and retains the Unicode download name in UTF-8 `filename*` ([RFC 6266](https://www.rfc-editor.org/rfc/rfc6266#section-4.3), [RFC 8187](https://www.rfc-editor.org/rfc/rfc8187#section-3.2.1)). Both names strip C0/DEL/C1 controls and replace `\"` / `\\` / `/` to prevent header injection; isolated UTF-16 surrogates become U+FFFD before encoding, while valid pairs are preserved.\n - The 500 body is a generic `'Internal error serving asset'`; the underlying error is logged via `console.error` so operators can debug without leaking paths/bucket names to clients.\n - Works in SvelteKit `+server.ts` endpoints, Hono, and any runtime with a global `Response` (Node 18+). Pass `responseCtor` for older runtimes.\n- `resolveAssetForServing(options)` → `{ asset, data, contentType, filename, size }` when callers want to render their own framework response. Throws `AssetServeError(status)` on the same failure modes.\n\n## Source/derived vocabulary\n\nThe following roles are exported as `ASSET_ROLES` and should be preferred over ad-hoc strings when apps want cross-package tooling (serving, UI pickers) to agree on meaning:\n\n| Role | Use |\n|------|-----|\n| `source_document` | original upstream document (agenda PDF, minutes) |\n| `document_image` | page/extracted image derived from a source document |\n| `thumbnail` | preview rendition of another asset |\n| `proof` | non-canonical evidence asset backing a fact |\n| `derivation_source` | \"came from\" link on generated media |\n| `attachment` | generic owner-join link |\n| `hero` | primary/featured asset on an owner |\n\nCanonical metadata keys are exported as `ASSET_METADATA_KEYS`: `extractionStatus`, `extractionError`, `extractedAt`, `sourceUrl`, `sourceHash`, `pageNumber`. Extraction status values live in `ASSET_EXTRACTION_STATUS` (`pending | running | succeeded | failed`).\n\n## UI Registry\n\nThe `./ui` subpath exports `ASSETS_MODULE_META` and `ASSETS_UI_SLOTS` so registry-driven hosts (smrt-chat, dynamic admin shells) can discover the package's Svelte components without a hard import.\n\n```ts\nimport { ASSETS_MODULE_META, ASSETS_UI_SLOTS } from '@happyvertical/smrt-assets/ui';\nimport '@happyvertical/smrt-assets/svelte'; // side-effect: ModuleUIRegistry.register(...)\nimport { ModuleUIRegistry } from '@happyvertical/smrt-ui/registry';\n\nconst AssetManager = ModuleUIRegistry.get('@happyvertical/smrt-assets', 'asset-manager');\n```\n\nRegistered slots: `asset-manager` (admin), `asset-grid` / `asset-list` (list), `asset-detail` (detail), `asset-toolbar` / `asset-action-bar` (action), `asset-create-modal` (form). Slot IDs are stable contracts — host apps reference them by string.\n\n## Gotchas\n\n- **Files SDK is a lazy boundary (#1979)**: `AssetStore` loads `@happyvertical/files` through `src/files-runtime.ts` (bundler-invisible), because smrt-assets is reachable from provider-neutral consumer graphs via profiles. Node/tsx/vite-dev runtimes resolve it on first file operation; fully-bundled deployments import `@happyvertical/smrt-assets/filesystem` at startup. Never import the files SDK statically from modules reachable from `src/index.ts`.\n- **Version history manual**: `findVersions()` chaining required — no ORM shortcut\n- **Tag management uses raw SQL**: `asset_tags` is a join table, not an SMRT model\n- **Folder tree traversal**: via `SmrtHierarchical` (`getParent`/`getChildren`/`getAncestors`/`getDescendants`/`getHierarchy`/`moveTo`); `FolderCollection.getTree(rootId?)` and `getPath(folderId)` wrap these for convenience\n- **AssetAssociation polymorphic FK**: requires manual `metaType` string matching\n- **Optional tenancy**: assets can be global (tenantId=null) or tenant-scoped\n",
4349
+ "browser": {
4350
+ "status": "server-only",
4351
+ "issues": [
4352
+ "#3624"
4353
+ ],
4354
+ "via": [
4355
+ "@happyvertical/smrt-tenancy"
4356
+ ]
4357
+ }
4349
4358
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-assets",
3
- "version": "0.55.6",
3
+ "version": "0.55.8",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Asset management system with versioning, metadata, and AI-powered operations for SMRT framework",
6
6
  "type": "module",
@@ -44,16 +44,16 @@
44
44
  }
45
45
  },
46
46
  "dependencies": {
47
- "@happyvertical/ai": "^0.102.4",
48
- "@happyvertical/files": "^0.102.4",
49
- "@happyvertical/logger": "^0.102.4",
50
- "@happyvertical/smrt-core": "0.55.6",
51
- "@happyvertical/smrt-tags": "0.55.6",
52
- "@happyvertical/smrt-tenancy": "0.55.6",
53
- "@happyvertical/smrt-types": "0.55.6",
54
- "@happyvertical/smrt-ui": "0.55.6",
55
- "@happyvertical/sql": "^0.102.4",
56
- "@happyvertical/utils": "^0.102.4"
47
+ "@happyvertical/ai": "^0.103.1",
48
+ "@happyvertical/files": "^0.103.1",
49
+ "@happyvertical/logger": "^0.103.1",
50
+ "@happyvertical/smrt-core": "0.55.8",
51
+ "@happyvertical/smrt-tags": "0.55.8",
52
+ "@happyvertical/smrt-tenancy": "0.55.8",
53
+ "@happyvertical/smrt-types": "0.55.8",
54
+ "@happyvertical/smrt-ui": "0.55.8",
55
+ "@happyvertical/sql": "^0.103.1",
56
+ "@happyvertical/utils": "^0.103.1"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "svelte": "^5.57.0"
@@ -64,8 +64,8 @@
64
64
  }
65
65
  },
66
66
  "devDependencies": {
67
- "@happyvertical/smrt-playground": "0.55.6",
68
- "@happyvertical/smrt-vitest": "0.55.6",
67
+ "@happyvertical/smrt-playground": "0.55.8",
68
+ "@happyvertical/smrt-vitest": "0.55.8",
69
69
  "@sveltejs/adapter-auto": "^7.0.1",
70
70
  "@sveltejs/kit": "2.69.1",
71
71
  "@sveltejs/package": "^2.5.8",