@coreframe/assets 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AssetBuildEntry, AssetBuildResult, AssetCatalog, AssetCatalogEntry, AssetCatalogPack, AssetFile, AssetKind, AssetManifest, AssetManifestEntry, AssetOutput, AssetOutputStatus, AssetProblem, AssetPublishResult, AssetSource, AssetStatus, AssetStatusEntry, AssetVariant, AudioAssetFile, AudioCatalogEntry, AudioManifestEntry, ImageCatalogEntry, ImageManifestEntry, LoadedAssetCatalog, LoadedAssetManifest, LottieAssetFile, LottieCatalogEntry, LottieManifestEntry, PublishedAsset, SvgAssetFile, SvgCatalogEntry, SvgManifestEntry, SvgViewBox, VideoAssetFile, VideoCatalogEntry, VideoManifestEntry } from "./contracts.js";
2
2
  import { assetCatalogEntries, assetCatalogPackNames, assetManifestPath, findCatalogAsset, formatAssetProblems, listAssetManifestPacks, manifestEntryOutputs, readAssetCatalog, readAssetManifest, resolveAssetVariantFile } from "./project.js";
3
- import { AddAssetOptions, AssetManifestStatus, AssetWorkflowOptions, BuildAssetsOptions, CheckAssetManifestsOptions, CheckAssetsOptions, PublishAssetsOptions, addAsset, buildAssets, checkAssetManifests, checkAssets, materializeAsset, printAssetResult, publishAssets } from "./workflows.js";
3
+ import { AddAssetOptions, AssetManifestStatus, AssetResultOperation, AssetWorkflowOptions, BuildAssetsOptions, CheckAssetManifestsOptions, CheckAssetsOptions, PublishAssetsOptions, addAsset, buildAssets, checkAssetManifests, checkAssets, materializeAsset, printAssetResult, publishAssets } from "./workflows.js";
4
4
  import { AssetBackupResult, BackupAssetsOptions, backupAssets } from "./backup.js";
5
- export { AddAssetOptions, AssetBackupResult, type AssetBuildEntry, type AssetBuildResult, type AssetCatalog, type AssetCatalogEntry, type AssetCatalogPack, type AssetFile, type AssetKind, type AssetManifest, type AssetManifestEntry, AssetManifestStatus, type AssetOutput, type AssetOutputStatus, type AssetProblem, type AssetPublishResult, type AssetSource, type AssetStatus, type AssetStatusEntry, type AssetVariant, AssetWorkflowOptions, type AudioAssetFile, type AudioCatalogEntry, type AudioManifestEntry, BackupAssetsOptions, BuildAssetsOptions, CheckAssetManifestsOptions, CheckAssetsOptions, type ImageCatalogEntry, type ImageManifestEntry, type LoadedAssetCatalog, type LoadedAssetManifest, type LottieAssetFile, type LottieCatalogEntry, type LottieManifestEntry, PublishAssetsOptions, type PublishedAsset, type SvgAssetFile, type SvgCatalogEntry, type SvgManifestEntry, type SvgViewBox, type VideoAssetFile, type VideoCatalogEntry, type VideoManifestEntry, addAsset, assetCatalogEntries, assetCatalogPackNames, assetManifestPath, backupAssets, buildAssets, checkAssetManifests, checkAssets, findCatalogAsset, formatAssetProblems, listAssetManifestPacks, manifestEntryOutputs, materializeAsset, printAssetResult, publishAssets, readAssetCatalog, readAssetManifest, resolveAssetVariantFile };
5
+ export { AddAssetOptions, AssetBackupResult, type AssetBuildEntry, type AssetBuildResult, type AssetCatalog, type AssetCatalogEntry, type AssetCatalogPack, type AssetFile, type AssetKind, type AssetManifest, type AssetManifestEntry, AssetManifestStatus, type AssetOutput, type AssetOutputStatus, type AssetProblem, type AssetPublishResult, AssetResultOperation, type AssetSource, type AssetStatus, type AssetStatusEntry, type AssetVariant, AssetWorkflowOptions, type AudioAssetFile, type AudioCatalogEntry, type AudioManifestEntry, BackupAssetsOptions, BuildAssetsOptions, CheckAssetManifestsOptions, CheckAssetsOptions, type ImageCatalogEntry, type ImageManifestEntry, type LoadedAssetCatalog, type LoadedAssetManifest, type LottieAssetFile, type LottieCatalogEntry, type LottieManifestEntry, PublishAssetsOptions, type PublishedAsset, type SvgAssetFile, type SvgCatalogEntry, type SvgManifestEntry, type SvgViewBox, type VideoAssetFile, type VideoCatalogEntry, type VideoManifestEntry, addAsset, assetCatalogEntries, assetCatalogPackNames, assetManifestPath, backupAssets, buildAssets, checkAssetManifests, checkAssets, findCatalogAsset, formatAssetProblems, listAssetManifestPacks, manifestEntryOutputs, materializeAsset, printAssetResult, publishAssets, readAssetCatalog, readAssetManifest, resolveAssetVariantFile };
@@ -64,6 +64,18 @@ declare function checkAssetManifests(options?: CheckAssetManifestsOptions): Prom
64
64
  declare function checkAssets(options?: CheckAssetsOptions): Promise<AssetStatus>;
