@wovin/connect-nftstorage 0.1.35 → 0.2.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.
@@ -0,0 +1,2 @@
1
+ import{retrieveThread as i}from"@wovin/connect-gateway";import{Logger as r}from"besonders-logger";var{WARN:s,LOG:g,DEBUG:d,VERBOSE:S,ERROR:l}=r.setup(r.INFO),o="https://nftstorage.link";async function m(t,{readOnly:e=!0,pinnedCID:n}={}){return i(t,{readOnly:e,pinnedCID:n,gateways:[{url:o}]})}export{o as a,m as b};
2
+ //# sourceMappingURL=chunk-32YGF2Q4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/retrieve.ts"],"sourcesContent":["import { retrieveThread as retrieveThreadGW } from '@wovin/connect-gateway'\nimport { CidString, IpnsString } from '@wovin/core/applog'\nimport { Logger } from 'besonders-logger'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\nexport const NFTSTORAGE_GATEWAY = `https://nftstorage.link`\n\nexport async function retrieveThread(\n\tpubID: IpnsString | CidString | null,\n\t{ readOnly = true, pinnedCID }: { readOnly?: boolean; pinnedCID?: CidString } = {},\n) {\n\treturn retrieveThreadGW(pubID, {\n\t\treadOnly,\n\t\tpinnedCID,\n\t\tgateways: [{ url: NFTSTORAGE_GATEWAY }],\n\t})\n}\n"],"mappings":"AAAA,OAAS,kBAAkBA,MAAwB,yBAEnD,OAAS,UAAAC,MAAc,mBAEvB,GAAM,CAAE,KAAAC,EAAM,IAAAC,EAAK,MAAAC,EAAO,QAAAC,EAAS,MAAAC,CAAM,EAAIL,EAAO,MAAMA,EAAO,IAAI,EAExDM,EAAqB,0BAElC,eAAsBC,EACrBC,EACA,CAAE,SAAAC,EAAW,GAAM,UAAAC,CAAU,EAAmD,CAAC,EAChF,CACD,OAAOX,EAAiBS,EAAO,CAC9B,SAAAC,EACA,UAAAC,EACA,SAAU,CAAC,CAAE,IAAKJ,CAAmB,CAAC,CACvC,CAAC,CACF","names":["retrieveThreadGW","Logger","WARN","LOG","DEBUG","VERBOSE","ERROR","NFTSTORAGE_GATEWAY","retrieveThread","pubID","readOnly","pinnedCID"]}
@@ -0,0 +1,2 @@
1
+ import*as o from"@ucans/ucans";import{Logger as n}from"besonders-logger";import{CID as i}from"multiformats";var{WARN:d,LOG:p,DEBUG:s,VERBOSE:f,ERROR:g}=n.setup(n.INFO);async function l(e,t){let r=typeof t!="string",a=await(await fetch("https://api.nft.storage/upload",{method:"POST",headers:{Authorization:`Bearer ${r?o.encode(t):t}`,"Content-Type":"application/car","x-agent-did":r?t.payload.iss:void 0},body:e})).json();if(s("[storeCar] result",{result:a,isUcan:r}),!a.ok)throw new Error("Failed to upload"+JSON.stringify(a.error));return i.parse(a.value.cid)}async function h(e,t,r){s("[createRequestToken] ",{keypair:e,ucanToken:r});let a=r.payload;return o.build({issuer:e,audience:t,capabilities:a.att,proofs:[o.encode(r)]})}async function y(e,t){s("Registering",{did:t});let r=await(await fetch("https://api.nft.storage/user/did",{method:"POST",headers:{Authorization:`Bearer ${e}`},body:JSON.stringify({did:t})})).json();if(s("Register DID result",r),!r.ok)throw new Error("Failed to register DID "+JSON.stringify(r.error))}async function w(e){s("Get root UCAN",{apiKey:e});let t=await(await fetch("https://api.nft.storage/ucan/token",{method:"POST",headers:{Authorization:`Bearer ${e}`}})).json();if(s("Get root UCAN result",t),!t.ok)throw new Error("Failed get root UCAN "+JSON.stringify(t.error));return o.validate(t.value)}export{l as a,h as b,y as c,w as d};
2
+ //# sourceMappingURL=chunk-LQCSTNWI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/store.ts"],"sourcesContent":["import * as ucans from '@ucans/ucans'\nimport { Logger } from 'besonders-logger'\nimport { CID } from 'multiformats'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\nexport async function storeCar(car: Blob, token: ucans.Ucan | string): Promise<CID> {\n\t// const ucanInfo = await ucans.validate(ucanToken)\n\tconst isUcan = typeof token !== 'string'\n\n\t// Docs: https://nft.storage/api-docs/#operations-NFT_Storage-upload\n\tconst result = await (await fetch('https://api.nft.storage/upload', {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Authorization': `Bearer ${isUcan ? ucans.encode(token) : token}`,\n\t\t\t'Content-Type': `application/car`,\n\t\t\t'x-agent-did': isUcan ? token.payload.iss : undefined,\n\t\t},\n\t\tbody: car,\n\t})).json()\n\tDEBUG('[storeCar] result', { result, isUcan })\n\tif (!result.ok) throw new Error(`Failed to upload` + JSON.stringify(result.error))\n\treturn CID.parse(result.value.cid)\n}\n\nexport async function createRequestToken(\n\tkeypair: ucans.DidableKey,\n\tserviceDID: string,\n\tucanToken: ucans.Ucan,\n) {\n\tDEBUG(`[createRequestToken] `, { keypair, ucanToken })\n\t// we want to include the capabilities of the parent token in our request token\n\t// so we validate the parent token to extract the payload and copy over the capabilities\n\t// // the `att` field contains the capabilities we need for uploading\n\tconst payload = ucanToken.payload\n\treturn ucans.build({\n\t\tissuer: keypair,\n\t\taudience: serviceDID,\n\t\tcapabilities: (payload as any).att, // .map(att => ucans.capability.parse(att)),\n\t\tproofs: [ucans.encode(ucanToken)],\n\t})\n}\nexport async function registerDid(apiKey: string, did: string) {\n\tDEBUG(`Registering`, { did })\n\tconst result = await (await fetch('https://api.nft.storage/user/did', {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Authorization': `Bearer ${apiKey}`,\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tdid,\n\t\t}),\n\t})).json()\n\tDEBUG(`Register DID result`, result)\n\tif (!result.ok) throw new Error(`Failed to register DID ` + JSON.stringify(result.error))\n}\nexport async function getRootUcan(apiKey: string) {\n\tDEBUG(`Get root UCAN`, { apiKey })\n\tconst result = await (await fetch('https://api.nft.storage/ucan/token', {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\t'Authorization': `Bearer ${apiKey}`,\n\t\t},\n\t})).json()\n\tDEBUG(`Get root UCAN result`, result)\n\tif (!result.ok) throw new Error(`Failed get root UCAN ` + JSON.stringify(result.error))\n\treturn ucans.validate(result.value)\n}\n\n// import { build } from 'ucan-storage/ucan-storage'\n\n// // The DID for the storage service. In real code, you should obtain this from the service you're targetting.\n// const serviceDID = 'did:key:a-fake-service-did'\n\n// async function createRequestToken(parentUCAN, issuerKeyPair) {\n// \t// we want to include the capabilities of the parent token in our request token\n// \t// so we validate the parent token to extract the payload and copy over the capabilities\n// \tconst { payload } = await validate(parentUCAN)\n\n// \t// the `att` field contains the capabilities we need for uploading\n// \tconst { att } = payload\n\n// \treturn build({\n// \t\tissuer: issuerKeyPair,\n// \t\taudience: serviceDID,\n// \t\tcapabilities: att,\n// \t\tproofs: [parentUcan],\n// \t})\n// }\n"],"mappings":"AAAA,UAAYA,MAAW,eACvB,OAAS,UAAAC,MAAc,mBACvB,OAAS,OAAAC,MAAW,eAEpB,GAAM,CAAE,KAAAC,EAAM,IAAAC,EAAK,MAAAC,EAAO,QAAAC,EAAS,MAAAC,CAAM,EAAIN,EAAO,MAAMA,EAAO,IAAI,EAErE,eAAsBO,EAASC,EAAWC,EAA0C,CAEnF,IAAMC,EAAS,OAAOD,GAAU,SAG1BE,EAAS,MAAO,MAAM,MAAM,iCAAkC,CACnE,OAAQ,OACR,QAAS,CACR,cAAiB,UAAUD,EAAe,SAAOD,CAAK,EAAIA,CAAK,GAC/D,eAAgB,kBAChB,cAAeC,EAASD,EAAM,QAAQ,IAAM,MAC7C,EACA,KAAMD,CACP,CAAC,GAAG,KAAK,EAET,GADAJ,EAAM,oBAAqB,CAAE,OAAAO,EAAQ,OAAAD,CAAO,CAAC,EACzC,CAACC,EAAO,GAAI,MAAM,IAAI,MAAM,mBAAqB,KAAK,UAAUA,EAAO,KAAK,CAAC,EACjF,OAAOV,EAAI,MAAMU,EAAO,MAAM,GAAG,CAClC,CAEA,eAAsBC,EACrBC,EACAC,EACAC,EACC,CACDX,EAAM,wBAAyB,CAAE,QAAAS,EAAS,UAAAE,CAAU,CAAC,EAIrD,IAAMC,EAAUD,EAAU,QAC1B,OAAa,QAAM,CAClB,OAAQF,EACR,SAAUC,EACV,aAAeE,EAAgB,IAC/B,OAAQ,CAAO,SAAOD,CAAS,CAAC,CACjC,CAAC,CACF,CACA,eAAsBE,EAAYC,EAAgBC,EAAa,CAC9Df,EAAM,cAAe,CAAE,IAAAe,CAAI,CAAC,EAC5B,IAAMR,EAAS,MAAO,MAAM,MAAM,mCAAoC,CACrE,OAAQ,OACR,QAAS,CACR,cAAiB,UAAUO,CAAM,EAClC,EACA,KAAM,KAAK,UAAU,CACpB,IAAAC,CACD,CAAC,CACF,CAAC,GAAG,KAAK,EAET,GADAf,EAAM,sBAAuBO,CAAM,EAC/B,CAACA,EAAO,GAAI,MAAM,IAAI,MAAM,0BAA4B,KAAK,UAAUA,EAAO,KAAK,CAAC,CACzF,CACA,eAAsBS,EAAYF,EAAgB,CACjDd,EAAM,gBAAiB,CAAE,OAAAc,CAAO,CAAC,EACjC,IAAMP,EAAS,MAAO,MAAM,MAAM,qCAAsC,CACvE,OAAQ,OACR,QAAS,CACR,cAAiB,UAAUO,CAAM,EAClC,CACD,CAAC,GAAG,KAAK,EAET,GADAd,EAAM,uBAAwBO,CAAM,EAChC,CAACA,EAAO,GAAI,MAAM,IAAI,MAAM,wBAA0B,KAAK,UAAUA,EAAO,KAAK,CAAC,EACtF,OAAa,WAASA,EAAO,KAAK,CACnC","names":["ucans","Logger","CID","WARN","LOG","DEBUG","VERBOSE","ERROR","storeCar","car","token","isUcan","result","createRequestToken","keypair","serviceDID","ucanToken","payload","registerDid","apiKey","did","getRootUcan"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as ucans from '@ucans/ucans';
2
2
  import { type StorageConnector } from '@wovin/core/pubsub';
