@enslo/sd-parsers-web 1.0.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.
Files changed (48) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.txt +21 -0
  3. package/README.md +221 -0
  4. package/dist/data/generators.d.ts +12 -0
  5. package/dist/data/generators.d.ts.map +1 -0
  6. package/dist/data/index.d.ts +10 -0
  7. package/dist/data/index.d.ts.map +1 -0
  8. package/dist/data/model.d.ts +25 -0
  9. package/dist/data/model.d.ts.map +1 -0
  10. package/dist/data/prompt.d.ts +20 -0
  11. package/dist/data/prompt.d.ts.map +1 -0
  12. package/dist/data/promptInfo.d.ts +56 -0
  13. package/dist/data/promptInfo.d.ts.map +1 -0
  14. package/dist/data/sampler.d.ts +24 -0
  15. package/dist/data/sampler.d.ts.map +1 -0
  16. package/dist/exceptions.d.ts +13 -0
  17. package/dist/exceptions.d.ts.map +1 -0
  18. package/dist/extractors/eagerness.d.ts +9 -0
  19. package/dist/extractors/eagerness.d.ts.map +1 -0
  20. package/dist/extractors/extractors.d.ts +30 -0
  21. package/dist/extractors/extractors.d.ts.map +1 -0
  22. package/dist/extractors/index.d.ts +14 -0
  23. package/dist/extractors/index.d.ts.map +1 -0
  24. package/dist/imageUtils.d.ts +16 -0
  25. package/dist/imageUtils.d.ts.map +1 -0
  26. package/dist/index.d.ts +23 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/parserManager.d.ts +26 -0
  29. package/dist/parserManager.d.ts.map +1 -0
  30. package/dist/parsers/automatic1111.d.ts +10 -0
  31. package/dist/parsers/automatic1111.d.ts.map +1 -0
  32. package/dist/parsers/comfyui.d.ts +10 -0
  33. package/dist/parsers/comfyui.d.ts.map +1 -0
  34. package/dist/parsers/dummy.d.ts +10 -0
  35. package/dist/parsers/dummy.d.ts.map +1 -0
  36. package/dist/parsers/fooocus.d.ts +10 -0
  37. package/dist/parsers/fooocus.d.ts.map +1 -0
  38. package/dist/parsers/index.d.ts +17 -0
  39. package/dist/parsers/index.d.ts.map +1 -0
  40. package/dist/parsers/invokeai.d.ts +13 -0
  41. package/dist/parsers/invokeai.d.ts.map +1 -0
  42. package/dist/parsers/novelai.d.ts +10 -0
  43. package/dist/parsers/novelai.d.ts.map +1 -0
  44. package/dist/parsers/parser.d.ts +38 -0
  45. package/dist/parsers/parser.d.ts.map +1 -0
  46. package/dist/sd-parsers-web.es.js +751 -0
  47. package/dist/sd-parsers-web.umd.js +4 -0
  48. package/package.json +62 -0