65
65
  declare function publishAssets(options?: PublishAssetsOptions): Promise<AssetPublishResult>;
66
66
  declare function materializeAsset(assetId: string, options?: BuildAssetsOptions): Promise<AssetBuildResult>;
67
- declare function printAssetResult(result: unknown, json?: boolean): void;
67
+ type AssetResultOperation = {
68
+ kind: "add";
69
+ assetId: string;
70
+ } | {
71
+ kind: "build";
72
+ } | {
73
+ kind: "check";
74
+ } | {
75
+ kind: "publish";
76
+ } | {
77
+ kind: "status";
78
+ };
79
+ declare function printAssetResult(result: unknown, json?: boolean, operation?: AssetResultOperation): void;
68
80
  //#endregion
69
- export { AddAssetOptions, AssetManifestStatus, AssetWorkflowOptions, BuildAssetsOptions, CheckAssetManifestsOptions, CheckAssetsOptions, PublishAssetsOptions, addAsset, buildAssets, checkAssetManifests, checkAssets, materializeAsset, printAssetResult, publishAssets };
81
+ export { AddAssetOptions, AssetManifestStatus, AssetResultOperation, AssetWorkflowOptions, BuildAssetsOptions, CheckAssetManifestsOptions, CheckAssetsOptions, PublishAssetsOptions, addAsset, buildAssets, checkAssetManifests, checkAssets, materializeAsset, printAssetResult, publishAssets };
package/dist/workflows.js CHANGED
@@ -1 +1 @@
1
- import{fs as e,process as t}from"./environment.js";import{assertAssetId as n,assertAssetPackName as r,assetCatalogEntries as i,assetCatalogPackNames as a,assetIdPattern as o,assetManifestPath as s,catalogPath as c,findAssetReferences as l,findCatalogAsset as u,formatAssetProblems as d,isAssetVariantPath as f,listAssetManifestPacks as p,manifestEntryMatchesCatalog as m,manifestEntryOutputs as h,readAssetCatalog as g,readAssetManifest as _,removeAssetManifest as v,resolveAssetVariantFile as y,resolveAssetsConfig as b,setCatalogAsset as x,validateSource as S,writeCatalog as C,writeManifest as w}from"./project.js";import{assetCacheRoot as T,assetSourceKey as E,cacheAssetSourceFile as D,createB2AssetStore as O,materializeAssetSource as k,sha256File as A}from"./storage.js";import{assertVariantWidths as j,assetVariantWidths as M,buildAssetVariants as N,mediaTypeFor as P,readImageDimensions as F,variantWidthsProblem as I}from"./images.js";import{assetKindFor as L,buildPassthroughAsset as R,inspectAudio as z,inspectLottie as B,inspectSvg as V,inspectVideo as H,mediaTypeForAsset as U}from"./media.js";import{basename as W,dirname as G,join as K,relative as q,resolve as J,sep as Y}from"node:path";const X=K(`.coreframe/assets`,`asset-publish-report.json`);async function ee({alt:i,cacheDir:a,config:o,cwd:s=t.cwd(),env:c=t.env,file:l,id:u,pack:d,store:f,variantWidths:p}){n(u),d!==void 0&&r(d);let m=J(s,l),h=L(m),_=i?.trim();if((h===`image`||h===`svg`)&&!_)throw Error(`Raster images and SVG assets require non-empty alt text.`);if(h!==`image`&&p)throw Error(`Asset kind "${h}" does not support responsive variant widths.`);await ne(h,m,p);let v=await g(s,{allowMissing:!0,migrate:!0});if(v.problems.length>0)return{ok:!1,assets:[],fetched:[],problems:v.problems};let y=await b(s,o),S=f??O({config:y,env:c}),w=await A(m),k={digest:w,filename:W(l),mediaType:h===`image`?P(l):U(l,h),size:(await e.stat(m)).size},j=a??T(c),M=await D({cacheRoot:j,digest:w,env:c,source:m}),N=E(w);if(!await S.has(y.sourceBucket,N)&&(await S.upload(y.sourceBucket,N,M,k.mediaType),!await S.has(y.sourceBucket,N)))throw Error(`Backblaze B2 did not confirm source upload ${N}.`);return x(v.catalog,u,te({alt:_,kind:h,source:k,variantWidths:p}),d),await C(s,v.catalog),Z({cacheDir:j,config:y,cwd:s,env:c,id:v.migrated?void 0:u,pack:v.migrated?void 0:d,store:S})}function te({alt:e,kind:t,source:n,variantWidths:r}){return t===`image`?{kind:t,source:n,alt:e,...r?{variantWidths:r}:{}}:t===`svg`?{kind:t,source:n,alt:e}:{kind:t,source:n}}async function ne(e,t,n){if(e===`image`){j(n,(await F(t)).width),P(t);return}if(e===`svg`){await V(t);return}if(e===`audio`){await z(t);return}if(e===`video`){await H(t);return}await B(t)}async function Z({cacheDir:e,config:n,cwd:o=t.cwd(),env:s=t.env,id:l,pack:d,store:f,updateManifest:m=!0}={}){d!==void 0&&r(d);let y=await g(o,{migrate:!0}),x=[...y.problems],C=[],D=[];if(x.length>0)return{ok:!1,assets:C,fetched:D,problems:x};y.migrated&&(l=void 0,d=void 0);let A=i(y.catalog),j=l?u(y.catalog,l):void 0;if(l&&!j)return x.push({code:`REFERENCE_MISSING`,message:`Asset "${l}" is not present in ${c}.`,assetId:l,fix:`Run: coreframe assets add <file> --id ${l}`}),{ok:!1,assets:C,fetched:D,problems:x};if(l&&d!==void 0&&j?.pack!==d)return x.push({code:`REFERENCE_MISSING`,message:`Asset "${l}" is not present in asset pack "${d}".`,assetId:l,fix:`Build the asset without --pack or use its owning pack.`}),{ok:!1,assets:C,fetched:D,problems:x};let M=l?j?.pack:d;if(!l&&d!==void 0&&!y.catalog.packs?.[d])return x.push({code:`REFERENCE_MISSING`,message:`Asset pack "${d}" is not present in ${c}.`,fix:`Add an asset with --pack ${d}.`}),{ok:!1,assets:C,fetched:D,problems:x};let N=A.filter(e=>(l===void 0||e.assetId===l)&&(M===void 0?d===void 0||e.pack===void 0:e.pack===M)),P=l!==void 0||d!==void 0?[M]:[void 0,...a(y.catalog)],F=await b(o,n),I=f??O({config:F,env:s}),L=e??T(s),R=new Map;for(let e of P)if(l&&m){let t=await _(o,{allowMissing:!0,pack:e});if(t.problems.length>0)return{ok:!1,assets:C,fetched:D,problems:t.problems};R.set(e,t.manifest)}else R.set(e,re(e));for(let{assetId:e,entry:t,pack:n}of N){let r=S(e,t);if(r){x.push(r);continue}let i;try{i=await k({bucket:F.sourceBucket,cacheRoot:L,digest:t.source.digest,env:s,store:I})}catch(t){x.push({code:`SOURCE_UNAVAILABLE`,message:`Asset "${e}" source could not be materialized: ${t.message}`,assetId:e,fix:`Check the B2 asset configuration and credential profile "${F.credentialProfile}".`});continue}i.fetched&&D.push(E(t.source.digest));try{let r=await ie({assetId:e,config:F,cwd:o,entry:t,sourcePath:i.path});R.get(n).assets[e]=r,C.push({assetId:e,outputs:h(r)})}catch(n){x.push({code:`INVALID_MEDIA`,message:`Asset "${e}" could not be built: ${n.message}`,assetId:e,file:c,fix:`Replace the source with a supported ${t.kind} file, then run: coreframe assets build --id ${e}`})}}if(m&&x.length===0){for(let[e,t]of R)await w(o,t,e);if(l===void 0&&d===void 0){let e=new Set(a(y.catalog));for(let t of await p(o))e.has(t)||await v(o,t)}}return{ok:x.length===0,assets:C,fetched:D,problems:x}}function re(e){return{schemaVersion:2,...e===void 0?{}:{pack:e},assets:{}}}async function ie({assetId:e,config:t,cwd:n,entry:r,sourcePath:i}){if(r.kind===`image`){let a=await F(i),o=I(e,r,a.width);if(o)throw Error(o.message);let s=await N({assetId:e,config:t,cwd:n,entry:r,sourcePath:i,sourceDimensions:a});return{kind:`image`,sourceDigest:r.source.digest,alt:r.alt,...a,variants:s}}let a=await R({assetId:e,cwd:n,format:r.kind===`svg`?`svg`:r.kind===`audio`?`mp3`:r.kind===`video`?`mp4`:`json`,mediaType:r.source.mediaType,projectId:t.projectId,sourceDigest:r.source.digest,sourcePath:i});return r.kind===`svg`?{kind:`svg`,sourceDigest:r.source.digest,alt:r.alt,...await V(i),file:a}:r.kind===`audio`?{kind:`audio`,sourceDigest:r.source.digest,...await z(i),file:a}:r.kind===`video`?{kind:`video`,sourceDigest:r.source.digest,...await H(i),file:a}:{kind:`lottie`,sourceDigest:r.source.digest,...await B(i),file:a}}async function Q(e={}){let{cwd:n=t.cwd(),pack:o}=e;o!==void 0&&r(o);let l=await g(n),u=[...l.problems],d=new Set,v=u.length>0;if(u.some(e=>e.code===`SCHEMA_MIGRATION_REQUIRED`))return{ok:!1,catalog:l.catalog,expectedPrefix:``,manifests:new Map,problems:u,requiresFullBuild:!0,selectedEntries:[],staleAssetIds:[]};if(o!==void 0&&!l.catalog.packs?.[o])return u.push({code:`REFERENCE_MISSING`,message:`Asset pack "${o}" is not present in ${c}.`,fix:`Add an asset with --pack ${o}.`}),{ok:!1,catalog:l.catalog,expectedPrefix:``,manifests:new Map,problems:u,requiresFullBuild:!0,selectedEntries:[],staleAssetIds:[]};let y=o===void 0?[void 0,...a(l.catalog)]:[o],x=new Map;for(let e of y){let t=await _(n,{pack:e});u.push(...t.problems),v||=t.problems.length>0,x.set(e,t.manifest)}if(o===void 0){let e=new Set(a(l.catalog));for(let t of await p(n))e.has(t)||(u.push({code:`MANIFEST_STALE`,message:`Generated asset pack manifest "${t}" is not present in the catalog.`,file:s(t),fix:`Run: coreframe assets build`}),v=!0)}let S=`projects/${(await b(n,e.config)).projectId}/assets`,C=i(l.catalog).filter(e=>o===void 0||e.pack===o);for(let{assetId:e,entry:t,pack:n}of C){let r=s(n),i=x.get(n)?.assets[e];if(!i||!m(i,t)){u.push({code:`MANIFEST_STALE`,message:`Asset "${e}" is missing from the generated manifest or does not match its catalog entry.`,assetId:e,file:r,fix:`Run: coreframe assets build --id ${e}`}),d.add(e);continue}if(t.kind===`image`&&i.kind===`image`){let n=I(e,t,i.width);if(n)u.push(n),d.add(e);else{let n=M(t,i.width),a=i.variants.map(e=>e.width);(n.length!==a.length||!n.every((e,t)=>e===a[t]))&&(u.push({code:`MANIFEST_STALE`,message:`Asset "${e}" generated variants do not match its catalog widths.`,assetId:e,file:r,fix:`Run: coreframe assets build --id ${e}`}),d.add(e))}}for(let t of h(i))f(t.path,S)||(u.push({code:`INVALID_VARIANT_PATH`,message:`Asset "${e}" has an invalid generated output path.`,assetId:e,file:t.path,fix:`Run: coreframe assets build --id ${e}`}),d.add(e))}for(let[e,t]of x){let n=e===void 0?l.catalog.assets:l.catalog.packs?.[e]?.assets;for(let r of Object.keys(t.assets))n?.[r]||(u.push({code:`MANIFEST_STALE`,message:`Generated manifest asset "${r}" is not present in its catalog collection.`,assetId:r,file:s(e),fix:`Run: coreframe assets build`}),v=!0)}return{ok:u.length===0,catalog:l.catalog,expectedPrefix:S,manifests:x,problems:u,requiresFullBuild:v,selectedEntries:C,staleAssetIds:[...d].sort()}}async function ae(e={}){let{ok:t,problems:n,requiresFullBuild:r,staleAssetIds:i}=await Q(e);return{ok:t,problems:n,requiresFullBuild:r,staleAssetIds:i}}async function $(n={}){let{cwd:i=t.cwd(),fix:a=!1,pack:s}=n;if(s!==void 0&&r(s),a){let e=await Z(n);if(!e.ok)return{ok:!1,assets:[],problems:e.problems}}let d=await Q(n),{catalog:p,expectedPrefix:g,manifests:_,selectedEntries:v}=d,b=[...d.problems],x=[];if(b.some(e=>e.code===`SCHEMA_MIGRATION_REQUIRED`)||s!==void 0&&!p.packs?.[s])return{ok:!1,assets:x,problems:b};let C=await l(i);for(let{assetId:t,entry:n,pack:r}of v){o.test(t)||b.push({code:`INVALID_ASSET_ID`,message:`Asset ID "${t}" must use lowercase path segments.`,assetId:t,file:c}),(n.kind===`image`||n.kind===`svg`)&&!n.alt.trim()&&b.push({code:`INVALID_ALT`,message:`Asset "${t}" is missing alt text.`,assetId:t,file:c});let a=S(t,n);a&&b.push(a);let s=_.get(r)?.assets[t];if(!s||!m(s,n))continue;let l=await Promise.all(h(s).map(async t=>{let n=f(t.path,g),r=!1;if(n)try{let n=y(i,t.path);r=(await e.stat(n)).size===t.size&&await A(n)===t.hash}catch{r=!1}return{...t,exists:r}}));l.every(e=>e.exists)||b.push({code:`GENERATED_ASSET_MISSING`,message:`Asset "${t}" is missing its expected generated output.`,assetId:t,fix:`Run: coreframe assets build --id ${t}`}),x.push({assetId:t,source:n.source,outputs:l})}for(let e of C){let t=u(p,e.assetId);t?t.entry.kind!==`image`&&t.entry.kind!==`svg`&&b.push({code:`INVALID_REFERENCE`,message:`Markdown image reference "${e.assetId}" cannot use asset kind "${t.entry.kind}".`,assetId:e.assetId,file:e.file}):b.push({code:`INVALID_REFERENCE`,message:`Asset reference "${e.assetId}" is not present in ${c}.`,assetId:e.assetId,file:e.file,fix:`Run: coreframe assets add <file> --id ${e.assetId}`})}return{ok:b.length===0,assets:x,problems:b}}async function oe(n={}){let{cwd:r=t.cwd(),env:i=t.env,pack:o}=n,s=[...(await $(n)).problems],c=[],l=[],u=J(r,X);if(s.length===0){let e=await b(r,n.config),t=n.store??O({config:e,env:i}),{catalog:s}=await g(r),u=o===void 0?[void 0,...a(s)]:[o];for(let n of u){let{manifest:i}=await _(r,{pack:n});for(let[n,a]of Object.entries(i.assets))for(let i of h(a)){let a=y(r,i.path),o={assetId:n,source:q(r,a).split(Y).join(`/`),target:`${e.publicBucket}/${i.path}`,size:i.size};if(await t.has(e.publicBucket,i.path)){l.push(o);continue}await t.upload(e.publicBucket,i.path,a,i.mediaType),c.push(o)}}}let d={ok:s.length===0,uploaded:c,skipped:l,reportPath:u,problems:s};return await e.mkdir(G(u),{recursive:!0}),await e.writeFile(u,`${JSON.stringify(d,null,2)}\n`),d}async function se(e,t={}){return Z({...t,id:e})}function ce(e,t=!1){if(t){console.log(JSON.stringify(e,null,2));return}let n=e;n.problems?.length&&console.error(d(n.problems)),console.log(n.ok===!1?`Asset workflow has problems.`:`Asset workflow complete.`)}export{ee as addAsset,Z as buildAssets,ae as checkAssetManifests,$ as checkAssets,se as materializeAsset,ce as printAssetResult,oe as publishAssets};
1
+ import{fs as e,process as t}from"./environment.js";import{assertAssetId as n,assertAssetPackName as r,assetCatalogEntries as i,assetCatalogPackNames as a,assetIdPattern as o,assetManifestPath as s,catalogPath as c,findAssetReferences as l,findCatalogAsset as u,formatAssetProblems as d,isAssetVariantPath as f,listAssetManifestPacks as p,manifestEntryMatchesCatalog as m,manifestEntryOutputs as h,readAssetCatalog as g,readAssetManifest as _,removeAssetManifest as v,resolveAssetVariantFile as y,resolveAssetsConfig as b,setCatalogAsset as x,validateSource as S,writeCatalog as C,writeManifest as w}from"./project.js";import{assetCacheRoot as T,assetSourceKey as E,cacheAssetSourceFile as D,createB2AssetStore as O,materializeAssetSource as k,sha256File as A}from"./storage.js";import{assertVariantWidths as j,assetVariantWidths as M,buildAssetVariants as N,mediaTypeFor as P,readImageDimensions as F,variantWidthsProblem as I}from"./images.js";import{assetKindFor as L,buildPassthroughAsset as R,inspectAudio as z,inspectLottie as B,inspectSvg as V,inspectVideo as H,mediaTypeForAsset as U}from"./media.js";import{basename as W,dirname as G,join as K,relative as q,resolve as J,sep as Y}from"node:path";const X=K(`.coreframe/assets`,`asset-publish-report.json`);async function ee({alt:i,cacheDir:a,config:o,cwd:s=t.cwd(),env:c=t.env,file:l,id:u,pack:d,store:f,variantWidths:p}){n(u),d!==void 0&&r(d);let m=J(s,l),h=L(m),_=i?.trim();if((h===`image`||h===`svg`)&&!_)throw Error(`Raster images and SVG assets require non-empty alt text.`);if(h!==`image`&&p)throw Error(`Asset kind "${h}" does not support responsive variant widths.`);await ne(h,m,p);let v=await g(s,{allowMissing:!0,migrate:!0});if(v.problems.length>0)return{ok:!1,assets:[],fetched:[],problems:v.problems};let y=await b(s,o),S=f??O({config:y,env:c}),w=await A(m),k={digest:w,filename:W(l),mediaType:h===`image`?P(l):U(l,h),size:(await e.stat(m)).size},j=a??T(c),M=await D({cacheRoot:j,digest:w,env:c,source:m}),N=E(w);if(!await S.has(y.sourceBucket,N)&&(await S.upload(y.sourceBucket,N,M,k.mediaType),!await S.has(y.sourceBucket,N)))throw Error(`Backblaze B2 did not confirm source upload ${N}.`);return x(v.catalog,u,te({alt:_,kind:h,source:k,variantWidths:p}),d),await C(s,v.catalog),Z({cacheDir:j,config:y,cwd:s,env:c,id:v.migrated?void 0:u,pack:v.migrated?void 0:d,store:S})}function te({alt:e,kind:t,source:n,variantWidths:r}){return t===`image`?{kind:t,source:n,alt:e,...r?{variantWidths:r}:{}}:t===`svg`?{kind:t,source:n,alt:e}:{kind:t,source:n}}async function ne(e,t,n){if(e===`image`){j(n,(await F(t)).width),P(t);return}if(e===`svg`){await V(t);return}if(e===`audio`){await z(t);return}if(e===`video`){await H(t);return}await B(t)}async function Z({cacheDir:e,config:n,cwd:o=t.cwd(),env:s=t.env,id:l,pack:d,store:f,updateManifest:m=!0}={}){d!==void 0&&r(d);let y=await g(o,{migrate:!0}),x=[...y.problems],C=[],D=[];if(x.length>0)return{ok:!1,assets:C,fetched:D,problems:x};y.migrated&&(l=void 0,d=void 0);let A=i(y.catalog),j=l?u(y.catalog,l):void 0;if(l&&!j)return x.push({code:`REFERENCE_MISSING`,message:`Asset "${l}" is not present in ${c}.`,assetId:l,fix:`Run: coreframe assets add <file> --id ${l}`}),{ok:!1,assets:C,fetched:D,problems:x};if(l&&d!==void 0&&j?.pack!==d)return x.push({code:`REFERENCE_MISSING`,message:`Asset "${l}" is not present in asset pack "${d}".`,assetId:l,fix:`Build the asset without --pack or use its owning pack.`}),{ok:!1,assets:C,fetched:D,problems:x};let M=l?j?.pack:d;if(!l&&d!==void 0&&!y.catalog.packs?.[d])return x.push({code:`REFERENCE_MISSING`,message:`Asset pack "${d}" is not present in ${c}.`,fix:`Add an asset with --pack ${d}.`}),{ok:!1,assets:C,fetched:D,problems:x};let N=A.filter(e=>(l===void 0||e.assetId===l)&&(M===void 0?d===void 0||e.pack===void 0:e.pack===M)),P=l!==void 0||d!==void 0?[M]:[void 0,...a(y.catalog)],F=await b(o,n),I=f??O({config:F,env:s}),L=e??T(s),R=new Map;for(let e of P)if(l&&m){let t=await _(o,{allowMissing:!0,pack:e});if(t.problems.length>0)return{ok:!1,assets:C,fetched:D,problems:t.problems};R.set(e,t.manifest)}else R.set(e,re(e));for(let{assetId:e,entry:t,pack:n}of N){let r=S(e,t);if(r){x.push(r);continue}let i;try{i=await k({bucket:F.sourceBucket,cacheRoot:L,digest:t.source.digest,env:s,store:I})}catch(t){x.push({code:`SOURCE_UNAVAILABLE`,message:`Asset "${e}" source could not be materialized: ${t.message}`,assetId:e,fix:`Check the B2 asset configuration and credential profile "${F.credentialProfile}".`});continue}i.fetched&&D.push(E(t.source.digest));try{let r=await ie({assetId:e,config:F,cwd:o,entry:t,sourcePath:i.path});R.get(n).assets[e]=r,C.push({assetId:e,outputs:h(r)})}catch(n){x.push({code:`INVALID_MEDIA`,message:`Asset "${e}" could not be built: ${n.message}`,assetId:e,file:c,fix:`Replace the source with a supported ${t.kind} file, then run: coreframe assets build --id ${e}`})}}if(m&&x.length===0){for(let[e,t]of R)await w(o,t,e);if(l===void 0&&d===void 0){let e=new Set(a(y.catalog));for(let t of await p(o))e.has(t)||await v(o,t)}}return{ok:x.length===0,assets:C,fetched:D,problems:x}}function re(e){return{schemaVersion:2,...e===void 0?{}:{pack:e},assets:{}}}async function ie({assetId:e,config:t,cwd:n,entry:r,sourcePath:i}){if(r.kind===`image`){let a=await F(i),o=I(e,r,a.width);if(o)throw Error(o.message);let s=await N({assetId:e,config:t,cwd:n,entry:r,sourcePath:i,sourceDimensions:a});return{kind:`image`,sourceDigest:r.source.digest,alt:r.alt,...a,variants:s}}let a=await R({assetId:e,cwd:n,format:r.kind===`svg`?`svg`:r.kind===`audio`?`mp3`:r.kind===`video`?`mp4`:`json`,mediaType:r.source.mediaType,projectId:t.projectId,sourceDigest:r.source.digest,sourcePath:i});return r.kind===`svg`?{kind:`svg`,sourceDigest:r.source.digest,alt:r.alt,...await V(i),file:a}:r.kind===`audio`?{kind:`audio`,sourceDigest:r.source.digest,...await z(i),file:a}:r.kind===`video`?{kind:`video`,sourceDigest:r.source.digest,...await H(i),file:a}:{kind:`lottie`,sourceDigest:r.source.digest,...await B(i),file:a}}async function Q(e={}){let{cwd:n=t.cwd(),pack:o}=e;o!==void 0&&r(o);let l=await g(n),u=[...l.problems],d=new Set,v=u.length>0;if(u.some(e=>e.code===`SCHEMA_MIGRATION_REQUIRED`))return{ok:!1,catalog:l.catalog,expectedPrefix:``,manifests:new Map,problems:u,requiresFullBuild:!0,selectedEntries:[],staleAssetIds:[]};if(o!==void 0&&!l.catalog.packs?.[o])return u.push({code:`REFERENCE_MISSING`,message:`Asset pack "${o}" is not present in ${c}.`,fix:`Add an asset with --pack ${o}.`}),{ok:!1,catalog:l.catalog,expectedPrefix:``,manifests:new Map,problems:u,requiresFullBuild:!0,selectedEntries:[],staleAssetIds:[]};let y=o===void 0?[void 0,...a(l.catalog)]:[o],x=new Map;for(let e of y){let t=await _(n,{pack:e});u.push(...t.problems),v||=t.problems.length>0,x.set(e,t.manifest)}if(o===void 0){let e=new Set(a(l.catalog));for(let t of await p(n))e.has(t)||(u.push({code:`MANIFEST_STALE`,message:`Generated asset pack manifest "${t}" is not present in the catalog.`,file:s(t),fix:`Run: coreframe assets build`}),v=!0)}let S=`projects/${(await b(n,e.config)).projectId}/assets`,C=i(l.catalog).filter(e=>o===void 0||e.pack===o);for(let{assetId:e,entry:t,pack:n}of C){let r=s(n),i=x.get(n)?.assets[e];if(!i||!m(i,t)){u.push({code:`MANIFEST_STALE`,message:`Asset "${e}" is missing from the generated manifest or does not match its catalog entry.`,assetId:e,file:r,fix:`Run: coreframe assets build --id ${e}`}),d.add(e);continue}if(t.kind===`image`&&i.kind===`image`){let n=I(e,t,i.width);if(n)u.push(n),d.add(e);else{let n=M(t,i.width),a=i.variants.map(e=>e.width);(n.length!==a.length||!n.every((e,t)=>e===a[t]))&&(u.push({code:`MANIFEST_STALE`,message:`Asset "${e}" generated variants do not match its catalog widths.`,assetId:e,file:r,fix:`Run: coreframe assets build --id ${e}`}),d.add(e))}}for(let t of h(i))f(t.path,S)||(u.push({code:`INVALID_VARIANT_PATH`,message:`Asset "${e}" has an invalid generated output path.`,assetId:e,file:t.path,fix:`Run: coreframe assets build --id ${e}`}),d.add(e))}for(let[e,t]of x){let n=e===void 0?l.catalog.assets:l.catalog.packs?.[e]?.assets;for(let r of Object.keys(t.assets))n?.[r]||(u.push({code:`MANIFEST_STALE`,message:`Generated manifest asset "${r}" is not present in its catalog collection.`,assetId:r,file:s(e),fix:`Run: coreframe assets build`}),v=!0)}return{ok:u.length===0,catalog:l.catalog,expectedPrefix:S,manifests:x,problems:u,requiresFullBuild:v,selectedEntries:C,staleAssetIds:[...d].sort()}}async function ae(e={}){let{ok:t,problems:n,requiresFullBuild:r,staleAssetIds:i}=await Q(e);return{ok:t,problems:n,requiresFullBuild:r,staleAssetIds:i}}async function $(n={}){let{cwd:i=t.cwd(),fix:a=!1,pack:s}=n;if(s!==void 0&&r(s),a){let e=await Z(n);if(!e.ok)return{ok:!1,assets:[],problems:e.problems}}let d=await Q(n),{catalog:p,expectedPrefix:g,manifests:_,selectedEntries:v}=d,b=[...d.problems],x=[];if(b.some(e=>e.code===`SCHEMA_MIGRATION_REQUIRED`)||s!==void 0&&!p.packs?.[s])return{ok:!1,assets:x,problems:b};let C=await l(i);for(let{assetId:t,entry:n,pack:r}of v){o.test(t)||b.push({code:`INVALID_ASSET_ID`,message:`Asset ID "${t}" must use lowercase path segments.`,assetId:t,file:c}),(n.kind===`image`||n.kind===`svg`)&&!n.alt.trim()&&b.push({code:`INVALID_ALT`,message:`Asset "${t}" is missing alt text.`,assetId:t,file:c});let a=S(t,n);a&&b.push(a);let s=_.get(r)?.assets[t];if(!s||!m(s,n))continue;let l=await Promise.all(h(s).map(async t=>{let n=f(t.path,g),r=!1;if(n)try{let n=y(i,t.path);r=(await e.stat(n)).size===t.size&&await A(n)===t.hash}catch{r=!1}return{...t,exists:r}}));l.every(e=>e.exists)||b.push({code:`GENERATED_ASSET_MISSING`,message:`Asset "${t}" is missing its expected generated output.`,assetId:t,fix:`Run: coreframe assets build --id ${t}`}),x.push({assetId:t,source:n.source,outputs:l})}for(let e of C){let t=u(p,e.assetId);t?t.entry.kind!==`image`&&t.entry.kind!==`svg`&&b.push({code:`INVALID_REFERENCE`,message:`Markdown image reference "${e.assetId}" cannot use asset kind "${t.entry.kind}".`,assetId:e.assetId,file:e.file}):b.push({code:`INVALID_REFERENCE`,message:`Asset reference "${e.assetId}" is not present in ${c}.`,assetId:e.assetId,file:e.file,fix:`Run: coreframe assets add <file> --id ${e.assetId}`})}return{ok:b.length===0,assets:x,problems:b}}async function oe(n={}){let{cwd:r=t.cwd(),env:i=t.env,pack:o}=n,s=[...(await $(n)).problems],c=[],l=[],u=J(r,X);if(s.length===0){let e=await b(r,n.config),t=n.store??O({config:e,env:i}),{catalog:s}=await g(r),u=o===void 0?[void 0,...a(s)]:[o];for(let n of u){let{manifest:i}=await _(r,{pack:n});for(let[n,a]of Object.entries(i.assets))for(let i of h(a)){let a=y(r,i.path),o={assetId:n,source:q(r,a).split(Y).join(`/`),target:`${e.publicBucket}/${i.path}`,size:i.size};if(await t.has(e.publicBucket,i.path)){l.push(o);continue}await t.upload(e.publicBucket,i.path,a,i.mediaType),c.push(o)}}}let d={ok:s.length===0,uploaded:c,skipped:l,reportPath:u,problems:s};return await e.mkdir(G(u),{recursive:!0}),await e.writeFile(u,`${JSON.stringify(d,null,2)}\n`),d}async function se(e,t={}){return Z({...t,id:e})}function ce(e,t=!1,n){if(t){console.log(JSON.stringify(e,null,2));return}let r=e;r.problems?.length&&console.error(d(r.problems));let i=r.problems?.length??0,a=r.assets?.length??0,o=r.uploaded?.length??0,s=r.skipped?.length??0,c=(e,t)=>`${e} ${t}${e===1?``:`s`}`,l;if(r.ok===!1)switch(n?.kind){case`add`:l=`Could not add and build asset "${n.assetId}".`;break;case`build`:l=`Asset build found ${c(i,`problem`)}.`;break;case`check`:case`status`:l=`Asset verification found ${c(i,`problem`)}.`;break;case`publish`:l=`Asset publishing stopped because verification found ${c(i,`problem`)}.`;break;default:l=`Asset workflow has problems.`}else switch(n?.kind){case`add`:l=`Added and built asset "${n.assetId}".`;break;case`build`:l=`Built ${c(a,`asset`)}.`;break;case`check`:l=`Verified ${c(a,`asset`)}.`;break;case`publish`:l=`Published ${c(o,`asset file`)}.`,s>0&&(l+=` ${c(s,`file`)} already existed.`);break;case`status`:l=a===1?`The asset is valid.`:`All ${c(a,`asset`)} are valid.`;break;default:l=`Asset workflow complete.`}console.log(l)}export{ee as addAsset,Z as buildAssets,ae as checkAssetManifests,$ as checkAssets,se as materializeAsset,ce as printAssetResult,oe as publishAssets};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreframe/assets",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Asset processing and object-storage workflows for Coreframe apps",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,8 +22,8 @@
22
22
  "music-metadata": "^11.14.0",
23
23
  "nano-spawn": "^2.1.0",
24
24
  "saxes": "^6.0.0",
25
- "@coreframe/object-storage": "^0.1.4",
26
- "@coreframe/config": "^0.1.8"
25
+ "@coreframe/config": "^0.1.9",
26
+ "@coreframe/object-storage": "^0.1.4"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^26.1.0",