3
3
  import { CID } from 'multiformats';
4
- export * from './retrieve';
4
+ export * from './retrieve.ts';
5
5
  export declare class NftStorageConnector implements StorageConnector {
6
6
  serviceDID: string | null;
7
7
  private apiKey;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAMlC,cAAc,YAAY,CAAA;AAG1B,qBAAa,mBAAoB,YAAW,gBAAgB;IAanD,UAAU,EAAE,MAAM,GAAG,IAAI;IAChC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;WAfJ,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;QAChD,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,KAAK,CAAC,UAAU,CAAA;QAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,IAAI,CAAA;KACrB;gBAQO,UAAU,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,EAAE,KAAK,CAAC,UAAU,GAAG,IAAI,EAChC,QAAQ,EAAE,KAAK,CAAC,IAAI,GAAG,IAAI;IAKpC,IAAI,OAAO,YAEV;IACD,IAAI,OAAO,YAEV;IAEK,QAAQ,CAAC,GAAG,EAAE,IAAI;IA2BxB,UAAU;;;CAGV"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAMlC,cAAc,eAAe,CAAA;AAG7B,qBAAa,mBAAoB,YAAW,gBAAgB;IAanD,UAAU,EAAE,MAAM,GAAG,IAAI;IAChC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;WAfJ,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;QAChD,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,KAAK,CAAC,UAAU,CAAA;QAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,IAAI,CAAA;KACrB;gBAQO,UAAU,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,EAAE,KAAK,CAAC,UAAU,GAAG,IAAI,EAChC,QAAQ,EAAE,KAAK,CAAC,IAAI,GAAG,IAAI;IAKpC,IAAI,OAAO,YAEV;IACD,IAAI,OAAO,YAEV;IAEK,QAAQ,CAAC,GAAG,EAAE,IAAI;IA2BxB,UAAU;;;CAGV"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import{a as o,b as f}from"./chunk-32YGF2Q4.js";import{a as i,b as s,c as n,d as c}from"./chunk-LQCSTNWI.js";import{Logger as p}from"besonders-logger";var{WARN:l,LOG:v,DEBUG:m,VERBOSE:I,ERROR:y}=p.setup(p.INFO),u=class D{constructor(r,t,e,a){this.serviceDID=r;this.apiKey=t;this.keypair=e;this.rootUcan=a;if(!(t||e&&a))throw new Error("Needs apiKey - or keypair and rootUcan")}static async init({apiKey:r,keypair:t,rootUcan:e}){return m("Init NFT.Storage connector:",{apiKey:r,keypair:t,serviceDID:null}),new D(null,r,t,e)}get isSetup(){return!0}get isValid(){return!0}async storeCar(r){if(this.apiKey&&!this.keypair)return i(r,this.apiKey);if(!this.serviceDID){let{value:t}=await(await fetch("https://api.nft.storage/did")).json();this.serviceDID=t}for(let t=1;t<3;t++)try{this.rootUcan||(await n(this.apiKey,this.keypair.did()),this.rootUcan=await c(this.apiKey));let e=await s(this.keypair,this.serviceDID,this.rootUcan);return i(r,e)}catch(e){if(y("[nft-connector.storeCar] error:",e),e.message?.contains?.("ERROR_TOKEN_NOT_FOUND"))l(`Token not found (might be a race condition) (attempt=${t}):`,e);else throw e}}getGateway(){return{url:o}}};export{o as NFTSTORAGE_GATEWAY,u as NftStorageConnector,f as retrieveThread};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import * as ucans from '@ucans/ucans'\nimport type { IpfsGateway } from '@wovin/connect-gateway'\nimport { type StorageConnector } from '@wovin/core/pubsub'\nimport { Logger } from 'besonders-logger'\nimport { CID } from 'multiformats'\nimport { NFTSTORAGE_GATEWAY } from './retrieve.ts'\nimport { createRequestToken, getRootUcan, registerDid, storeCar } from './store.ts'\n\nconst { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars\n\nexport * from './retrieve.ts'\n// export * from './store.ts'\n\nexport class NftStorageConnector implements StorageConnector {\n\tstatic async init({ apiKey, keypair, rootUcan }: {\n\t\tapiKey?: string\n\t\tkeypair?: ucans.DidableKey\n\t\trootUcan?: ucans.Ucan\n\t}) {\n\t\t// const { value: serviceDID } = await (await fetch('https://api.nft.storage/did')).json() - Unnecessary delay on init (& might fail when no internet)\n\t\tconst serviceDID = null\n\t\t// if (!keypair) keypair = await ucans.EdKeypair.create()\n\t\tDEBUG(`Init NFT.Storage connector:`, { apiKey, keypair, serviceDID })\n\t\treturn new NftStorageConnector(serviceDID, apiKey, keypair, rootUcan)\n\t}\n\tconstructor(\n\t\tpublic serviceDID: string | null,\n\t\tprivate apiKey: string | null,\n\t\tprivate keypair: ucans.DidableKey | null,\n\t\tprivate rootUcan: ucans.Ucan | null,\n\t) {\n\t\tif (!(apiKey || (keypair && rootUcan))) throw new Error(`Needs apiKey - or keypair and rootUcan`)\n\t}\n\n\tget isSetup() {\n\t\treturn true\n\t}\n\tget isValid() {\n\t\treturn true // TODO test ucan etc\n\t}\n\n\tasync storeCar(car: Blob) {\n\t\tif (this.apiKey && !this.keypair) {\n\t\t\treturn storeCar(car, this.apiKey)\n\t\t}\n\t\tif (!this.serviceDID) {\n\t\t\tconst { value: serviceDID } = await (await fetch('https://api.nft.storage/did')).json()\n\t\t\tthis.serviceDID = serviceDID\n\t\t}\n\t\t// NFT.storage allows only one registered DID, so we might have another agent register between our register & push\n\t\tfor (let attempt = 1; attempt < 3; attempt++) {\n\t\t\ttry {\n\t\t\t\tif (!this.rootUcan) {\n\t\t\t\t\tawait registerDid(this.apiKey, this.keypair.did())\n\t\t\t\t\tthis.rootUcan = await getRootUcan(this.apiKey)\n\t\t\t\t\t// TODO: callback to the app - for persisting?\n\t\t\t\t}\n\t\t\t\tconst requestUcan = await createRequestToken(this.keypair, this.serviceDID, this.rootUcan)\n\t\t\t\treturn storeCar(car, requestUcan)\n\t\t\t} catch (err) {\n\t\t\t\tERROR(`[nft-connector.storeCar] error:`, err)\n\t\t\t\tif ((err as any).message?.contains?.('ERROR_TOKEN_NOT_FOUND')) {\n\t\t\t\t\tWARN(`Token not found (might be a race condition) (attempt=${attempt}):`, err)\n\t\t\t\t} else throw err\n\t\t\t}\n\t\t}\n\t}\n\n\tgetGateway() {\n\t\treturn { url: NFTSTORAGE_GATEWAY } satisfies IpfsGateway\n\t}\n}\n"],"mappings":"4GAGA,OAAS,UAAAA,MAAc,mBAKvB,GAAM,CAAE,KAAAC,EAAM,IAAAC,EAAK,MAAAC,EAAO,QAAAC,EAAS,MAAAC,CAAM,EAAIC,EAAO,MAAMA,EAAO,IAAI,EAKxDC,EAAN,MAAMC,CAAgD,CAY5D,YACQC,EACCC,EACAC,EACAC,EACP,CAJM,gBAAAH,EACC,YAAAC,EACA,aAAAC,EACA,cAAAC,EAER,GAAI,EAAEF,GAAWC,GAAWC,GAAY,MAAM,IAAI,MAAM,wCAAwC,CACjG,CAlBA,aAAa,KAAK,CAAE,OAAAF,EAAQ,QAAAC,EAAS,SAAAC,CAAS,EAI3C,CAIF,OAAAT,EAAM,8BAA+B,CAAE,OAAAO,EAAQ,QAAAC,EAAS,eAAW,CAAC,EAC7D,IAAIH,EAAoB,KAAYE,EAAQC,EAASC,CAAQ,CACrE,CAUA,IAAI,SAAU,CACb,MAAO,EACR,CACA,IAAI,SAAU,CACb,MAAO,EACR,CAEA,MAAM,SAASC,EAAW,CACzB,GAAI,KAAK,QAAU,CAAC,KAAK,QACxB,OAAOC,EAASD,EAAK,KAAK,MAAM,EAEjC,GAAI,CAAC,KAAK,WAAY,CACrB,GAAM,CAAE,MAAOJ,CAAW,EAAI,MAAO,MAAM,MAAM,6BAA6B,GAAG,KAAK,EACtF,KAAK,WAAaA,CACnB,CAEA,QAASM,EAAU,EAAGA,EAAU,EAAGA,IAClC,GAAI,CACE,KAAK,WACT,MAAMC,EAAY,KAAK,OAAQ,KAAK,QAAQ,IAAI,CAAC,EACjD,KAAK,SAAW,MAAMC,EAAY,KAAK,MAAM,GAG9C,IAAMC,EAAc,MAAMC,EAAmB,KAAK,QAAS,KAAK,WAAY,KAAK,QAAQ,EACzF,OAAOL,EAASD,EAAKK,CAAW,CACjC,OAASE,EAAK,CAEb,GADAf,EAAM,kCAAmCe,CAAG,EACvCA,EAAY,SAAS,WAAW,uBAAuB,EAC3DnB,EAAK,wDAAwDc,CAAO,KAAMK,CAAG,MACvE,OAAMA,CACd,CAEF,CAEA,YAAa,CACZ,MAAO,CAAE,IAAKC,CAAmB,CAClC,CACD","names":["Logger","WARN","LOG","DEBUG","VERBOSE","ERROR","Logger","NftStorageConnector","_NftStorageConnector","serviceDID","apiKey","keypair","rootUcan","car","storeCar","attempt","registerDid","getRootUcan","requestUcan","createRequestToken","err","NFTSTORAGE_GATEWAY"]}
@@ -0,0 +1,2 @@
1
+ import{a,b}from"./chunk-32YGF2Q4.js";export{a as NFTSTORAGE_GATEWAY,b as retrieveThread};
2
+ //# sourceMappingURL=retrieve.js.map
package/dist/store.js ADDED
@@ -0,0 +1,2 @@
1
+ import{a,b,c,d}from"./chunk-LQCSTNWI.js";export{b as createRequestToken,d as getRootUcan,c as registerDid,a as storeCar};
2
+ //# sourceMappingURL=store.js.map
package/package.json CHANGED
@@ -1,31 +1,32 @@
1
1
  {
2
2
  "name": "@wovin/connect-nftstorage",
3
- "version": "0.1.35",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
- "main": "./dist/index.min.js",
6
- "module": "./dist/index.min.js",
7
- "browser": "./dist/index.min.js",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "browser": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "import": "./dist/index.min.js",
11
+ "import": "./dist/index.js",
12
12
  "types": "./dist/index.d.ts"
13
13
  },
14
14
  "./retrieve": {
15
- "import": "./dist/retrieve.min.js",
15
+ "import": "./dist/retrieve.js",
16
16
  "types": "./dist/retrieve.d.ts"
17
17
  },
18
18
  "./utils": {
19
- "import": "./dist/utils.min.js",
19
+ "import": "./dist/utils.js",
20
20
  "types": "./dist/utils.d.ts"
21
21
  },
22
22
  "./store": {
23
- "import": "./dist/store.min.js",
23
+ "import": "./dist/store.js",
24
24
  "types": "./dist/store.d.ts"
25
25
  }
26
26
  },
27
27
  "files": [
28
- "./dist/"
28
+ "./dist/",
29
+ "./src/"
29
30
  ],
30
31
  "esm.sh": {
31
32
  "bundle": false
@@ -36,8 +37,8 @@
36
37
  "besonders-logger": "1.0.1",
37
38
  "multiformats": "^13.0.1",
38
39
  "ucan-storage": "^1.3.0",
39
- "@wovin/connect-gateway": "^0.1.35",
40
- "@wovin/core": "^0.1.35"
40
+ "@wovin/connect-gateway": "^0.2.0",
41
+ "@wovin/core": "^0.2.0"
41
42
  },
42
43
  "devDependencies": {
43
44
  "concurrently": "^8.2.2",
package/src/index.ts ADDED
@@ -0,0 +1,72 @@
1
+ import * as ucans from '@ucans/ucans'
2
+ import type { IpfsGateway } from '@wovin/connect-gateway'
3
+ import { type StorageConnector } from '@wovin/core/pubsub'
4
+ import { Logger } from 'besonders-logger'
5
+ import { CID } from 'multiformats'
6
+ import { NFTSTORAGE_GATEWAY } from './retrieve.ts'
7
+ import { createRequestToken, getRootUcan, registerDid, storeCar } from './store.ts'
8
+
9
+ const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars
10
+
11
+ export * from './retrieve.ts'
12
+ // export * from './store.ts'
13
+
14
+ export class NftStorageConnector implements StorageConnector {
15
+ static async init({ apiKey, keypair, rootUcan }: {
16
+ apiKey?: string
17
+ keypair?: ucans.DidableKey
18
+ rootUcan?: ucans.Ucan
19
+ }) {
20
+ // const { value: serviceDID } = await (await fetch('https://api.nft.storage/did')).json() - Unnecessary delay on init (& might fail when no internet)
21
+ const serviceDID = null
22
+ // if (!keypair) keypair = await ucans.EdKeypair.create()
23
+ DEBUG(`Init NFT.Storage connector:`, { apiKey, keypair, serviceDID })
24
+ return new NftStorageConnector(serviceDID, apiKey, keypair, rootUcan)
25
+ }
26
+ constructor(
27
+ public serviceDID: string | null,
28
+ private apiKey: string | null,
29
+ private keypair: ucans.DidableKey | null,
30
+ private rootUcan: ucans.Ucan | null,
31
+ ) {
32
+ if (!(apiKey || (keypair && rootUcan))) throw new Error(`Needs apiKey - or keypair and rootUcan`)
33
+ }
34
+
35
+ get isSetup() {
36
+ return true
37
+ }
38
+ get isValid() {
39
+ return true // TODO test ucan etc
40
+ }
41
+
42
+ async storeCar(car: Blob) {
43
+ if (this.apiKey && !this.keypair) {
44
+ return storeCar(car, this.apiKey)
45
+ }
46
+ if (!this.serviceDID) {
47
+ const { value: serviceDID } = await (await fetch('https://api.nft.storage/did')).json()
48
+ this.serviceDID = serviceDID
49
+ }
50
+ // NFT.storage allows only one registered DID, so we might have another agent register between our register & push
51
+ for (let attempt = 1; attempt < 3; attempt++) {
52
+ try {
53
+ if (!this.rootUcan) {
54
+ await registerDid(this.apiKey, this.keypair.did())
55
+ this.rootUcan = await getRootUcan(this.apiKey)
56
+ // TODO: callback to the app - for persisting?
57
+ }
58
+ const requestUcan = await createRequestToken(this.keypair, this.serviceDID, this.rootUcan)
59
+ return storeCar(car, requestUcan)
60
+ } catch (err) {
61
+ ERROR(`[nft-connector.storeCar] error:`, err)
62
+ if ((err as any).message?.contains?.('ERROR_TOKEN_NOT_FOUND')) {
63
+ WARN(`Token not found (might be a race condition) (attempt=${attempt}):`, err)
64
+ } else throw err
65
+ }
66
+ }
67
+ }
68
+
69
+ getGateway() {
70
+ return { url: NFTSTORAGE_GATEWAY } satisfies IpfsGateway
71
+ }
72
+ }
@@ -0,0 +1,18 @@
1
+ import { retrieveThread as retrieveThreadGW } from '@wovin/connect-gateway'
2
+ import { CidString, IpnsString } from '@wovin/core/applog'
3
+ import { Logger } from 'besonders-logger'
4
+
5
+ const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars
6
+
7
+ export const NFTSTORAGE_GATEWAY = `https://nftstorage.link`
8
+
9
+ export async function retrieveThread(
10
+ pubID: IpnsString | CidString | null,
11
+ { readOnly = true, pinnedCID }: { readOnly?: boolean; pinnedCID?: CidString } = {},
12
+ ) {
13
+ return retrieveThreadGW(pubID, {
14
+ readOnly,
15
+ pinnedCID,
16
+ gateways: [{ url: NFTSTORAGE_GATEWAY }],
17
+ })
18
+ }
package/src/store.ts ADDED
@@ -0,0 +1,89 @@
1
+ import * as ucans from '@ucans/ucans'
2
+ import { Logger } from 'besonders-logger'
3
+ import { CID } from 'multiformats'
4
+
5
+ const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line no-unused-vars
6
+
7
+ export async function storeCar(car: Blob, token: ucans.Ucan | string): Promise<CID> {
8
+ // const ucanInfo = await ucans.validate(ucanToken)
9
+ const isUcan = typeof token !== 'string'
10
+
11
+ // Docs: https://nft.storage/api-docs/#operations-NFT_Storage-upload
12
+ const result = await (await fetch('https://api.nft.storage/upload', {
13
+ method: 'POST',
14
+ headers: {
15
+ 'Authorization': `Bearer ${isUcan ? ucans.encode(token) : token}`,
16
+ 'Content-Type': `application/car`,
17
+ 'x-agent-did': isUcan ? token.payload.iss : undefined,
18
+ },
19
+ body: car,
20
+ })).json()
21
+ DEBUG('[storeCar] result', { result, isUcan })
22
+ if (!result.ok) throw new Error(`Failed to upload` + JSON.stringify(result.error))
23
+ return CID.parse(result.value.cid)
24
+ }
25
+
26
+ export async function createRequestToken(
27
+ keypair: ucans.DidableKey,
28
+ serviceDID: string,
29
+ ucanToken: ucans.Ucan,
30
+ ) {
31
+ DEBUG(`[createRequestToken] `, { keypair, ucanToken })
32
+ // we want to include the capabilities of the parent token in our request token
33
+ // so we validate the parent token to extract the payload and copy over the capabilities
34
+ // // the `att` field contains the capabilities we need for uploading
35
+ const payload = ucanToken.payload
36
+ return ucans.build({
37
+ issuer: keypair,
38
+ audience: serviceDID,
39
+ capabilities: (payload as any).att, // .map(att => ucans.capability.parse(att)),
40
+ proofs: [ucans.encode(ucanToken)],
41
+ })
42
+ }
43
+ export async function registerDid(apiKey: string, did: string) {
44
+ DEBUG(`Registering`, { did })
45
+ const result = await (await fetch('https://api.nft.storage/user/did', {
46
+ method: 'POST',
47
+ headers: {
48
+ 'Authorization': `Bearer ${apiKey}`,
49
+ },
50
+ body: JSON.stringify({
51
+ did,
52
+ }),
53
+ })).json()
54
+ DEBUG(`Register DID result`, result)
55
+ if (!result.ok) throw new Error(`Failed to register DID ` + JSON.stringify(result.error))
56
+ }
57
+ export async function getRootUcan(apiKey: string) {
58
+ DEBUG(`Get root UCAN`, { apiKey })
59
+ const result = await (await fetch('https://api.nft.storage/ucan/token', {
60
+ method: 'POST',
61
+ headers: {
62
+ 'Authorization': `Bearer ${apiKey}`,
63
+ },
64
+ })).json()
65
+ DEBUG(`Get root UCAN result`, result)
66
+ if (!result.ok) throw new Error(`Failed get root UCAN ` + JSON.stringify(result.error))
67
+ return ucans.validate(result.value)
68
+ }
69
+
70
+ // import { build } from 'ucan-storage/ucan-storage'
71
+
72
+ // // The DID for the storage service. In real code, you should obtain this from the service you're targetting.
73
+ // const serviceDID = 'did:key:a-fake-service-did'
74
+
75
+ // async function createRequestToken(parentUCAN, issuerKeyPair) {
76
+ // // we want to include the capabilities of the parent token in our request token
77
+ // // so we validate the parent token to extract the payload and copy over the capabilities
78
+ // const { payload } = await validate(parentUCAN)
79
+
80
+ // // the `att` field contains the capabilities we need for uploading
81
+ // const { att } = payload
82
+
83
+ // return build({
84
+ // issuer: issuerKeyPair,
85
+ // audience: serviceDID,
86
+ // capabilities: att,
87
+ // proofs: [parentUcan],
88
+ // })
89
+ // }