@@ -0,0 +1,4 @@
1
+ (function(m,T){typeof exports=="object"&&typeof module<"u"?T(exports,require("png-chunks-extract"),require("exifr")):typeof define=="function"&&define.amd?define(["exports","png-chunks-extract","exifr"],T):(m=typeof globalThis<"u"?globalThis:m||self,T(m.SDParsersWeb={},m.pngChunksExtract,m.exifr))})(this,function(m,T,W){"use strict";class h extends Error{constructor(t){super(t),this.name="ParserError"}}class v extends h{constructor(t){super(t),this.name="MetadataError"}}var y=(n=>(n[n.FAST=1]="FAST",n[n.DEFAULT=2]="DEFAULT",n[n.EAGER=3]="EAGER",n))(y||{}),P=(n=>(n.AUTOMATIC1111="AUTOMATIC1111",n.COMFYUI="ComfyUI",n.FOOOCUS="Fooocus",n.INVOKEAI="InvokeAI",n.NOVELAI="NovelAI",n.UNKNOWN="unknown",n))(P||{});function k(n){const{name:t,hash:e,modelId:r,metadata:s={}}=n;if(!t&&!e)throw new Error("Either name or hash need to be given.");return{name:t,hash:e,modelId:r,metadata:s}}function B(n){return n.name&&n.hash?`${n.name} (${n.hash})`:n.name||n.hash||""}function g(n,t={}){const{promptId:e,metadata:r={}}=t;return{value:n,promptId:e,metadata:r}}function N(n){return n.value}function A(n,t={},e={}){const{samplerId:r,model:s,prompts:a=[],negativePrompts:o=[]}=e;return{name:n,parameters:t,samplerId:r,model:s,prompts:a,negativePrompts:o}}function w(n,t,e={},r={}){return{generator:n,samplers:t,metadata:e,rawParameters:r}}function M(n){return n.metadata.full_prompt?n.metadata.full_prompt:C(n).map(N).join(", ")}function b(n){return n.metadata.full_negative_prompt?n.metadata.full_negative_prompt:U(n).map(N).join(", ")}function C(n){const t=new Set,e=[];for(const r of n.samplers)for(const s of r.prompts){const a=`${s.promptId||""}:${s.value}`;t.has(a)||(t.add(a),e.push(s))}return e}function U(n){const t=new Set,e=[];for(const r of n.samplers)for(const s of r.negativePrompts){const a=`${s.promptId||""}:${s.value}`;t.has(a)||(t.add(a),e.push(s))}return e}function X(n){const t=new Set,e=[];for(const r of n.samplers)if(r.model){const s=`${r.model.modelId||""}:${r.model.name||""}:${r.model.hash||""}`;t.has(s)||(t.add(s),e.push(r.model))}return e}function D(n){return{full_prompt:M(n),full_negative_prompt:b(n),generator:n.generator,samplers:n.samplers,metadata:n.metadata,rawParameters:n.rawParameters}}function Y(n){return JSON.stringify(D(n))}async function q(n,t){try{const e={};return Object.keys(e).length>0?e:null}catch(e){throw new v(`Error reading PNG metadata: ${e}`)}}async function H(n,t){try{const r=T(n).filter(a=>a.name==="tEXt"||a.name==="zTXt"||a.name==="iTXt");if(r.length===0)return null;const s={};for(const a of r)try{let o,i;if(a.name==="tEXt"){const p=a.data,c=p.indexOf(0);if(c===-1)continue;i=new TextDecoder("latin1").decode(p.subarray(0,c)),o=new TextDecoder("latin1").decode(p.subarray(c+1))}else{if(a.name==="zTXt")continue;if(a.name==="iTXt")continue;continue}i&&o&&(s[i]=o,i.toLowerCase()==="parameters"&&(s.parameters=o))}catch{continue}return Object.keys(s).length>0?s:null}catch(e){throw new v(`Error reading PNG text chunks: ${e}`)}}async function Z(n,t){try{return null}catch(e){throw new v(`Error reading stenographic alpha: ${e}`)}}async function $(n,t){try{const e=await W.parse(n,{userComment:!0,pick:["userComment"]}),r=(e==null?void 0:e.userComment)||(e==null?void 0:e.UserComment)||(e==null?void 0:e["0x9286"]);if(r){if(r instanceof Uint8Array){const s=r.slice(0,8),a=new TextDecoder("ascii").decode(s).replace(/\0/g,""),o=r.slice(8);let i;return a==="UNICODE"?i=new TextDecoder("utf-16be").decode(o):a==="ASCII"?i=new TextDecoder("ascii").decode(o):i=new TextDecoder("utf-8").decode(o),t===P.AUTOMATIC1111||t===P.FOOOCUS?{parameters:i}:{userComment:i}}return typeof r=="string"?{parameters:r}:null}return null}catch(e){if(t===P.AUTOMATIC1111||t===P.FOOOCUS)return null;throw new v(`Error reading JPEG UserComment: ${e}`)}}const Q={PNG:{[y.FAST]:[q],[y.DEFAULT]:[H],[y.EAGER]:[Z]},JPEG:{[y.FAST]:[$],[y.DEFAULT]:[],[y.EAGER]:[]},WEBP:{[y.FAST]:[$],[y.DEFAULT]:[],[y.EAGER]:[]}};class S{constructor(t=!0,e=!1){this.generator=P.UNKNOWN,this.doNormalizationPass=t,this.debug=e}normalizeParameters(t,e,r=!0,s=!0){if(!this.doNormalizationPass)return Array.isArray(t)?Object.fromEntries(t):t;const a=Array.isArray(t)?Object.fromEntries(t):{...t},o={};if(e)for(const i of e){const[p,c]=i;if(typeof c=="string")p in a&&(o[c]=a[p],delete a[p]);else{const[l,u]=c;if(p in a){const d={};for(const E of l)E in a&&(d[E]=a[E]);let f=u;for(const[E,O]of Object.entries(d))f=f.replace(new RegExp(`\\{${E}\\}`,"g"),String(O));o[p]=f}}}for(let[i,p]of Object.entries(a))r&&(i=i.toLowerCase()),s&&(i=i.replace(/\s+/g,"_")),o[i]=p;return o}}function _(n,t){const e=[];for(const r of n)r in t&&(e.push([r,t[r]]),delete t[r]);return e}const j=["Sampler","CFG scale","Seed","Steps","ENSD","Schedule type","Denoising strength","Clip skip"],ee=[["Schedule type","scheduler"],["CFG scale","cfg_scale"],["Seed","seed"],["Steps","steps"],["Denoising strength","denoising_strength"],["Clip skip","clip_skip"]];class L extends S{constructor(){super(...arguments),this.generator=P.AUTOMATIC1111}async parse(t){var r,s,a,o;let e;try{if(!t.parameters||typeof t.parameters!="string")throw new Error("parameters field is missing or not a string");e=t.parameters.split(`
2
+ `)}catch(i){throw new h(`Error reading parameter string: ${i}`)}try{const{infoIndex:i,samplerInfo:p,metadata:c}=te(e),l=e.slice(0,i).join(`
3
+ `).split("Negative prompt:"),u=((r=l[0])==null?void 0:r.trim())||"",d=((s=l[1])==null?void 0:s.trim())||"",f=Object.fromEntries(_(j,p)),E=f.Sampler||"unknown";delete f.Sampler;const O=this.normalizeParameters(f,ee),K=c.Model,V=c["Model hash"];delete c.Model,delete c["Model hash"];const he=K||V?k({name:K,hash:V}):void 0,ge=u?[g(u)]:[],ye=d?[g(d)]:[],Pe=A(E,O,{model:he,prompts:ge,negativePrompts:ye});return w(this.generator,[Pe],c,t)}catch{const c=e.join(`
4
+ `).split("Negative prompt:"),l=((a=c[0])==null?void 0:a.trim())||"",u=((o=c[1])==null?void 0:o.trim())||"",d=l?[g(l)]:[],f=u?[g(u)]:[],E=A("unknown",{},{prompts:d,negativePrompts:f});return w(this.generator,[E],{},t)}}}function te(n){for(let t=n.length-1;t>=0;t--){const e=n[t],r=re(e),s=Object.fromEntries(_(j,{...r}));if(Object.keys(s).length>=3)return{infoIndex:t,samplerInfo:s,metadata:r}}throw new h("No sampler information found")}function re(n){const t={},e=n.match(/(?:,\s*)?Hashes:\s*(\{[^}]*\})\s*/);if(e)try{t.Hashes=JSON.parse(e[1]),n=n.substring(0,e.index)+n.substring(e.index+e[0].length)}catch{}for(const r of n.split(","))try{const s=r.indexOf(":");if(s>0){const a=r.substring(0,s).trim(),o=r.substring(s+1).trim();t[a]=o}}catch{}return t}const se=["guidance_scale","cfg_scale","scheduler","seed","sharpness","steps"],ne=[["guidance_scale","cfg_scale"]];class R extends S{constructor(){super(...arguments),this.generator=P.FOOOCUS}async parse(t){let e;try{if(!t.hasOwnProperty("parameters"))throw new Error("parameters field is missing");if(typeof t.parameters=="string")e=JSON.parse(t.parameters);else throw typeof t.parameters=="object"&&t.parameters!==null?new Error("parameters field is missing"):new Error("parameters field is missing")}catch(r){throw new h(`Error decoding parameter data: ${r}`)}try{const r=e.base_model||e.base_model_hash?k({name:e.base_model,hash:e.base_model_hash}):void 0;delete e.base_model,delete e.base_model_hash;const s=Object.fromEntries(_(se,e)),a=this.normalizeParameters(s,ne),o=e.sampler||"unknown";delete e.sampler;const i=e.prompt;delete e.prompt;const p=e.negative_prompt;delete e.negative_prompt;const c=i?[g(i)]:[],l=p?[g(p)]:[],u=A(o,a,{model:r,prompts:c,negativePrompts:l});return w(this.generator,[u],e,t)}catch(r){throw new h(`Error reading parameter value: ${r}`)}}}const oe=["WanVideoSampler"],ae=new Set(["sampler_name","steps","cfg"]),ie=[],ce=["text","positive"],pe=["text","negative"],F=["ConditioningCombine"];class x extends S{constructor(){super(...arguments),this.generator=P.COMFYUI}async parse(t){let e,r;try{e=t.prompt,typeof e=="string"&&(e=JSON.parse(e)),r=t.workflow,typeof r=="string"&&(r=JSON.parse(r))}catch(o){throw new h(`Error reading parameters: ${o}`)}const{samplers:s,metadata:a}=I.extract(this,e,r);return w(this.generator,s,a,t)}}class I{constructor(t,e,r={}){this.parser=t,this.processedNodes=new Set;try{this.prompt={};for(const[s,a]of Object.entries(e))this.prompt[String(s)]=a}catch(s){throw new h(`Prompt has unexpected format: ${s}`)}this.links={};try{if(r&&r.links&&Array.isArray(r.links)){for(const s of r.links)if(Array.isArray(s)&&s.length>=6){const[,a,,o,,i]=s,p=String(o),c=String(a);this.links[p]||(this.links[p]={}),this.links[p][c]||(this.links[p][c]=new Set),this.links[p][c].add(i)}}}catch(s){throw new h(`Workflow has unexpected format: ${s}`)}}static extract(t,e,r={}){const s=new I(t,e,r),a=[],o={};for(const[i,p]of Object.entries(s.prompt)){const c=s.tryGetSampler(i,p);c&&a.push(c)}for(const[i,p]of Object.entries(s.prompt))if(!s.processedNodes.has(i))try{if(p.inputs){const c=s.getInputValues(p.inputs,i);if(c&&Object.keys(c).length>0){const l=p.class_type;o[l]||(o[l]=[]),o[l].push(c)}}}catch{}return{samplers:a,metadata:o}}tryStepInto(t,e){var r;for(const s of e)try{const a=(r=t[s])==null?void 0:r[0];if(a&&this.prompt[a]){const o=this.prompt[a];if(o.inputs)return{...o.inputs}}}catch{continue}return t}tryGetSampler(t,e){try{const c={...e.inputs},l=e.class_type;if(!oe.includes(l)&&!this.hasSamplerParams(c))return null}catch{return null}this.parser.debug&&console.log(`Found sampler #${t}`),this.processedNodes.add(t);const r={...e.inputs},s=r.sampler_name||r.scheduler||"unknown";delete r.sampler_name,delete r.scheduler;const a=this.parser.normalizeParameters(this.getInputValues(r),ie),o=this.getModel(t),{prompts:i,negativePrompts:p}=this.getPrompts(t);return A(s,a,{samplerId:t,model:o,prompts:i,negativePrompts:p})}hasSamplerParams(t){const e=new Set(Object.keys(t));for(const r of ae)if(e.has(r))return!0;return!1}getModel(t){try{const e=this.getTrace([t],["MODEL"]),r=this.getTraceMetadata(e);for(const[s,a]of Object.entries(r))if((s.includes("Checkpoint")||s.includes("Model"))&&Array.isArray(a)&&a.length>0){const o=a[0];if(typeof o=="object"&&o.ckpt_name)return k({name:o.ckpt_name})}}catch{}}getPrompts(t){const e=[],r=[];try{const s=this.getTrace([t],["CONDITIONING"]),a=this.getTraceMetadata(s);for(const[o,i]of Object.entries(a))if(!F.includes(o)&&Array.isArray(i)){for(const p of i)if(typeof p=="object"){for(const c of ce)p[c]&&typeof p[c]=="string"&&e.push(g(p[c]));for(const c of pe)p[c]&&typeof p[c]=="string"&&r.push(g(p[c]))}}}catch{}return{prompts:e,negativePrompts:r}}getTrace(t,e){const r=new Set,s=[],a=o=>{if(r.has(o))return;r.add(o),s.push(o);const i=this.links[o];if(i)for(const[p,c]of Object.entries(i))for(const l of e)c.has(l)&&a(p)};for(const o of t)a(o);return s}getTraceMetadata(t){const e={};for(const r of t)try{const s=this.prompt[r];if(!s)continue;const a=s.class_type;if(F.includes(a))continue;const o=this.getInputValues(s.inputs,r);if(!o||Object.keys(o).length===0)continue;e[a]?Array.isArray(e[a])?e[a].push(o):e[a]=[e[a],o]:e[a]=o}catch{continue}return e}getInputValues(t,e){try{const r={};for(const[s,a]of Object.entries(t))Array.isArray(a)||(r[s]=a);if(Object.keys(r).length>0)return e?{id:e,...r}:r}catch{}return{}}}class G extends S{constructor(){super(...arguments),this.generator=P.INVOKEAI}async parse(t){if(t["sd-metadata"])return this.parseSdMetadata(t["sd-metadata"]);if(t.Dream)return this.parseDream(t.Dream);if(t.invokeai_metadata||t.invokeai_graph)return this.parseInvokeAiMeta(t);throw new h("No supported InvokeAI metadata format found")}parseSdMetadata(t){var e;try{const r=typeof t=="string"?JSON.parse(t):t,s=r.sampler_name||((e=r.image)==null?void 0:e.sampler)||r.sampler||"unknown",a={},o=r.image||r;o.cfg_scale!==void 0&&(a.cfg_scale=o.cfg_scale),o.steps!==void 0&&(a.steps=o.steps),o.seed!==void 0&&(a.seed=o.seed),o.width!==void 0&&(a.width=o.width),o.height!==void 0&&(a.height=o.height);const i=r.prompt||o.prompt?[g(r.prompt||o.prompt)]:[],p=r.negative_prompt||o.negative_prompt?[g(r.negative_prompt||o.negative_prompt)]:[],c=A(s,a,{prompts:i,negativePrompts:p});return w(this.generator,[c],r,{"sd-metadata":t})}catch(r){throw new h(`Error parsing sd-metadata: ${r}`)}}parseDream(t){try{let e=t.match(/^"(.*?)"(.*)$/),r,s;if(e)[,r,s]=e;else{const l=t.indexOf(" -");l!==-1?(r=t.substring(0,l),s=t.substring(l)):(r=t,s="")}const a={},o={};if(s){const l=s.matchAll(/-(\w+)\s+([^\s-]+)/g);for(const u of l){const[,d,f]=u;switch(d){case"A":o.sampler=f;break;case"C":o.cfg_scale=f;break;case"H":o.height=f;break;case"s":o.steps=f;break;case"S":o.seed=f;break;case"W":o.width=f;break;default:a[d]=f}}}const i=o.sampler||"unknown";delete o.sampler;const p=r?[g(r)]:[],c=A(i,o,{prompts:p});return w(this.generator,[c],a,{Dream:t})}catch(e){throw new h(`Error parsing Dream format: ${e}`)}}parseInvokeAiMeta(t){try{let e={};t.invokeai_metadata&&(e=typeof t.invokeai_metadata=="string"?JSON.parse(t.invokeai_metadata):t.invokeai_metadata);const r=e.sampler_name||e.scheduler||"unknown",s={};e.cfg_scale!==void 0&&(s.cfg_scale=e.cfg_scale),e.steps!==void 0&&(s.steps=e.steps),e.seed!==void 0&&(s.seed=e.seed),e.width!==void 0&&(s.width=e.width),e.height!==void 0&&(s.height=e.height);const a=e.positive_prompt||e.prompt?[g(e.positive_prompt||e.prompt)]:[],o=e.negative_prompt?[g(e.negative_prompt)]:[],i=A(r,s,{prompts:a,negativePrompts:o});return w(this.generator,[i],e,t)}catch(e){throw new h(`Error parsing InvokeAI metadata: ${e}`)}}}const me=["seed","strength","noise","scale","steps"],le=[];class J extends S{constructor(){super(...arguments),this.generator=P.NOVELAI}async parse(t){let e,r,s;try{t.parameters?(typeof t.parameters=="string"?e=JSON.parse(t.parameters):e=t.parameters,r=e.prompt||"",s=e.source||""):(e=JSON.parse(t.Comment||"{}"),r=t.Description||"",s=t.Source||"")}catch(o){throw new h(`Error reading parameter values: ${o}`)}let a;try{if(a=e.sampler,!a)throw new Error("Sampler name not found");delete e.sampler;const o=Object.fromEntries(_(me,e)),i=this.normalizeParameters(o,le),p=r!=null&&r.trim()?[g(r.trim())]:[],c=e.uc;delete e.uc;const l=c?[g(c)]:[];let u;const d=s==null?void 0:s.match(/^(.*?)\s+([A-Z0-9]+)$/);if(d){const[,E,O]=d;u=k({name:E,hash:O})}const f=A(a,i,{model:u,prompts:p,negativePrompts:l});return w(this.generator,[f],e,t)}catch(o){throw new h(`No sampler found: ${o}`)}}}class ue extends S{constructor(){super(...arguments),this.generator=P.UNKNOWN}async parse(t){const e=A("dummy_sampler",{});return w(this.generator,[e],{"some other":"metadata"},t)}}const z=[R,L,x,G,J];function fe(n){return n[0]===137&&n[1]===80&&n[2]===78&&n[3]===71?"PNG":n[0]===255&&n[1]===216&&n[2]===255?"JPEG":n[0]===82&&n[1]===73&&n[2]===70&&n[3]===70&&n[8]===87&&n[9]===69&&n[10]===66&&n[11]===80?"WEBP":null}class de{constructor(t={}){const{debug:e=!1,eagerness:r=y.DEFAULT,managedParsers:s,normalizeParameters:a=!0}=t;this.eagerness=r,this.debug=e;const o=s||z;this.managedParsers=o.map(i=>new i(a,e))}async parse(t,e){const r=e||this.eagerness;let s;if(t instanceof Blob){const i=await t.arrayBuffer();s=new Uint8Array(i)}else t instanceof ArrayBuffer?s=new Uint8Array(t):s=t;const a=fe(s);if(!a)return this.debug&&console.log("Unknown image format"),null;const o=Q[a];if(!o)return this.debug&&console.log(`Unsupported image format: ${a}`),null;for(const i of[y.FAST,y.DEFAULT,y.EAGER]){if(i>r)break;const p=o[i];if(p)for(const c of p)for(const l of this.managedParsers)try{const u=await c(s,l.generator);if(!u)continue;try{return await l.parse(u)}catch(d){if(d instanceof h)this.debug&&console.error(`Error in parser[${l.constructor.name}]: ${d.message}`);else throw d}}catch(u){if(u instanceof v){this.debug&&console.error("Error reading metadata:",u.message);break}else throw u}}return null}}m.AUTOMATIC1111Parser=L,m.ComfyUIParser=x,m.DummyParser=ue,m.Eagerness=y,m.FooocusParser=R,m.Generators=P,m.InvokeAIParser=G,m.MANAGED_PARSERS=z,m.MetadataError=v,m.NovelAIParser=J,m.Parser=S,m.ParserError=h,m.ParserManager=de,m.createModel=k,m.createPrompt=g,m.createPromptInfo=w,m.createSampler=A,m.getFullNegativePrompt=b,m.getFullPrompt=M,m.getModels=X,m.getNegativePrompts=U,m.getPrompts=C,m.modelToString=B,m.promptInfoToDict=D,m.promptInfoToJSON=Y,m.promptToString=N,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})});
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@enslo/sd-parsers-web",
3
+ "version": "1.0.0",
4
+ "description": "Browser-only library to read metadata from Stable Diffusion images",
5
+ "type": "module",
6
+ "main": "./dist/sd-parsers-web.umd.js",
7
+ "module": "./dist/sd-parsers-web.es.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/sd-parsers-web.es.js",
12
+ "require": "./dist/sd-parsers-web.umd.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "vite build && tsc --emitDeclarationOnly",
18
+ "dev": "vite build --watch",
19
+ "test": "jest",
20
+ "sync-version": "./scripts/sync-version.sh"
21
+ },
22
+ "keywords": [
23
+ "stable-diffusion",
24
+ "metadata",
25
+ "image-parsing",
26
+ "browser",
27
+ "web",
28
+ "ai",
29
+ "automatic1111",
30
+ "comfyui",
31
+ "fooocus",
32
+ "invokeai",
33
+ "novelai"
34
+ ],
35
+ "author": "Ernest Croft",
36
+ "license": "MIT",
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "registry": "https://registry.npmjs.org/"
40
+ },
41
+ "dependencies": {
42
+ "exifr": "^7.1.0",
43
+ "png-chunks-extract": "^1.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "@types/jest": "^29.5.0",
47
+ "@types/png-chunks-extract": "^1.0.2",
48
+ "jest": "^29.5.0",
49
+ "jest-environment-jsdom": "^29.5.0",
50
+ "ts-jest": "^29.1.0",
51
+ "typescript": "^5.0.0",
52
+ "vite": "^5.0.0",
53
+ "vite-plugin-dts": "^3.0.0"
54
+ },
55
+ "files": [
56
+ "dist/**/*"
57
+ ],
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "git+https://github.com/enslo/sd-parsers-web.git"
61
+ }
62
+ }