@happyvertical/smrt-assets 0.30.0
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/AGENTS.md +78 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +136 -0
- package/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/asset-association.d.ts +16 -0
- package/dist/asset-association.d.ts.map +1 -0
- package/dist/asset-associations.d.ts +27 -0
- package/dist/asset-associations.d.ts.map +1 -0
- package/dist/asset-capabilities.d.ts +137 -0
- package/dist/asset-capabilities.d.ts.map +1 -0
- package/dist/asset-conventions.d.ts +76 -0
- package/dist/asset-conventions.d.ts.map +1 -0
- package/dist/asset-metafield.d.ts +27 -0
- package/dist/asset-metafield.d.ts.map +1 -0
- package/dist/asset-metafields.d.ts +27 -0
- package/dist/asset-metafields.d.ts.map +1 -0
- package/dist/asset-runtime.d.ts +218 -0
- package/dist/asset-runtime.d.ts.map +1 -0
- package/dist/asset-serving.d.ts +146 -0
- package/dist/asset-serving.d.ts.map +1 -0
- package/dist/asset-status.d.ts +15 -0
- package/dist/asset-status.d.ts.map +1 -0
- package/dist/asset-statuses.d.ts +25 -0
- package/dist/asset-statuses.d.ts.map +1 -0
- package/dist/asset-store.d.ts +200 -0
- package/dist/asset-store.d.ts.map +1 -0
- package/dist/asset-type.d.ts +15 -0
- package/dist/asset-type.d.ts.map +1 -0
- package/dist/asset-types.d.ts +28 -0
- package/dist/asset-types.d.ts.map +1 -0
- package/dist/asset.d.ts +158 -0
- package/dist/asset.d.ts.map +1 -0
- package/dist/assets.d.ts +125 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/folder.d.ts +16 -0
- package/dist/folder.d.ts.map +1 -0
- package/dist/folders.d.ts +45 -0
- package/dist/folders.d.ts.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2285 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.json +4079 -0
- package/dist/media-bundle-persistence.d.ts +99 -0
- package/dist/media-bundle-persistence.d.ts.map +1 -0
- package/dist/owned-asset-helpers.d.ts +20 -0
- package/dist/owned-asset-helpers.d.ts.map +1 -0
- package/dist/playground.d.ts +2 -0
- package/dist/playground.d.ts.map +1 -0
- package/dist/playground.js +127 -0
- package/dist/playground.js.map +1 -0
- package/dist/smrt-knowledge.json +1922 -0
- package/dist/svelte/ActionBar.svelte +203 -0
- package/dist/svelte/ActionBar.svelte.d.ts +5 -0
- package/dist/svelte/ActionBar.svelte.d.ts.map +1 -0
- package/dist/svelte/AssetDetail.svelte +521 -0
- package/dist/svelte/AssetDetail.svelte.d.ts +35 -0
- package/dist/svelte/AssetDetail.svelte.d.ts.map +1 -0
- package/dist/svelte/AssetGrid.svelte +351 -0
- package/dist/svelte/AssetGrid.svelte.d.ts +5 -0
- package/dist/svelte/AssetGrid.svelte.d.ts.map +1 -0
- package/dist/svelte/AssetList.svelte +436 -0
- package/dist/svelte/AssetList.svelte.d.ts +5 -0
- package/dist/svelte/AssetList.svelte.d.ts.map +1 -0
- package/dist/svelte/AssetManager.svelte +381 -0
- package/dist/svelte/AssetManager.svelte.d.ts +5 -0
- package/dist/svelte/AssetManager.svelte.d.ts.map +1 -0
- package/dist/svelte/AssetToolbar.svelte +388 -0
- package/dist/svelte/AssetToolbar.svelte.d.ts +5 -0
- package/dist/svelte/AssetToolbar.svelte.d.ts.map +1 -0
- package/dist/svelte/CreateAssetModal.svelte +373 -0
- package/dist/svelte/CreateAssetModal.svelte.d.ts +19 -0
- package/dist/svelte/CreateAssetModal.svelte.d.ts.map +1 -0
- package/dist/svelte/__tests__/ActionBar.test.js +72 -0
- package/dist/svelte/__tests__/AssetDetail.test.js +57 -0
- package/dist/svelte/__tests__/AssetGrid.test.js +69 -0
- package/dist/svelte/__tests__/AssetList.test.js +72 -0
- package/dist/svelte/__tests__/AssetManager.test.js +21 -0
- package/dist/svelte/__tests__/AssetManagerRoute.test.js +16 -0
- package/dist/svelte/__tests__/AssetToolbar.test.js +39 -0
- package/dist/svelte/__tests__/CreateAssetModal.test.js +42 -0
- package/dist/svelte/i18n.d.ts +76 -0
- package/dist/svelte/i18n.d.ts.map +1 -0
- package/dist/svelte/i18n.js +87 -0
- package/dist/svelte/index.d.ts +19 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +30 -0
- package/dist/svelte/playground/AssetDetailPreview.svelte +131 -0
- package/dist/svelte/playground/AssetDetailPreview.svelte.d.ts +8 -0
- package/dist/svelte/playground/AssetDetailPreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground/CreateAssetModalPreview.svelte +151 -0
- package/dist/svelte/playground/CreateAssetModalPreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/CreateAssetModalPreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground.d.ts +60 -0
- package/dist/svelte/playground.d.ts.map +1 -0
- package/dist/svelte/playground.js +93 -0
- package/dist/svelte/routes/AssetManagerRoute.svelte +209 -0
- package/dist/svelte/routes/AssetManagerRoute.svelte.d.ts +4 -0
- package/dist/svelte/routes/AssetManagerRoute.svelte.d.ts.map +1 -0
- package/dist/svelte/routes/index.d.ts +2 -0
- package/dist/svelte/routes/index.d.ts.map +1 -0
- package/dist/svelte/routes/index.js +1 -0
- package/dist/svelte/routes/shared.d.ts +25 -0
- package/dist/svelte/routes/shared.d.ts.map +1 -0
- package/dist/svelte/routes/shared.js +31 -0
- package/dist/svelte/types.d.ts +179 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +6 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui.d.ts +10 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +85 -0
- package/dist/ui.js.map +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { SmrtClassOptions } from '@happyvertical/smrt-core';
|
|
2
|
+
import { Asset } from './asset';
|
|
3
|
+
import { AssetAssociation } from './asset-association';
|
|
4
|
+
import { AssetAssociationCollection } from './asset-associations';
|
|
5
|
+
import { AssetCapabilityProvider, AssetExternalSourceRef, AssetExternalSyncResult, AssetNearbySearchInput, AssetProcessResult, AssetSearchResult, AssetVariantRequest, AssetVariantResult, AssetWorkflowInput, AssetWorkflowResult } from './asset-capabilities';
|
|
6
|
+
import { AssetExtractionStatus, AssetRole } from './asset-conventions';
|
|
7
|
+
import { AssetStore, AssetStoreOptions, ProviderOptions, StoreOptions } from './asset-store';
|
|
8
|
+
import { AssetCollection } from './assets';
|
|
9
|
+
/**
|
|
10
|
+
* DB configuration accepted by the runtime — mirrors the shape
|
|
11
|
+
* `SmrtCollection.create({ db })` already accepts.
|
|
12
|
+
*/
|
|
13
|
+
export type AssetRuntimeDb = NonNullable<SmrtClassOptions['db']>;
|
|
14
|
+
/**
|
|
15
|
+
* Options for constructing an `AssetRuntime` via `createAssetRuntime()`.
|
|
16
|
+
*/
|
|
17
|
+
export interface AssetRuntimeOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Database used for `AssetCollection` and `AssetAssociationCollection`.
|
|
20
|
+
*
|
|
21
|
+
* Accepts anything `SmrtCollection.create({ db })` accepts — a string
|
|
22
|
+
* URL, a config object, or a live `DatabaseInterface`.
|
|
23
|
+
*/
|
|
24
|
+
db: AssetRuntimeDb;
|
|
25
|
+
/**
|
|
26
|
+
* Storage provider for `AssetStore`.
|
|
27
|
+
*
|
|
28
|
+
* A string is treated as a local filesystem `basePath`; otherwise
|
|
29
|
+
* forwarded to `@happyvertical/files`.
|
|
30
|
+
*/
|
|
31
|
+
storage: ProviderOptions;
|
|
32
|
+
/**
|
|
33
|
+
* Optional behavior for the underlying `AssetStore`.
|
|
34
|
+
*
|
|
35
|
+
* Use this to provide a storage resolver while keeping the convenience
|
|
36
|
+
* runtime factory.
|
|
37
|
+
*/
|
|
38
|
+
storeOptions?: AssetStoreOptions;
|
|
39
|
+
/**
|
|
40
|
+
* Optional collection instance. If omitted, one is created from `db`.
|
|
41
|
+
* Useful in tests or when the caller already has a configured
|
|
42
|
+
* collection (e.g. from `ObjectRegistry`).
|
|
43
|
+
*/
|
|
44
|
+
collection?: AssetCollection;
|
|
45
|
+
/**
|
|
46
|
+
* Optional associations collection. If omitted, one is created from `db`.
|
|
47
|
+
*/
|
|
48
|
+
associations?: AssetAssociationCollection;
|
|
49
|
+
/**
|
|
50
|
+
* Optional asset capability providers.
|
|
51
|
+
*
|
|
52
|
+
* Providers let callers keep one app-facing asset runtime while
|
|
53
|
+
* delegating processing, variant generation, search, external sync, or
|
|
54
|
+
* workflow submission to local processors or external systems.
|
|
55
|
+
*/
|
|
56
|
+
capabilityProviders?: AssetCapabilityProvider[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Structural shape of the runtime. Agents and serving helpers should
|
|
60
|
+
* depend on `AssetRuntimeLike` rather than the concrete class so tests
|
|
61
|
+
* can pass in a minimal object.
|
|
62
|
+
*/
|
|
63
|
+
export interface AssetRuntimeLike {
|
|
64
|
+
readonly collection: AssetCollection;
|
|
65
|
+
readonly associations: AssetAssociationCollection;
|
|
66
|
+
readonly store: AssetStore;
|
|
67
|
+
readonly capabilityProviders?: readonly AssetCapabilityProvider[];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Options for `AssetRuntime.storeDerivedAsset()`.
|
|
71
|
+
*/
|
|
72
|
+
export interface StoreDerivedAssetOptions extends Omit<StoreOptions, 'sourceAssetId'> {
|
|
73
|
+
/**
|
|
74
|
+
* Relationship role for the derivation link.
|
|
75
|
+
*
|
|
76
|
+
* Defaults to `ASSET_ROLES.DERIVATION_SOURCE` when `linkAssociation`
|
|
77
|
+
* is true (the default). Set explicitly for roles like
|
|
78
|
+
* `document_image` or `thumbnail` when a derivative has a more
|
|
79
|
+
* specific semantic than "came from".
|
|
80
|
+
*/
|
|
81
|
+
role?: AssetRole | string;
|
|
82
|
+
/**
|
|
83
|
+
* If true (default), also create an `AssetAssociation` record with
|
|
84
|
+
* `assetId=source.id`, `metaType=<derivativeMetaType>`,
|
|
85
|
+
* `metaId=<newAssetId>`, `role=<role>` so the provenance link is
|
|
86
|
+
* queryable independent of `sourceAssetId`.
|
|
87
|
+
*
|
|
88
|
+
* Set to `false` if you only want the column-level `sourceAssetId`
|
|
89
|
+
* derivation link.
|
|
90
|
+
*/
|
|
91
|
+
linkAssociation?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* `metaType` string stored on the `AssetAssociation`. This describes
|
|
94
|
+
* the *derivative* object (the target of `metaId`), not the source.
|
|
95
|
+
*
|
|
96
|
+
* Defaults to `'Asset'`. Callers whose derivatives are STI subclasses
|
|
97
|
+
* — e.g. an `Image` produced from a PDF — should pass the subclass
|
|
98
|
+
* name here so consumers can distinguish subtype derivatives from
|
|
99
|
+
* plain assets. This matches the convention used by
|
|
100
|
+
* `smrt-images`' `ImageDeriver.deriveWithAssociations()`.
|
|
101
|
+
*/
|
|
102
|
+
derivativeMetaType?: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Options for `AssetRuntime.linkDerivation()`.
|
|
106
|
+
*/
|
|
107
|
+
export interface LinkDerivationOptions {
|
|
108
|
+
role?: AssetRole | string;
|
|
109
|
+
/**
|
|
110
|
+
* `metaType` describing the derivative object (target of `metaId`).
|
|
111
|
+
* See `StoreDerivedAssetOptions.derivativeMetaType`.
|
|
112
|
+
*/
|
|
113
|
+
derivativeMetaType?: string;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Convenience runtime for `smrt-assets` callers. See the package
|
|
117
|
+
* `CLAUDE.md` for the full "source vs derived" vocabulary.
|
|
118
|
+
*/
|
|
119
|
+
export declare class AssetRuntime implements AssetRuntimeLike {
|
|
120
|
+
readonly collection: AssetCollection;
|
|
121
|
+
readonly associations: AssetAssociationCollection;
|
|
122
|
+
readonly store: AssetStore;
|
|
123
|
+
readonly capabilityProviders: AssetCapabilityProvider[];
|
|
124
|
+
constructor(collection: AssetCollection, associations: AssetAssociationCollection, store: AssetStore, capabilityProviders?: AssetCapabilityProvider[]);
|
|
125
|
+
registerCapabilityProvider(provider: AssetCapabilityProvider): this;
|
|
126
|
+
private providersFor;
|
|
127
|
+
processAsset(asset: Asset, input?: {
|
|
128
|
+
variants?: AssetVariantRequest[];
|
|
129
|
+
metadata?: Record<string, unknown>;
|
|
130
|
+
}): Promise<AssetProcessResult>;
|
|
131
|
+
ensureVariant(asset: Asset, request: AssetVariantRequest): Promise<AssetVariantResult>;
|
|
132
|
+
searchNearbyAssets(input: Omit<AssetNearbySearchInput, 'runtime'>): Promise<AssetSearchResult>;
|
|
133
|
+
syncExternalAsset(asset: Asset, input?: {
|
|
134
|
+
externalId?: string | null;
|
|
135
|
+
sourceRef?: AssetExternalSourceRef | null;
|
|
136
|
+
metadata?: Record<string, unknown>;
|
|
137
|
+
}): Promise<AssetExternalSyncResult>;
|
|
138
|
+
submitAssetWorkflow(asset: Asset, input: Omit<AssetWorkflowInput, 'runtime' | 'asset'>): Promise<AssetWorkflowResult>;
|
|
139
|
+
/**
|
|
140
|
+
* Create a new source asset with both a record and bytes on disk.
|
|
141
|
+
*
|
|
142
|
+
* This is the same as `AssetStore.store()`, but exposed on the runtime
|
|
143
|
+
* so callers only need one handle.
|
|
144
|
+
*/
|
|
145
|
+
storeSourceAsset(name: string, data: Buffer, opts: StoreOptions): Promise<Asset>;
|
|
146
|
+
/**
|
|
147
|
+
* Create a derivative of `source`, persist its bytes, and optionally
|
|
148
|
+
* record a provenance association.
|
|
149
|
+
*
|
|
150
|
+
* The new asset's `sourceAssetId` always points at `source.id`. When
|
|
151
|
+
* `linkAssociation` is true (the default), the runtime also writes
|
|
152
|
+
* an `AssetAssociation` so queries by role (e.g. "all `document_image`
|
|
153
|
+
* derivatives for this `source_document`") work without scanning
|
|
154
|
+
* `source_asset_id` chains.
|
|
155
|
+
*/
|
|
156
|
+
storeDerivedAsset(source: Asset, name: string, data: Buffer, opts: StoreDerivedAssetOptions): Promise<Asset>;
|
|
157
|
+
/**
|
|
158
|
+
* Record a provenance association between an existing source asset
|
|
159
|
+
* and an existing derivative asset without touching bytes.
|
|
160
|
+
*/
|
|
161
|
+
linkDerivation(source: Asset, derivative: Asset, opts?: LinkDerivationOptions): Promise<AssetAssociation>;
|
|
162
|
+
/**
|
|
163
|
+
* Update the standard extraction-status metadata on an asset's
|
|
164
|
+
* `description` JSON sidecar. This is a thin convenience over the
|
|
165
|
+
* convention in `asset-conventions.ts` — callers that store
|
|
166
|
+
* metadata elsewhere can ignore it.
|
|
167
|
+
*
|
|
168
|
+
* **How existing descriptions are handled**:
|
|
169
|
+
* - Empty / unset → fresh JSON object.
|
|
170
|
+
* - Valid JSON object → merged into; existing keys preserved.
|
|
171
|
+
* - Free-form prose or non-object JSON → preserved under the
|
|
172
|
+
* reserved `text` key of the resulting object (e.g.
|
|
173
|
+
* `{ text: "original prose", extractionStatus: "..." }`). No prose
|
|
174
|
+
* is discarded.
|
|
175
|
+
*
|
|
176
|
+
* Callers that already use `text` for something else, or that need
|
|
177
|
+
* an entirely separate metadata surface, should either round-trip
|
|
178
|
+
* the JSON themselves or skip this helper — its only job is the
|
|
179
|
+
* `extractionStatus` / `extractionError` / `extractedAt` triple.
|
|
180
|
+
*
|
|
181
|
+
* Error handling: when `status` transitions away from `failed`
|
|
182
|
+
* without a new `extra.error`, the stale `extractionError` is
|
|
183
|
+
* cleared so downstream consumers don't misread the current state.
|
|
184
|
+
* When `status === 'succeeded'`, `extractedAt` is stamped to now
|
|
185
|
+
* unless the caller provides one.
|
|
186
|
+
*/
|
|
187
|
+
setExtractionStatus(asset: Asset, status: AssetExtractionStatus, extra?: {
|
|
188
|
+
error?: string;
|
|
189
|
+
extractedAt?: Date;
|
|
190
|
+
}): Promise<void>;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Factory — lazily creates a shared asset runtime from DB + storage
|
|
194
|
+
* config. Initializes the store's filesystem adapter before returning.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```ts
|
|
198
|
+
* import { createAssetRuntime, ASSET_ROLES } from '@happyvertical/smrt-assets';
|
|
199
|
+
*
|
|
200
|
+
* const runtime = await createAssetRuntime({
|
|
201
|
+
* db: { type: 'sqlite', url: 'app.db' },
|
|
202
|
+
* storage: { type: 's3', bucket: 'my-app' },
|
|
203
|
+
* });
|
|
204
|
+
*
|
|
205
|
+
* const pdf = await runtime.storeSourceAsset('agenda.pdf', bytes, {
|
|
206
|
+
* mimeType: 'application/pdf',
|
|
207
|
+
* typeSlug: 'document',
|
|
208
|
+
* });
|
|
209
|
+
*
|
|
210
|
+
* await runtime.storeDerivedAsset(pdf, 'agenda-p1.png', pageBytes, {
|
|
211
|
+
* mimeType: 'image/png',
|
|
212
|
+
* typeSlug: 'image',
|
|
213
|
+
* role: ASSET_ROLES.DOCUMENT_IMAGE,
|
|
214
|
+
* });
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
export declare function createAssetRuntime(options: AssetRuntimeOptions): Promise<AssetRuntime>;
|
|
218
|
+
//# sourceMappingURL=asset-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-runtime.d.ts","sourceRoot":"","sources":["../src/asset-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Asset } from './asset';
|
|
2
|
+
import { AssetRuntimeLike } from './asset-runtime';
|
|
3
|
+
/**
|
|
4
|
+
* Result of `resolveAssetForServing()` — lets advanced callers
|
|
5
|
+
* stream bytes themselves while still reusing the access check.
|
|
6
|
+
*/
|
|
7
|
+
export interface ResolvedAssetBytes {
|
|
8
|
+
asset: Asset;
|
|
9
|
+
data: Buffer;
|
|
10
|
+
contentType: string;
|
|
11
|
+
filename: string;
|
|
12
|
+
size: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Options for `serveAsset()` and `resolveAssetForServing()`.
|
|
16
|
+
*/
|
|
17
|
+
export interface ServeAssetOptions {
|
|
18
|
+
/** Shared asset runtime (collection + store). */
|
|
19
|
+
runtime: AssetRuntimeLike;
|
|
20
|
+
/**
|
|
21
|
+
* Either an asset id to look up or a fully-loaded `Asset`
|
|
22
|
+
* instance. Passing the instance skips the `collection.get()` call.
|
|
23
|
+
*/
|
|
24
|
+
asset: string | Asset;
|
|
25
|
+
/**
|
|
26
|
+
* Tenant of the caller. When provided, the asset must either
|
|
27
|
+
* belong to this tenant or be a global asset (`tenantId = null`)
|
|
28
|
+
* or a 403 is returned.
|
|
29
|
+
*/
|
|
30
|
+
tenantId?: string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Optional `Content-Disposition` — `'inline'` (default) or
|
|
33
|
+
* `'attachment'`. Use `'attachment'` for download links.
|
|
34
|
+
*/
|
|
35
|
+
disposition?: 'inline' | 'attachment';
|
|
36
|
+
/**
|
|
37
|
+
* Extra headers merged into the 200 response. Does not affect
|
|
38
|
+
* 403/404/500 responses.
|
|
39
|
+
*/
|
|
40
|
+
headers?: Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Optional override for the filename used in `Content-Disposition`.
|
|
43
|
+
* Defaults to the basename of the asset's `sourceUri` or `name`.
|
|
44
|
+
*/
|
|
45
|
+
filename?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Optional access-check hook. Return `false` to short-circuit with a
|
|
48
|
+
* 403 before bytes are loaded. Runs after the built-in tenant check.
|
|
49
|
+
*/
|
|
50
|
+
canAccess?: (asset: Asset) => boolean | Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* How to handle assets whose `sourceUri` is an `http(s)` URL rather
|
|
53
|
+
* than a store-backed path.
|
|
54
|
+
*
|
|
55
|
+
* - `'error'` (default): treat a remote URI as an error (`500`). This
|
|
56
|
+
* is the safe default — `sourceUri` is attacker-settable on many
|
|
57
|
+
* asset-creation paths, so proxying it blindly is an SSRF vector
|
|
58
|
+
* (fetching `169.254.169.254` cloud metadata, internal services,
|
|
59
|
+
* etc.). Opt into `'proxy'` only for trusted sources.
|
|
60
|
+
* - `'proxy'`: fetch the bytes via `globalThis.fetch` and return them
|
|
61
|
+
* inline. Keeps the origin URL hidden from the client and preserves
|
|
62
|
+
* the same tenant/access checks the local path gets. Guarded against
|
|
63
|
+
* SSRF: the host must resolve to a public IP (private, loopback,
|
|
64
|
+
* link-local, and cloud-metadata ranges are rejected), only
|
|
65
|
+
* `http(s)` is allowed, and redirects are re-validated.
|
|
66
|
+
* - `'redirect'`: return a `302` to `sourceUri` instead of fetching.
|
|
67
|
+
* Skips the byte round-trip but exposes the origin URL.
|
|
68
|
+
*
|
|
69
|
+
* Anything that does not look like `http://` or `https://` is read
|
|
70
|
+
* through the store as usual.
|
|
71
|
+
*/
|
|
72
|
+
remoteMode?: 'proxy' | 'redirect' | 'error';
|
|
73
|
+
/**
|
|
74
|
+
* Custom `fetch` implementation for the `remoteMode: 'proxy'` path.
|
|
75
|
+
* Defaults to `globalThis.fetch` (Node 18+).
|
|
76
|
+
*/
|
|
77
|
+
fetchImpl?: typeof fetch;
|
|
78
|
+
/**
|
|
79
|
+
* Maximum number of bytes to buffer when `remoteMode: 'proxy'` fetches
|
|
80
|
+
* a remote asset. Protects against memory-exhaustion DoS from a hostile
|
|
81
|
+
* (or compromised) origin streaming an unbounded body. Defaults to
|
|
82
|
+
* {@link DEFAULT_REMOTE_MAX_BYTES} (50 MiB).
|
|
83
|
+
*/
|
|
84
|
+
remoteMaxBytes?: number;
|
|
85
|
+
/**
|
|
86
|
+
* Timeout in milliseconds for the `remoteMode: 'proxy'` fetch. Defaults
|
|
87
|
+
* to {@link DEFAULT_REMOTE_TIMEOUT_MS} (10s). Prevents a slow/hung
|
|
88
|
+
* origin from pinning the request indefinitely.
|
|
89
|
+
*/
|
|
90
|
+
remoteTimeoutMs?: number;
|
|
91
|
+
/**
|
|
92
|
+
* Custom `Response`-like constructor, for runtimes that don't have
|
|
93
|
+
* a global `Response` (pre-Node-18, workers with a custom shim).
|
|
94
|
+
* Defaults to `globalThis.Response`.
|
|
95
|
+
*/
|
|
96
|
+
responseCtor?: ResponseConstructor;
|
|
97
|
+
}
|
|
98
|
+
type ResponseConstructor = typeof Response;
|
|
99
|
+
/** Default cap (50 MiB) on bytes buffered from a proxied remote asset. */
|
|
100
|
+
export declare const DEFAULT_REMOTE_MAX_BYTES: number;
|
|
101
|
+
/** Default timeout (10s) for a proxied remote-asset fetch. */
|
|
102
|
+
export declare const DEFAULT_REMOTE_TIMEOUT_MS = 10000;
|
|
103
|
+
/**
|
|
104
|
+
* Resolve an asset + bytes for serving, enforcing the same tenant
|
|
105
|
+
* and access checks as `serveAsset()` but returning the parts so
|
|
106
|
+
* callers can render their own framework response.
|
|
107
|
+
*
|
|
108
|
+
* Throws `AssetServeError` with a status on any error so callers can
|
|
109
|
+
* map to their HTTP layer.
|
|
110
|
+
*/
|
|
111
|
+
export declare function resolveAssetForServing(options: ServeAssetOptions): Promise<ResolvedAssetBytes>;
|
|
112
|
+
/**
|
|
113
|
+
* Serve an asset as a standard Web `Response`.
|
|
114
|
+
*
|
|
115
|
+
* Returns:
|
|
116
|
+
* - `404` when the asset id doesn't resolve
|
|
117
|
+
* - `403` when the tenant mismatches or `canAccess` denies
|
|
118
|
+
* - `302` when `remoteMode: 'redirect'` and the asset's `sourceUri`
|
|
119
|
+
* is an `http(s)` URL
|
|
120
|
+
* - `502` when `remoteMode: 'proxy'` and the origin fetch fails
|
|
121
|
+
* - `500` when bytes fail to read (file missing, provider error)
|
|
122
|
+
* - `200` with the raw bytes, `Content-Type`, `Content-Length`, and
|
|
123
|
+
* `Content-Disposition` set otherwise.
|
|
124
|
+
*
|
|
125
|
+
* The resulting `Response` is framework-agnostic: SvelteKit `+server.ts`
|
|
126
|
+
* endpoints, Hono, and plain Node HTTP all accept it via their Web
|
|
127
|
+
* interop layer.
|
|
128
|
+
*/
|
|
129
|
+
export declare function serveAsset(options: ServeAssetOptions): Promise<Response>;
|
|
130
|
+
/**
|
|
131
|
+
* Error raised by `resolveAssetForServing()` with the HTTP status
|
|
132
|
+
* callers should use when rendering their own response.
|
|
133
|
+
*
|
|
134
|
+
* `message` is the specific, server-side reason — safe to log, never sent to
|
|
135
|
+
* the client. `clientMessage` is the opaque body {@link serveAsset} returns to
|
|
136
|
+
* the HTTP client; it defaults to a generic, status-keyed string so the
|
|
137
|
+
* specific reason can't leak (SSRF rejection cause, upstream status, etc.).
|
|
138
|
+
*/
|
|
139
|
+
export declare class AssetServeError extends Error {
|
|
140
|
+
readonly status: number;
|
|
141
|
+
/** Opaque body safe to return to the HTTP client. */
|
|
142
|
+
readonly clientMessage: string;
|
|
143
|
+
constructor(message: string, status: number, clientMessage?: string);
|
|
144
|
+
}
|
|
145
|
+
export {};
|
|
146
|
+
//# sourceMappingURL=asset-serving.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-serving.d.ts","sourceRoot":"","sources":["../src/asset-serving.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,OAAO,EAAE,gBAAgB,CAAC;IAE1B;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAEtB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB;;;OAGG;IACH,WAAW,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC;IAEtC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEzD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;IAE5C;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAEzB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAED,KAAK,mBAAmB,GAAG,OAAO,QAAQ,CAAC;AAE3C,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,QAAmB,CAAC;AAEzD,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAkWhD;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,kBAAkB,CAAC,CAmG7B;AAcD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,QAAQ,CAAC,CA2FnB;AAuBD;;;;;;;;GAQG;AACH,qBAAa,eAAgB,SAAQ,KAAK;aAMtB,MAAM,EAAE,MAAM;IALhC,qDAAqD;IACrD,SAAgB,aAAa,EAAE,MAAM,CAAC;gBAGpC,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EAC9B,aAAa,CAAC,EAAE,MAAM;CAMzB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SmrtObject } from '@happyvertical/smrt-core';
|
|
2
|
+
import { AssetStatusOptions } from './types';
|
|
3
|
+
export declare class AssetStatus extends SmrtObject {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
constructor(options?: AssetStatusOptions);
|
|
7
|
+
/**
|
|
8
|
+
* Get asset status by slug
|
|
9
|
+
*
|
|
10
|
+
* @param slug - The slug to search for
|
|
11
|
+
* @returns AssetStatus instance or null
|
|
12
|
+
*/
|
|
13
|
+
static getBySlug(_slug: string): Promise<AssetStatus | null>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=asset-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-status.d.ts","sourceRoot":"","sources":["../src/asset-status.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,qBAMa,WAAY,SAAQ,UAAU;IAEzC,IAAI,SAAM;IACV,WAAW,SAAM;gBAEL,OAAO,GAAE,kBAAuB;IAO5C;;;;;OAKG;WACU,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CAInE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { SmrtCollection } from '@happyvertical/smrt-core';
|
|
2
|
+
import { AssetStatus } from './asset-status';
|
|
3
|
+
export declare class AssetStatusCollection extends SmrtCollection<AssetStatus> {
|
|
4
|
+
static readonly _itemClass: typeof AssetStatus;
|
|
5
|
+
/**
|
|
6
|
+
* Get or create an asset status by slug
|
|
7
|
+
*
|
|
8
|
+
* @param slug - The asset status slug
|
|
9
|
+
* @param name - The display name (defaults to slug)
|
|
10
|
+
* @param description - Optional description
|
|
11
|
+
* @returns The existing or newly created AssetStatus
|
|
12
|
+
*/
|
|
13
|
+
getOrCreate(slug: string, name?: string, description?: string): Promise<AssetStatus>;
|
|
14
|
+
/**
|
|
15
|
+
* Initialize common asset statuses
|
|
16
|
+
*
|
|
17
|
+
* Creates standard asset statuses if they don't exist:
|
|
18
|
+
* - draft
|
|
19
|
+
* - published
|
|
20
|
+
* - archived
|
|
21
|
+
* - deleted
|
|
22
|
+
*/
|
|
23
|
+
initializeCommonStatuses(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=asset-statuses.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-statuses.d.ts","sourceRoot":"","sources":["../src/asset-statuses.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,qBAAa,qBAAsB,SAAQ,cAAc,CAAC,WAAW,CAAC;IACpE,MAAM,CAAC,QAAQ,CAAC,UAAU,qBAAe;IAEzC;;;;;;;OAOG;IACG,WAAW,CACf,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC;IAavB;;;;;;;;OAQG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;CAUhD"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { FilesystemInterface, GetFilesystemOptions } from '@happyvertical/files';
|
|
2
|
+
import { Asset } from './asset';
|
|
3
|
+
import { AssetCollection } from './assets';
|
|
4
|
+
/**
|
|
5
|
+
* Options for storing an asset
|
|
6
|
+
*/
|
|
7
|
+
export interface StoreOptions {
|
|
8
|
+
/** MIME type of the data */
|
|
9
|
+
mimeType: string;
|
|
10
|
+
/** Asset type slug (e.g., 'video', 'audio', 'image', 'reference-image') */
|
|
11
|
+
typeSlug?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Source asset ID (for derivatives like thumbnails, variants, AI edits).
|
|
14
|
+
*
|
|
15
|
+
* Renamed from `parentId` in R3-D — see Asset.sourceAssetId.
|
|
16
|
+
*/
|
|
17
|
+
sourceAssetId?: string;
|
|
18
|
+
/** Asset status slug */
|
|
19
|
+
statusSlug?: string;
|
|
20
|
+
/** Description */
|
|
21
|
+
description?: string;
|
|
22
|
+
/** Original source system for imported/derived assets */
|
|
23
|
+
sourceType?: string;
|
|
24
|
+
/** External id in the source system */
|
|
25
|
+
externalId?: string;
|
|
26
|
+
/** JSON metadata stored on the asset record */
|
|
27
|
+
metadata?: string | Record<string, unknown> | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Provider options for configuring the filesystem backend.
|
|
31
|
+
* Accepts any @happyvertical/files options or a simple basePath string for local storage.
|
|
32
|
+
*/
|
|
33
|
+
export type ProviderOptions = GetFilesystemOptions | string;
|
|
34
|
+
/**
|
|
35
|
+
* Asset storage operation currently being resolved.
|
|
36
|
+
*/
|
|
37
|
+
export type AssetStorageOperation = 'read' | 'write' | 'delete';
|
|
38
|
+
/**
|
|
39
|
+
* Context passed to an AssetStore resolver.
|
|
40
|
+
*
|
|
41
|
+
* Downstream apps can use this hook to route a logical Asset to whichever
|
|
42
|
+
* storage backend is appropriate for the current operation.
|
|
43
|
+
*/
|
|
44
|
+
export interface AssetStorageResolveRequest {
|
|
45
|
+
operation: AssetStorageOperation;
|
|
46
|
+
asset: Asset;
|
|
47
|
+
path: string;
|
|
48
|
+
sourceUri: string;
|
|
49
|
+
mimeType?: string;
|
|
50
|
+
typeSlug?: string;
|
|
51
|
+
defaultProviderOptions: GetFilesystemOptions;
|
|
52
|
+
defaultFilesystem: FilesystemInterface;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolved storage target for an AssetStore operation.
|
|
56
|
+
*/
|
|
57
|
+
export interface AssetStorageResolution {
|
|
58
|
+
filesystem?: FilesystemInterface;
|
|
59
|
+
providerOptions?: ProviderOptions;
|
|
60
|
+
path?: string;
|
|
61
|
+
sourceUri?: string;
|
|
62
|
+
}
|
|
63
|
+
export type AssetStorageResolver = (request: AssetStorageResolveRequest) => AssetStorageResolution | null | undefined | Promise<AssetStorageResolution | null | undefined>;
|
|
64
|
+
export interface AssetStoreOptions {
|
|
65
|
+
resolver?: AssetStorageResolver;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* AssetStore manages file storage and Asset record creation.
|
|
69
|
+
*
|
|
70
|
+
* Files are stored using @happyvertical/files with the convention:
|
|
71
|
+
* `{typeSlug}/{assetId}.{ext}`
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* import { AssetStore } from '@happyvertical/smrt-assets';
|
|
76
|
+
*
|
|
77
|
+
* // Local storage (backward-compatible)
|
|
78
|
+
* const store = new AssetStore('dev/data/assets', assetCollection);
|
|
79
|
+
* await store.initialize();
|
|
80
|
+
*
|
|
81
|
+
* // Provider-agnostic storage
|
|
82
|
+
* const s3Store = new AssetStore({ type: 's3', bucket: 'my-bucket' }, assetCollection);
|
|
83
|
+
* await s3Store.initialize();
|
|
84
|
+
*
|
|
85
|
+
* // Store a video buffer
|
|
86
|
+
* const asset = await store.store('my-video', videoBuffer, {
|
|
87
|
+
* mimeType: 'video/mp4',
|
|
88
|
+
* typeSlug: 'video',
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
91
|
+
* // Read it back
|
|
92
|
+
* const data = await store.read(asset);
|
|
93
|
+
*
|
|
94
|
+
* // Delete it
|
|
95
|
+
* await store.remove(asset);
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare class AssetStore {
|
|
99
|
+
private readonly collection;
|
|
100
|
+
private fs;
|
|
101
|
+
private readonly fsOptions;
|
|
102
|
+
private readonly fsCache;
|
|
103
|
+
private readonly resolver?;
|
|
104
|
+
constructor(providerOrBasePath: ProviderOptions, collection: AssetCollection, options?: AssetStoreOptions);
|
|
105
|
+
/** The base path for local storage, or empty string for non-local providers */
|
|
106
|
+
get basePath(): string;
|
|
107
|
+
/**
|
|
108
|
+
* Initialize the filesystem adapter.
|
|
109
|
+
* Must be called before any file operations.
|
|
110
|
+
*/
|
|
111
|
+
initialize(): Promise<this>;
|
|
112
|
+
/**
|
|
113
|
+
* Get the initialized filesystem (throws if not initialized)
|
|
114
|
+
*/
|
|
115
|
+
private getFs;
|
|
116
|
+
private providerCacheKey;
|
|
117
|
+
private getFilesystemForOptions;
|
|
118
|
+
/**
|
|
119
|
+
* Build a sourceUri for the given file path based on the provider type.
|
|
120
|
+
*/
|
|
121
|
+
private buildSourceUri;
|
|
122
|
+
private static buildSourceUriForProvider;
|
|
123
|
+
private static providerRelativePath;
|
|
124
|
+
private static requireAssetId;
|
|
125
|
+
private resolveStorage;
|
|
126
|
+
private writeAssetData;
|
|
127
|
+
/**
|
|
128
|
+
* Write file data for an existing Asset record (no DB record created).
|
|
129
|
+
*
|
|
130
|
+
* Use this when you've already created the record (e.g., via a
|
|
131
|
+
* collection.create()) and only need to persist the file data.
|
|
132
|
+
*
|
|
133
|
+
* @param asset - The existing asset to write data for
|
|
134
|
+
* @param data - File data as a Buffer
|
|
135
|
+
* @param opts - Storage options (mimeType required)
|
|
136
|
+
* @returns The sourceUri for the written file
|
|
137
|
+
*/
|
|
138
|
+
storeFile(asset: Asset, data: Buffer, opts: {
|
|
139
|
+
mimeType: string;
|
|
140
|
+
typeSlug?: string;
|
|
141
|
+
}): Promise<string>;
|
|
142
|
+
/**
|
|
143
|
+
* Write buffer to disk and create an Asset record.
|
|
144
|
+
*
|
|
145
|
+
* @param name - Human-readable name for the asset
|
|
146
|
+
* @param data - File data as a Buffer
|
|
147
|
+
* @param opts - Storage options (mimeType required)
|
|
148
|
+
* @returns Created Asset instance
|
|
149
|
+
*/
|
|
150
|
+
store(name: string, data: Buffer, opts: StoreOptions): Promise<Asset>;
|
|
151
|
+
/**
|
|
152
|
+
* Store a new version of an existing asset.
|
|
153
|
+
*
|
|
154
|
+
* @param asset - The existing asset to version
|
|
155
|
+
* @param data - File data for the new version
|
|
156
|
+
* @param opts - Optional overrides for store options
|
|
157
|
+
* @returns The newly created version Asset
|
|
158
|
+
*/
|
|
159
|
+
storeVersion(asset: Asset, data: Buffer, opts?: Partial<StoreOptions>): Promise<Asset>;
|
|
160
|
+
/**
|
|
161
|
+
* Read file data for a specific version of an asset.
|
|
162
|
+
*
|
|
163
|
+
* @param asset - The asset (any version in the chain)
|
|
164
|
+
* @param version - The version number to read
|
|
165
|
+
* @returns File data as a Buffer
|
|
166
|
+
*/
|
|
167
|
+
readVersion(asset: Asset, version: number): Promise<Buffer>;
|
|
168
|
+
/**
|
|
169
|
+
* Read file data from an Asset's sourceUri.
|
|
170
|
+
*
|
|
171
|
+
* @param asset - Asset to read data for
|
|
172
|
+
* @returns File data as a Buffer
|
|
173
|
+
*/
|
|
174
|
+
read(asset: Asset): Promise<Buffer>;
|
|
175
|
+
/**
|
|
176
|
+
* Read file by asset ID.
|
|
177
|
+
*
|
|
178
|
+
* @param id - Asset ID to look up
|
|
179
|
+
* @returns Object with data Buffer and Asset, or null if not found
|
|
180
|
+
*/
|
|
181
|
+
readById(id: string): Promise<{
|
|
182
|
+
data: Buffer;
|
|
183
|
+
asset: Asset;
|
|
184
|
+
} | null>;
|
|
185
|
+
/**
|
|
186
|
+
* Delete file from disk and remove the Asset record.
|
|
187
|
+
*
|
|
188
|
+
* @param asset - Asset to remove
|
|
189
|
+
*/
|
|
190
|
+
remove(asset: Asset): Promise<void>;
|
|
191
|
+
/**
|
|
192
|
+
* Extract filesystem path from a sourceUri.
|
|
193
|
+
* Handles file://, s3://, and plain paths.
|
|
194
|
+
*
|
|
195
|
+
* @param sourceUri - Asset sourceUri (e.g., 'file:///path/to/file.mp4', 's3://bucket/key')
|
|
196
|
+
* @returns Filesystem path
|
|
197
|
+
*/
|
|
198
|
+
static pathFromUri(sourceUri: string): string;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=asset-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-store.d.ts","sourceRoot":"","sources":["../src/asset-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SmrtObject } from '@happyvertical/smrt-core';
|
|
2
|
+
import { AssetTypeOptions } from './types';
|
|
3
|
+
export declare class AssetType extends SmrtObject {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
constructor(options?: AssetTypeOptions);
|
|
7
|
+
/**
|
|
8
|
+
* Get asset type by slug
|
|
9
|
+
*
|
|
10
|
+
* @param slug - The slug to search for
|
|
11
|
+
* @returns AssetType instance or null
|
|
12
|
+
*/
|
|
13
|
+
static getBySlug(_slug: string): Promise<AssetType | null>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=asset-type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-type.d.ts","sourceRoot":"","sources":["../src/asset-type.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAMa,SAAU,SAAQ,UAAU;IAEvC,IAAI,SAAM;IACV,WAAW,SAAM;gBAEL,OAAO,GAAE,gBAAqB;IAO1C;;;;;OAKG;WACU,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;CAIjE"}
|