[{"data":1,"prerenderedAt":2149},["ShallowReactive",2],{"docs:\u002Fdocs\u002Fquickstart":3,"docs:nav":2104},{"id":4,"title":5,"badge":6,"body":7,"description":2096,"extension":2097,"meta":2098,"navigation":236,"order":36,"path":2099,"section":2100,"seo":2101,"stem":2102,"__hash__":2103},"docs\u002Fdocs\u002Fquickstart.md","Quickstart",null,{"type":8,"value":9,"toc":2084},"minimark",[10,14,19,22,68,72,75,101,158,166,194,198,211,741,744,772,776,835,983,995,999,1002,1501,1512,1516,1519,1605,1608,1612,1737,1744,1748,1952,1955,1959,2017,2024,2028,2080],[11,12,13],"p",{},"By the end of this page you will have stored an object as 15 encrypted shards on 15 independent\nproviders and read it back from 10 of them.",[15,16,18],"h2",{"id":17},"before-you-start","Before you start",[11,20,21],{},"You need a runtime that can speak the storage transfer protocol to providers directly, because\nTessera does not proxy object bytes. That means a server-side runtime — Bun, Node, Go, or Python —\nnot a browser.",[23,24,29],"pre",{"className":25,"code":26,"language":27,"meta":28,"style":28},"language-bash shiki shiki-themes github-dark-default github-dark-default","bun add @noble\u002Fhashes @noble\u002Fcurves\nexport TESSERA_API=\"https:\u002F\u002Fapi.PLACEHOLDER_DOMAIN.example\"\n","bash","",[30,31,32,51],"code",{"__ignoreMap":28},[33,34,37,41,45,48],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sAxfE","bun",[33,42,44],{"class":43},"skZ57"," add",[33,46,47],{"class":43}," @noble\u002Fhashes",[33,49,50],{"class":43}," @noble\u002Fcurves\n",[33,52,54,58,62,65],{"class":35,"line":53},2,[33,55,57],{"class":56},"srH4v","export",[33,59,61],{"class":60},"sb7RM"," TESSERA_API",[33,63,64],{"class":56},"=",[33,66,67],{"class":43},"\"https:\u002F\u002Fapi.PLACEHOLDER_DOMAIN.example\"\n",[15,69,71],{"id":70},"_1-provision-a-credential","1 — Provision a credential",[11,73,74],{},"This is the one endpoint that needs no authentication, because you do not have a credential yet.",[23,76,78],{"className":25,"code":77,"language":27,"meta":28,"style":28},"curl -X POST \"$TESSERA_API\u002Fauth\u002Fprovision\"\n",[30,79,80],{"__ignoreMap":28},[33,81,82,85,89,92,95,98],{"class":35,"line":36},[33,83,84],{"class":39},"curl",[33,86,88],{"class":87},"sEQcL"," -X",[33,90,91],{"class":43}," POST",[33,93,94],{"class":43}," \"",[33,96,97],{"class":60},"$TESSERA_API",[33,99,100],{"class":43},"\u002Fauth\u002Fprovision\"\n",[23,102,106],{"className":103,"code":104,"language":105,"meta":28,"style":28},"language-json shiki shiki-themes github-dark-default github-dark-default","{\n  \"appID\": \"Aq3fZm9rLXRl\",\n  \"appKey\": \"kR8vN2pQ...64-bytes-base64url-unpadded\",\n  \"credential\": \"Aq3fZm9rLXRlc3QtY3JlZGVudGlhbC1oZXJlLW9r=\"\n}\n","json",[30,107,108,113,128,141,152],{"__ignoreMap":28},[33,109,110],{"class":35,"line":36},[33,111,112],{"class":60},"{\n",[33,114,115,119,122,125],{"class":35,"line":53},[33,116,118],{"class":117},"sV7Mv","  \"appID\"",[33,120,121],{"class":60},": ",[33,123,124],{"class":43},"\"Aq3fZm9rLXRl\"",[33,126,127],{"class":60},",\n",[33,129,131,134,136,139],{"class":35,"line":130},3,[33,132,133],{"class":117},"  \"appKey\"",[33,135,121],{"class":60},[33,137,138],{"class":43},"\"kR8vN2pQ...64-bytes-base64url-unpadded\"",[33,140,127],{"class":60},[33,142,144,147,149],{"class":35,"line":143},4,[33,145,146],{"class":117},"  \"credential\"",[33,148,121],{"class":60},[33,150,151],{"class":43},"\"Aq3fZm9rLXRlc3QtY3JlZGVudGlhbC1oZXJlLW9r=\"\n",[33,153,155],{"class":35,"line":154},5,[33,156,157],{"class":60},"}\n",[159,160,163],"app-callout",{"title":161,"tone":162},"`appKey` is shown once","warn",[11,164,165],{},"It is your ed25519 private key. We do not store a recoverable copy, so if you lose it, everything\nstored under it is unreachable — by you and by us. Put it in a secret manager now, before you write\nany data. Provisioning is rate limited to 5 credentials per hour per source address.",[23,167,169],{"className":25,"code":168,"language":27,"meta":28,"style":28},"export TESSERA_APPKEY=\"kR8vN2pQ...\"\nexport TESSERA_CREDENTIAL=\"Aq3fZm9rLXRlc3QtY3JlZGVudGlhbC1oZXJlLW9r=\"\n",[30,170,171,183],{"__ignoreMap":28},[33,172,173,175,178,180],{"class":35,"line":36},[33,174,57],{"class":56},[33,176,177],{"class":60}," TESSERA_APPKEY",[33,179,64],{"class":56},[33,181,182],{"class":43},"\"kR8vN2pQ...\"\n",[33,184,185,187,190,192],{"class":35,"line":53},[33,186,57],{"class":56},[33,188,189],{"class":60}," TESSERA_CREDENTIAL",[33,191,64],{"class":56},[33,193,151],{"class":43},[15,195,197],{"id":196},"_2-sign-a-request","2 — Sign a request",[11,199,200,201,204,205,210],{},"Every other endpoint needs three signed query parameters. Copy ",[30,202,203],{},"signRequest"," from\n",[206,207,209],"a",{"href":208},"\u002Fdocs\u002Fauthentication","Authentication"," — the construction has enough sharp edges that reading that\npage is genuinely faster than guessing.",[23,212,216],{"className":213,"code":214,"language":215,"meta":28,"style":28},"language-ts shiki shiki-themes github-dark-default github-dark-default","import { signRequest } from '.\u002Fsign'\n\nconst API = new URL(process.env.TESSERA_API!)\nconst cred = {\n  appKey: process.env.TESSERA_APPKEY!,\n  credential: process.env.TESSERA_CREDENTIAL!,\n}\n\nasync function call(method: string, path: string, body?: unknown) {\n  const raw = body === undefined ? null : new TextEncoder().encode(JSON.stringify(body))\n  const params = signRequest(cred, method, API.host, path, raw)\n\n  const res = await fetch(`${API.origin}${path}?${params}`, {\n    method,\n    headers: raw ? { 'content-type': 'application\u002Fjson' } : undefined,\n    body: raw,\n  })\n\n  const text = await res.text()\n  if (!res.ok) throw new Error(`${method} ${path} → ${res.status}: ${text}`)\n  \u002F\u002F Some endpoints answer 200 with a JSON error object rather than an error status.\n  const parsed = text ? JSON.parse(text) : null\n  if (parsed && typeof parsed === 'object' && 'error' in parsed) {\n    throw new Error(`${method} ${path} → ${parsed.error}`)\n  }\n  return parsed\n}\n","ts",[30,217,218,232,238,268,280,292,305,310,315,363,417,439,444,489,495,524,530,536,541,562,615,622,653,687,721,727,736],{"__ignoreMap":28},[33,219,220,223,226,229],{"class":35,"line":36},[33,221,222],{"class":56},"import",[33,224,225],{"class":60}," { signRequest } ",[33,227,228],{"class":56},"from",[33,230,231],{"class":43}," '.\u002Fsign'\n",[33,233,234],{"class":35,"line":53},[33,235,237],{"emptyLinePlaceholder":236},true,"\n",[33,239,240,243,246,249,252,256,259,262,265],{"class":35,"line":130},[33,241,242],{"class":56},"const",[33,244,245],{"class":87}," API",[33,247,248],{"class":56}," =",[33,250,251],{"class":56}," new",[33,253,255],{"class":254},"sYGIp"," URL",[33,257,258],{"class":60},"(process.env.",[33,260,261],{"class":87},"TESSERA_API",[33,263,264],{"class":56},"!",[33,266,267],{"class":60},")\n",[33,269,270,272,275,277],{"class":35,"line":143},[33,271,242],{"class":56},[33,273,274],{"class":87}," cred",[33,276,248],{"class":56},[33,278,279],{"class":60}," {\n",[33,281,282,285,288,290],{"class":35,"line":154},[33,283,284],{"class":60},"  appKey: process.env.",[33,286,287],{"class":87},"TESSERA_APPKEY",[33,289,264],{"class":56},[33,291,127],{"class":60},[33,293,295,298,301,303],{"class":35,"line":294},6,[33,296,297],{"class":60},"  credential: process.env.",[33,299,300],{"class":87},"TESSERA_CREDENTIAL",[33,302,264],{"class":56},[33,304,127],{"class":60},[33,306,308],{"class":35,"line":307},7,[33,309,157],{"class":60},[33,311,313],{"class":35,"line":312},8,[33,314,237],{"emptyLinePlaceholder":236},[33,316,318,321,324,327,330,333,336,339,342,345,347,349,351,354,357,360],{"class":35,"line":317},9,[33,319,320],{"class":56},"async",[33,322,323],{"class":56}," function",[33,325,326],{"class":254}," call",[33,328,329],{"class":60},"(",[33,331,332],{"class":39},"method",[33,334,335],{"class":56},":",[33,337,338],{"class":87}," string",[33,340,341],{"class":60},", ",[33,343,344],{"class":39},"path",[33,346,335],{"class":56},[33,348,338],{"class":87},[33,350,341],{"class":60},[33,352,353],{"class":39},"body",[33,355,356],{"class":56},"?:",[33,358,359],{"class":87}," unknown",[33,361,362],{"class":60},") {\n",[33,364,366,369,372,374,377,380,383,386,389,392,394,397,400,403,405,408,411,414],{"class":35,"line":365},10,[33,367,368],{"class":56},"  const",[33,370,371],{"class":87}," raw",[33,373,248],{"class":56},[33,375,376],{"class":60}," body ",[33,378,379],{"class":56},"===",[33,381,382],{"class":87}," undefined",[33,384,385],{"class":56}," ?",[33,387,388],{"class":87}," null",[33,390,391],{"class":56}," :",[33,393,251],{"class":56},[33,395,396],{"class":254}," TextEncoder",[33,398,399],{"class":60},"().",[33,401,402],{"class":254},"encode",[33,404,329],{"class":60},[33,406,407],{"class":87},"JSON",[33,409,410],{"class":60},".",[33,412,413],{"class":254},"stringify",[33,415,416],{"class":60},"(body))\n",[33,418,420,422,425,427,430,433,436],{"class":35,"line":419},11,[33,421,368],{"class":56},[33,423,424],{"class":87}," params",[33,426,248],{"class":56},[33,428,429],{"class":254}," signRequest",[33,431,432],{"class":60},"(cred, method, ",[33,434,435],{"class":87},"API",[33,437,438],{"class":60},".host, path, raw)\n",[33,440,442],{"class":35,"line":441},12,[33,443,237],{"emptyLinePlaceholder":236},[33,445,447,449,452,454,457,460,462,465,467,469,472,475,477,480,483,486],{"class":35,"line":446},13,[33,448,368],{"class":56},[33,450,451],{"class":87}," res",[33,453,248],{"class":56},[33,455,456],{"class":56}," await",[33,458,459],{"class":254}," fetch",[33,461,329],{"class":60},[33,463,464],{"class":43},"`${",[33,466,435],{"class":87},[33,468,410],{"class":43},[33,470,471],{"class":60},"origin",[33,473,474],{"class":43},"}${",[33,476,344],{"class":60},[33,478,479],{"class":43},"}?${",[33,481,482],{"class":60},"params",[33,484,485],{"class":43},"}`",[33,487,488],{"class":60},", {\n",[33,490,492],{"class":35,"line":491},14,[33,493,494],{"class":60},"    method,\n",[33,496,498,501,504,507,510,512,515,518,520,522],{"class":35,"line":497},15,[33,499,500],{"class":60},"    headers: raw ",[33,502,503],{"class":56},"?",[33,505,506],{"class":60}," { ",[33,508,509],{"class":43},"'content-type'",[33,511,121],{"class":60},[33,513,514],{"class":43},"'application\u002Fjson'",[33,516,517],{"class":60}," } ",[33,519,335],{"class":56},[33,521,382],{"class":87},[33,523,127],{"class":60},[33,525,527],{"class":35,"line":526},16,[33,528,529],{"class":60},"    body: raw,\n",[33,531,533],{"class":35,"line":532},17,[33,534,535],{"class":60},"  })\n",[33,537,539],{"class":35,"line":538},18,[33,540,237],{"emptyLinePlaceholder":236},[33,542,544,546,549,551,553,556,559],{"class":35,"line":543},19,[33,545,368],{"class":56},[33,547,548],{"class":87}," text",[33,550,248],{"class":56},[33,552,456],{"class":56},[33,554,555],{"class":60}," res.",[33,557,558],{"class":254},"text",[33,560,561],{"class":60},"()\n",[33,563,565,568,571,573,576,579,581,584,586,588,590,593,595,598,601,603,606,609,611,613],{"class":35,"line":564},20,[33,566,567],{"class":56},"  if",[33,569,570],{"class":60}," (",[33,572,264],{"class":56},[33,574,575],{"class":60},"res.ok) ",[33,577,578],{"class":56},"throw",[33,580,251],{"class":56},[33,582,583],{"class":254}," Error",[33,585,329],{"class":60},[33,587,464],{"class":43},[33,589,332],{"class":60},[33,591,592],{"class":43},"} ${",[33,594,344],{"class":60},[33,596,597],{"class":43},"} → ${",[33,599,600],{"class":60},"res",[33,602,410],{"class":43},[33,604,605],{"class":60},"status",[33,607,608],{"class":43},"}: ${",[33,610,558],{"class":60},[33,612,485],{"class":43},[33,614,267],{"class":60},[33,616,618],{"class":35,"line":617},21,[33,619,621],{"class":620},"sI3U9","  \u002F\u002F Some endpoints answer 200 with a JSON error object rather than an error status.\n",[33,623,625,627,630,632,635,637,640,642,645,648,650],{"class":35,"line":624},22,[33,626,368],{"class":56},[33,628,629],{"class":87}," parsed",[33,631,248],{"class":56},[33,633,634],{"class":60}," text ",[33,636,503],{"class":56},[33,638,639],{"class":87}," JSON",[33,641,410],{"class":60},[33,643,644],{"class":254},"parse",[33,646,647],{"class":60},"(text) ",[33,649,335],{"class":56},[33,651,652],{"class":87}," null\n",[33,654,656,658,661,664,667,670,672,675,678,681,684],{"class":35,"line":655},23,[33,657,567],{"class":56},[33,659,660],{"class":60}," (parsed ",[33,662,663],{"class":56},"&&",[33,665,666],{"class":56}," typeof",[33,668,669],{"class":60}," parsed ",[33,671,379],{"class":56},[33,673,674],{"class":43}," 'object'",[33,676,677],{"class":56}," &&",[33,679,680],{"class":43}," 'error'",[33,682,683],{"class":56}," in",[33,685,686],{"class":60}," parsed) {\n",[33,688,690,693,695,697,699,701,703,705,707,709,712,714,717,719],{"class":35,"line":689},24,[33,691,692],{"class":56},"    throw",[33,694,251],{"class":56},[33,696,583],{"class":254},[33,698,329],{"class":60},[33,700,464],{"class":43},[33,702,332],{"class":60},[33,704,592],{"class":43},[33,706,344],{"class":60},[33,708,597],{"class":43},[33,710,711],{"class":60},"parsed",[33,713,410],{"class":43},[33,715,716],{"class":60},"error",[33,718,485],{"class":43},[33,720,267],{"class":60},[33,722,724],{"class":35,"line":723},25,[33,725,726],{"class":60},"  }\n",[33,728,730,733],{"class":35,"line":729},26,[33,731,732],{"class":56},"  return",[33,734,735],{"class":60}," parsed\n",[33,737,739],{"class":35,"line":738},27,[33,740,157],{"class":60},[11,742,743],{},"Confirm it works before going further:",[23,745,747],{"className":213,"code":746,"language":215,"meta":28,"style":28},"await call('GET', '\u002Fauth\u002Fcheck') \u002F\u002F resolves on 204, throws on 401\n",[30,748,749],{"__ignoreMap":28},[33,750,751,754,756,758,761,763,766,769],{"class":35,"line":36},[33,752,753],{"class":56},"await",[33,755,326],{"class":254},[33,757,329],{"class":60},[33,759,760],{"class":43},"'GET'",[33,762,341],{"class":60},[33,764,765],{"class":43},"'\u002Fauth\u002Fcheck'",[33,767,768],{"class":60},") ",[33,770,771],{"class":620},"\u002F\u002F resolves on 204, throws on 401\n",[15,773,775],{"id":774},"_3-ask-where-to-write","3 — Ask where to write",[23,777,779],{"className":213,"code":778,"language":215,"meta":28,"style":28},"const { hosts } = await call('POST', '\u002Fprepare-write', {\n  totalShards: 15,\n  minShards: 10,\n})\n",[30,780,781,810,820,830],{"__ignoreMap":28},[33,782,783,785,787,790,792,794,796,798,800,803,805,808],{"class":35,"line":36},[33,784,242],{"class":56},[33,786,506],{"class":60},[33,788,789],{"class":87},"hosts",[33,791,517],{"class":60},[33,793,64],{"class":56},[33,795,456],{"class":56},[33,797,326],{"class":254},[33,799,329],{"class":60},[33,801,802],{"class":43},"'POST'",[33,804,341],{"class":60},[33,806,807],{"class":43},"'\u002Fprepare-write'",[33,809,488],{"class":60},[33,811,812,815,818],{"class":35,"line":53},[33,813,814],{"class":60},"  totalShards: ",[33,816,817],{"class":87},"15",[33,819,127],{"class":60},[33,821,822,825,828],{"class":35,"line":130},[33,823,824],{"class":60},"  minShards: ",[33,826,827],{"class":87},"10",[33,829,127],{"class":60},[33,831,832],{"class":35,"line":143},[33,833,834],{"class":60},"})\n",[23,836,838],{"className":103,"code":837,"language":105,"meta":28,"style":28},"{\n  \"hosts\": [\n    {\n      \"publicKey\": \"ed25519:9f3c1a...\",\n      \"address\": \"provider-1.example:9984\",\n      \"accountToken\": \"{\\\"hostKey\\\":\\\"ed25519:9f3c…\\\",\\\"account\\\":\\\"…\\\",\\\"validUntil\\\":…,\\\"signature\\\":\\\"…\\\"}\",\n      \"contractID\": \"a1b2c3...\"\n    }\n  ]\n}\n",[30,839,840,844,852,857,869,881,959,969,974,979],{"__ignoreMap":28},[33,841,842],{"class":35,"line":36},[33,843,112],{"class":60},[33,845,846,849],{"class":35,"line":53},[33,847,848],{"class":117},"  \"hosts\"",[33,850,851],{"class":60},": [\n",[33,853,854],{"class":35,"line":130},[33,855,856],{"class":60},"    {\n",[33,858,859,862,864,867],{"class":35,"line":143},[33,860,861],{"class":117},"      \"publicKey\"",[33,863,121],{"class":60},[33,865,866],{"class":43},"\"ed25519:9f3c1a...\"",[33,868,127],{"class":60},[33,870,871,874,876,879],{"class":35,"line":154},[33,872,873],{"class":117},"      \"address\"",[33,875,121],{"class":60},[33,877,878],{"class":43},"\"provider-1.example:9984\"",[33,880,127],{"class":60},[33,882,883,886,888,891,894,897,899,901,903,906,908,911,913,916,918,920,922,925,927,929,931,934,936,939,941,944,946,948,950,952,954,957],{"class":35,"line":294},[33,884,885],{"class":117},"      \"accountToken\"",[33,887,121],{"class":60},[33,889,890],{"class":43},"\"{",[33,892,893],{"class":56},"\\\"",[33,895,896],{"class":43},"hostKey",[33,898,893],{"class":56},[33,900,335],{"class":43},[33,902,893],{"class":56},[33,904,905],{"class":43},"ed25519:9f3c…",[33,907,893],{"class":56},[33,909,910],{"class":43},",",[33,912,893],{"class":56},[33,914,915],{"class":43},"account",[33,917,893],{"class":56},[33,919,335],{"class":43},[33,921,893],{"class":56},[33,923,924],{"class":43},"…",[33,926,893],{"class":56},[33,928,910],{"class":43},[33,930,893],{"class":56},[33,932,933],{"class":43},"validUntil",[33,935,893],{"class":56},[33,937,938],{"class":43},":…,",[33,940,893],{"class":56},[33,942,943],{"class":43},"signature",[33,945,893],{"class":56},[33,947,335],{"class":43},[33,949,893],{"class":56},[33,951,924],{"class":43},[33,953,893],{"class":56},[33,955,956],{"class":43},"}\"",[33,958,127],{"class":60},[33,960,961,964,966],{"class":35,"line":307},[33,962,963],{"class":117},"      \"contractID\"",[33,965,121],{"class":60},[33,967,968],{"class":43},"\"a1b2c3...\"\n",[33,970,971],{"class":35,"line":312},[33,972,973],{"class":60},"    }\n",[33,975,976],{"class":35,"line":317},[33,977,978],{"class":60},"  ]\n",[33,980,981],{"class":35,"line":365},[33,982,157],{"class":60},[11,984,985,986,990,991,994],{},"You get 15 entries, each a ",[987,988,989],"strong",{},"different"," provider, with a funded contract and an ",[30,992,993],{},"accountToken","\nthat authorises your writes. Treat the token as opaque and hand it to the transfer protocol\nunmodified.",[15,996,998],{"id":997},"_4-encrypt-split-and-write","4 — Encrypt, split, and write",[11,1000,1001],{},"Encryption first, then erasure coding. In that order — coding ciphertext means a provider holds a\nfragment of ciphertext; coding first and encrypting after would defeat the point.",[23,1003,1005],{"className":213,"code":1004,"language":215,"meta":28,"style":28},"import { createCipheriv, randomBytes } from 'node:crypto'\nimport { ReedSolomon } from 'your-rs-library'\n\nconst MIN_SHARDS = 10\nconst TOTAL_SHARDS = 15\n\n\u002F\u002F 4a — encrypt\nconst dataKey = randomBytes(32)\nconst iv = randomBytes(16)\nconst cipher = createCipheriv('aes-256-ctr', dataKey, iv)\nconst ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()])\n\n\u002F\u002F 4b — erasure code: 10 data shards + 5 parity\nconst shardSize = Math.ceil(ciphertext.length \u002F MIN_SHARDS)\nconst shards: Uint8Array[] = []\nfor (let i = 0; i \u003C MIN_SHARDS; i++) {\n  const shard = new Uint8Array(shardSize)\n  shard.set(ciphertext.subarray(i * shardSize, (i + 1) * shardSize))\n  shards.push(shard)\n}\nfor (let i = 0; i \u003C TOTAL_SHARDS - MIN_SHARDS; i++) shards.push(new Uint8Array(shardSize))\n\nconst rs = new ReedSolomon(MIN_SHARDS, TOTAL_SHARDS - MIN_SHARDS)\nrs.encode(shards)\n\n\u002F\u002F 4c — write shard i directly to provider i, and keep the sector root it returns\nconst sectors = await Promise.all(\n  shards.map(async (shard, i) => ({\n    host: hosts[i].publicKey,\n    root: await writeSectorToProvider(hosts[i], shard), \u002F\u002F your transfer client\n    contractID: hosts[i].contractID,\n  })),\n)\n",[30,1006,1007,1019,1031,1035,1047,1059,1063,1068,1087,1105,1125,1155,1159,1164,1192,1212,1246,1262,1297,1308,1312,1356,1360,1390,1400,1404,1409,1431,1461,1467,1484,1490,1496],{"__ignoreMap":28},[33,1008,1009,1011,1014,1016],{"class":35,"line":36},[33,1010,222],{"class":56},[33,1012,1013],{"class":60}," { createCipheriv, randomBytes } ",[33,1015,228],{"class":56},[33,1017,1018],{"class":43}," 'node:crypto'\n",[33,1020,1021,1023,1026,1028],{"class":35,"line":53},[33,1022,222],{"class":56},[33,1024,1025],{"class":60}," { ReedSolomon } ",[33,1027,228],{"class":56},[33,1029,1030],{"class":43}," 'your-rs-library'\n",[33,1032,1033],{"class":35,"line":130},[33,1034,237],{"emptyLinePlaceholder":236},[33,1036,1037,1039,1042,1044],{"class":35,"line":143},[33,1038,242],{"class":56},[33,1040,1041],{"class":87}," MIN_SHARDS",[33,1043,248],{"class":56},[33,1045,1046],{"class":87}," 10\n",[33,1048,1049,1051,1054,1056],{"class":35,"line":154},[33,1050,242],{"class":56},[33,1052,1053],{"class":87}," TOTAL_SHARDS",[33,1055,248],{"class":56},[33,1057,1058],{"class":87}," 15\n",[33,1060,1061],{"class":35,"line":294},[33,1062,237],{"emptyLinePlaceholder":236},[33,1064,1065],{"class":35,"line":307},[33,1066,1067],{"class":620},"\u002F\u002F 4a — encrypt\n",[33,1069,1070,1072,1075,1077,1080,1082,1085],{"class":35,"line":312},[33,1071,242],{"class":56},[33,1073,1074],{"class":87}," dataKey",[33,1076,248],{"class":56},[33,1078,1079],{"class":254}," randomBytes",[33,1081,329],{"class":60},[33,1083,1084],{"class":87},"32",[33,1086,267],{"class":60},[33,1088,1089,1091,1094,1096,1098,1100,1103],{"class":35,"line":317},[33,1090,242],{"class":56},[33,1092,1093],{"class":87}," iv",[33,1095,248],{"class":56},[33,1097,1079],{"class":254},[33,1099,329],{"class":60},[33,1101,1102],{"class":87},"16",[33,1104,267],{"class":60},[33,1106,1107,1109,1112,1114,1117,1119,1122],{"class":35,"line":365},[33,1108,242],{"class":56},[33,1110,1111],{"class":87}," cipher",[33,1113,248],{"class":56},[33,1115,1116],{"class":254}," createCipheriv",[33,1118,329],{"class":60},[33,1120,1121],{"class":43},"'aes-256-ctr'",[33,1123,1124],{"class":60},", dataKey, iv)\n",[33,1126,1127,1129,1132,1134,1137,1140,1143,1146,1149,1152],{"class":35,"line":419},[33,1128,242],{"class":56},[33,1130,1131],{"class":87}," ciphertext",[33,1133,248],{"class":56},[33,1135,1136],{"class":60}," Buffer.",[33,1138,1139],{"class":254},"concat",[33,1141,1142],{"class":60},"([cipher.",[33,1144,1145],{"class":254},"update",[33,1147,1148],{"class":60},"(plaintext), cipher.",[33,1150,1151],{"class":254},"final",[33,1153,1154],{"class":60},"()])\n",[33,1156,1157],{"class":35,"line":441},[33,1158,237],{"emptyLinePlaceholder":236},[33,1160,1161],{"class":35,"line":446},[33,1162,1163],{"class":620},"\u002F\u002F 4b — erasure code: 10 data shards + 5 parity\n",[33,1165,1166,1168,1171,1173,1176,1179,1182,1185,1188,1190],{"class":35,"line":491},[33,1167,242],{"class":56},[33,1169,1170],{"class":87}," shardSize",[33,1172,248],{"class":56},[33,1174,1175],{"class":60}," Math.",[33,1177,1178],{"class":254},"ceil",[33,1180,1181],{"class":60},"(ciphertext.",[33,1183,1184],{"class":87},"length",[33,1186,1187],{"class":56}," \u002F",[33,1189,1041],{"class":87},[33,1191,267],{"class":60},[33,1193,1194,1196,1199,1201,1204,1207,1209],{"class":35,"line":497},[33,1195,242],{"class":56},[33,1197,1198],{"class":87}," shards",[33,1200,335],{"class":56},[33,1202,1203],{"class":39}," Uint8Array",[33,1205,1206],{"class":60},"[] ",[33,1208,64],{"class":56},[33,1210,1211],{"class":60}," []\n",[33,1213,1214,1217,1219,1222,1225,1227,1230,1233,1236,1238,1241,1244],{"class":35,"line":526},[33,1215,1216],{"class":56},"for",[33,1218,570],{"class":60},[33,1220,1221],{"class":56},"let",[33,1223,1224],{"class":60}," i ",[33,1226,64],{"class":56},[33,1228,1229],{"class":87}," 0",[33,1231,1232],{"class":60},"; i ",[33,1234,1235],{"class":56},"\u003C",[33,1237,1041],{"class":87},[33,1239,1240],{"class":60},"; i",[33,1242,1243],{"class":56},"++",[33,1245,362],{"class":60},[33,1247,1248,1250,1253,1255,1257,1259],{"class":35,"line":532},[33,1249,368],{"class":56},[33,1251,1252],{"class":87}," shard",[33,1254,248],{"class":56},[33,1256,251],{"class":56},[33,1258,1203],{"class":254},[33,1260,1261],{"class":60},"(shardSize)\n",[33,1263,1264,1267,1270,1272,1275,1278,1281,1284,1287,1290,1292,1294],{"class":35,"line":538},[33,1265,1266],{"class":60},"  shard.",[33,1268,1269],{"class":254},"set",[33,1271,1181],{"class":60},[33,1273,1274],{"class":254},"subarray",[33,1276,1277],{"class":60},"(i ",[33,1279,1280],{"class":56},"*",[33,1282,1283],{"class":60}," shardSize, (i ",[33,1285,1286],{"class":56},"+",[33,1288,1289],{"class":87}," 1",[33,1291,768],{"class":60},[33,1293,1280],{"class":56},[33,1295,1296],{"class":60}," shardSize))\n",[33,1298,1299,1302,1305],{"class":35,"line":543},[33,1300,1301],{"class":60},"  shards.",[33,1303,1304],{"class":254},"push",[33,1306,1307],{"class":60},"(shard)\n",[33,1309,1310],{"class":35,"line":564},[33,1311,157],{"class":60},[33,1313,1314,1316,1318,1320,1322,1324,1326,1328,1330,1332,1335,1337,1339,1341,1344,1346,1348,1351,1353],{"class":35,"line":617},[33,1315,1216],{"class":56},[33,1317,570],{"class":60},[33,1319,1221],{"class":56},[33,1321,1224],{"class":60},[33,1323,64],{"class":56},[33,1325,1229],{"class":87},[33,1327,1232],{"class":60},[33,1329,1235],{"class":56},[33,1331,1053],{"class":87},[33,1333,1334],{"class":56}," -",[33,1336,1041],{"class":87},[33,1338,1240],{"class":60},[33,1340,1243],{"class":56},[33,1342,1343],{"class":60},") shards.",[33,1345,1304],{"class":254},[33,1347,329],{"class":60},[33,1349,1350],{"class":56},"new",[33,1352,1203],{"class":254},[33,1354,1355],{"class":60},"(shardSize))\n",[33,1357,1358],{"class":35,"line":624},[33,1359,237],{"emptyLinePlaceholder":236},[33,1361,1362,1364,1367,1369,1371,1374,1376,1379,1381,1384,1386,1388],{"class":35,"line":655},[33,1363,242],{"class":56},[33,1365,1366],{"class":87}," rs",[33,1368,248],{"class":56},[33,1370,251],{"class":56},[33,1372,1373],{"class":254}," ReedSolomon",[33,1375,329],{"class":60},[33,1377,1378],{"class":87},"MIN_SHARDS",[33,1380,341],{"class":60},[33,1382,1383],{"class":87},"TOTAL_SHARDS",[33,1385,1334],{"class":56},[33,1387,1041],{"class":87},[33,1389,267],{"class":60},[33,1391,1392,1395,1397],{"class":35,"line":689},[33,1393,1394],{"class":60},"rs.",[33,1396,402],{"class":254},[33,1398,1399],{"class":60},"(shards)\n",[33,1401,1402],{"class":35,"line":723},[33,1403,237],{"emptyLinePlaceholder":236},[33,1405,1406],{"class":35,"line":729},[33,1407,1408],{"class":620},"\u002F\u002F 4c — write shard i directly to provider i, and keep the sector root it returns\n",[33,1410,1411,1413,1416,1418,1420,1423,1425,1428],{"class":35,"line":738},[33,1412,242],{"class":56},[33,1414,1415],{"class":87}," sectors",[33,1417,248],{"class":56},[33,1419,456],{"class":56},[33,1421,1422],{"class":87}," Promise",[33,1424,410],{"class":60},[33,1426,1427],{"class":254},"all",[33,1429,1430],{"class":60},"(\n",[33,1432,1434,1436,1439,1441,1443,1445,1448,1450,1453,1455,1458],{"class":35,"line":1433},28,[33,1435,1301],{"class":60},[33,1437,1438],{"class":254},"map",[33,1440,329],{"class":60},[33,1442,320],{"class":56},[33,1444,570],{"class":60},[33,1446,1447],{"class":39},"shard",[33,1449,341],{"class":60},[33,1451,1452],{"class":39},"i",[33,1454,768],{"class":60},[33,1456,1457],{"class":56},"=>",[33,1459,1460],{"class":60}," ({\n",[33,1462,1464],{"class":35,"line":1463},29,[33,1465,1466],{"class":60},"    host: hosts[i].publicKey,\n",[33,1468,1470,1473,1475,1478,1481],{"class":35,"line":1469},30,[33,1471,1472],{"class":60},"    root: ",[33,1474,753],{"class":56},[33,1476,1477],{"class":254}," writeSectorToProvider",[33,1479,1480],{"class":60},"(hosts[i], shard), ",[33,1482,1483],{"class":620},"\u002F\u002F your transfer client\n",[33,1485,1487],{"class":35,"line":1486},31,[33,1488,1489],{"class":60},"    contractID: hosts[i].contractID,\n",[33,1491,1493],{"class":35,"line":1492},32,[33,1494,1495],{"class":60},"  })),\n",[33,1497,1499],{"class":35,"line":1498},33,[33,1500,267],{"class":60},[159,1502,1505],{"title":1503,"tone":1504},"Write failures are expected, and cheap","note",[11,1506,1507,1508,1511],{},"Providers time out. When a shard write fails, do not retry it forever — request another provider\nfrom ",[30,1509,1510],{},"\u002Fprepare-write"," and place the shard there instead. You need 15 successful placements out of\nhowever many attempts it takes; which specific providers they land on does not matter.",[15,1513,1515],{"id":1514},"_5-register-the-slab","5 — Register the slab",[11,1517,1518],{},"Now tell Tessera what you did. This is what makes the data findable later.",[23,1520,1522],{"className":213,"code":1521,"language":215,"meta":28,"style":28},"const [slabID] = await call('POST', '\u002Fslabs', [\n  {\n    version: 1,\n    minShards: MIN_SHARDS,\n    encryptionKey: iv32Base64,   \u002F\u002F 32 bytes, standard base64\n    sectors,                      \u002F\u002F 15 entries, one per provider\n  },\n])\n",[30,1523,1524,1555,1560,1570,1579,1587,1595,1600],{"__ignoreMap":28},[33,1525,1526,1528,1531,1534,1537,1539,1541,1543,1545,1547,1549,1552],{"class":35,"line":36},[33,1527,242],{"class":56},[33,1529,1530],{"class":60}," [",[33,1532,1533],{"class":87},"slabID",[33,1535,1536],{"class":60},"] ",[33,1538,64],{"class":56},[33,1540,456],{"class":56},[33,1542,326],{"class":254},[33,1544,329],{"class":60},[33,1546,802],{"class":43},[33,1548,341],{"class":60},[33,1550,1551],{"class":43},"'\u002Fslabs'",[33,1553,1554],{"class":60},", [\n",[33,1556,1557],{"class":35,"line":53},[33,1558,1559],{"class":60},"  {\n",[33,1561,1562,1565,1568],{"class":35,"line":130},[33,1563,1564],{"class":60},"    version: ",[33,1566,1567],{"class":87},"1",[33,1569,127],{"class":60},[33,1571,1572,1575,1577],{"class":35,"line":143},[33,1573,1574],{"class":60},"    minShards: ",[33,1576,1378],{"class":87},[33,1578,127],{"class":60},[33,1580,1581,1584],{"class":35,"line":154},[33,1582,1583],{"class":60},"    encryptionKey: iv32Base64,   ",[33,1585,1586],{"class":620},"\u002F\u002F 32 bytes, standard base64\n",[33,1588,1589,1592],{"class":35,"line":294},[33,1590,1591],{"class":60},"    sectors,                      ",[33,1593,1594],{"class":620},"\u002F\u002F 15 entries, one per provider\n",[33,1596,1597],{"class":35,"line":307},[33,1598,1599],{"class":60},"  },\n",[33,1601,1602],{"class":35,"line":312},[33,1603,1604],{"class":60},"])\n",[11,1606,1607],{},"The response is an array of hex slab IDs, in the same order as your request. The ID is a digest of\nthe slab's parameters, so registering identical parameters twice returns the same ID rather than\ncreating a duplicate.",[15,1609,1611],{"id":1610},"_6-register-the-object","6 — Register the object",[23,1613,1615],{"className":213,"code":1614,"language":215,"meta":28,"style":28},"const objectKey = sha256Hex(plaintext) \u002F\u002F your choice; a content hash gives free dedup\n\nawait call('POST', '\u002Fobjects', {\n  id: objectKey,\n  encryptedDataKey: wrap(dataKey),          \u002F\u002F wrapped by your key — we cannot unwrap it\n  slabs: [{ id: slabID, offset: 0, length: ciphertext.length }],\n  encryptedMetadata: encrypt({ name: 'hello.txt', size: plaintext.length }),\n  encryptedMetadataKey: wrap(metadataKey),\n  dataSignature: signOverData,\n  metadataSignature: signOverMetadata,\n})\n",[30,1616,1617,1635,1639,1656,1661,1675,1691,1713,1723,1728,1733],{"__ignoreMap":28},[33,1618,1619,1621,1624,1626,1629,1632],{"class":35,"line":36},[33,1620,242],{"class":56},[33,1622,1623],{"class":87}," objectKey",[33,1625,248],{"class":56},[33,1627,1628],{"class":254}," sha256Hex",[33,1630,1631],{"class":60},"(plaintext) ",[33,1633,1634],{"class":620},"\u002F\u002F your choice; a content hash gives free dedup\n",[33,1636,1637],{"class":35,"line":53},[33,1638,237],{"emptyLinePlaceholder":236},[33,1640,1641,1643,1645,1647,1649,1651,1654],{"class":35,"line":130},[33,1642,753],{"class":56},[33,1644,326],{"class":254},[33,1646,329],{"class":60},[33,1648,802],{"class":43},[33,1650,341],{"class":60},[33,1652,1653],{"class":43},"'\u002Fobjects'",[33,1655,488],{"class":60},[33,1657,1658],{"class":35,"line":143},[33,1659,1660],{"class":60},"  id: objectKey,\n",[33,1662,1663,1666,1669,1672],{"class":35,"line":154},[33,1664,1665],{"class":60},"  encryptedDataKey: ",[33,1667,1668],{"class":254},"wrap",[33,1670,1671],{"class":60},"(dataKey),          ",[33,1673,1674],{"class":620},"\u002F\u002F wrapped by your key — we cannot unwrap it\n",[33,1676,1677,1680,1683,1686,1688],{"class":35,"line":294},[33,1678,1679],{"class":60},"  slabs: [{ id: slabID, offset: ",[33,1681,1682],{"class":87},"0",[33,1684,1685],{"class":60},", length: ciphertext.",[33,1687,1184],{"class":87},[33,1689,1690],{"class":60}," }],\n",[33,1692,1693,1696,1699,1702,1705,1708,1710],{"class":35,"line":307},[33,1694,1695],{"class":60},"  encryptedMetadata: ",[33,1697,1698],{"class":254},"encrypt",[33,1700,1701],{"class":60},"({ name: ",[33,1703,1704],{"class":43},"'hello.txt'",[33,1706,1707],{"class":60},", size: plaintext.",[33,1709,1184],{"class":87},[33,1711,1712],{"class":60}," }),\n",[33,1714,1715,1718,1720],{"class":35,"line":312},[33,1716,1717],{"class":60},"  encryptedMetadataKey: ",[33,1719,1668],{"class":254},[33,1721,1722],{"class":60},"(metadataKey),\n",[33,1724,1725],{"class":35,"line":317},[33,1726,1727],{"class":60},"  dataSignature: signOverData,\n",[33,1729,1730],{"class":35,"line":365},[33,1731,1732],{"class":60},"  metadataSignature: signOverMetadata,\n",[33,1734,1735],{"class":35,"line":419},[33,1736,834],{"class":60},[11,1738,1739,1740,1743],{},"The object is now stored. ",[30,1741,1742],{},"encryptedMetadata"," is where filenames live — the API has no field for\none, and never will.",[15,1745,1747],{"id":1746},"_7-read-it-back","7 — Read it back",[23,1749,1751],{"className":213,"code":1750,"language":215,"meta":28,"style":28},"\u002F\u002F 7a — placement record\nconst obj = await call('GET', `\u002Fobjects\u002F${objectKey}`)\n\n\u002F\u002F 7b — for each slab, the providers and sector roots\nconst slab = await call('GET', `\u002Fslabs\u002F${obj.slabs[0].id}`)\n\n\u002F\u002F 7c — fetch any 10 of the 15 shards, directly from providers\nconst fetched = await fetchAnyN(slab.sectors, slab.minShards)\n\n\u002F\u002F 7d — reconstruct, then decrypt\nconst rs = new ReedSolomon(slab.minShards, slab.sectors.length - slab.minShards)\nrs.reconstruct(fetched)\nconst plaintext = decrypt(join(fetched).subarray(0, obj.slabs[0].length), unwrap(obj.encryptedDataKey))\n",[30,1752,1753,1758,1787,1791,1796,1841,1845,1850,1867,1871,1876,1898,1908],{"__ignoreMap":28},[33,1754,1755],{"class":35,"line":36},[33,1756,1757],{"class":620},"\u002F\u002F 7a — placement record\n",[33,1759,1760,1762,1765,1767,1769,1771,1773,1775,1777,1780,1783,1785],{"class":35,"line":53},[33,1761,242],{"class":56},[33,1763,1764],{"class":87}," obj",[33,1766,248],{"class":56},[33,1768,456],{"class":56},[33,1770,326],{"class":254},[33,1772,329],{"class":60},[33,1774,760],{"class":43},[33,1776,341],{"class":60},[33,1778,1779],{"class":43},"`\u002Fobjects\u002F${",[33,1781,1782],{"class":60},"objectKey",[33,1784,485],{"class":43},[33,1786,267],{"class":60},[33,1788,1789],{"class":35,"line":130},[33,1790,237],{"emptyLinePlaceholder":236},[33,1792,1793],{"class":35,"line":143},[33,1794,1795],{"class":620},"\u002F\u002F 7b — for each slab, the providers and sector roots\n",[33,1797,1798,1800,1803,1805,1807,1809,1811,1813,1815,1818,1821,1823,1826,1829,1831,1834,1837,1839],{"class":35,"line":154},[33,1799,242],{"class":56},[33,1801,1802],{"class":87}," slab",[33,1804,248],{"class":56},[33,1806,456],{"class":56},[33,1808,326],{"class":254},[33,1810,329],{"class":60},[33,1812,760],{"class":43},[33,1814,341],{"class":60},[33,1816,1817],{"class":43},"`\u002Fslabs\u002F${",[33,1819,1820],{"class":60},"obj",[33,1822,410],{"class":43},[33,1824,1825],{"class":60},"slabs",[33,1827,1828],{"class":43},"[",[33,1830,1682],{"class":87},[33,1832,1833],{"class":43},"].",[33,1835,1836],{"class":60},"id",[33,1838,485],{"class":43},[33,1840,267],{"class":60},[33,1842,1843],{"class":35,"line":294},[33,1844,237],{"emptyLinePlaceholder":236},[33,1846,1847],{"class":35,"line":307},[33,1848,1849],{"class":620},"\u002F\u002F 7c — fetch any 10 of the 15 shards, directly from providers\n",[33,1851,1852,1854,1857,1859,1861,1864],{"class":35,"line":312},[33,1853,242],{"class":56},[33,1855,1856],{"class":87}," fetched",[33,1858,248],{"class":56},[33,1860,456],{"class":56},[33,1862,1863],{"class":254}," fetchAnyN",[33,1865,1866],{"class":60},"(slab.sectors, slab.minShards)\n",[33,1868,1869],{"class":35,"line":317},[33,1870,237],{"emptyLinePlaceholder":236},[33,1872,1873],{"class":35,"line":365},[33,1874,1875],{"class":620},"\u002F\u002F 7d — reconstruct, then decrypt\n",[33,1877,1878,1880,1882,1884,1886,1888,1891,1893,1895],{"class":35,"line":419},[33,1879,242],{"class":56},[33,1881,1366],{"class":87},[33,1883,248],{"class":56},[33,1885,251],{"class":56},[33,1887,1373],{"class":254},[33,1889,1890],{"class":60},"(slab.minShards, slab.sectors.",[33,1892,1184],{"class":87},[33,1894,1334],{"class":56},[33,1896,1897],{"class":60}," slab.minShards)\n",[33,1899,1900,1902,1905],{"class":35,"line":441},[33,1901,1394],{"class":60},[33,1903,1904],{"class":254},"reconstruct",[33,1906,1907],{"class":60},"(fetched)\n",[33,1909,1910,1912,1915,1917,1920,1922,1925,1928,1930,1932,1934,1937,1939,1941,1943,1946,1949],{"class":35,"line":446},[33,1911,242],{"class":56},[33,1913,1914],{"class":87}," plaintext",[33,1916,248],{"class":56},[33,1918,1919],{"class":254}," decrypt",[33,1921,329],{"class":60},[33,1923,1924],{"class":254},"join",[33,1926,1927],{"class":60},"(fetched).",[33,1929,1274],{"class":254},[33,1931,329],{"class":60},[33,1933,1682],{"class":87},[33,1935,1936],{"class":60},", obj.slabs[",[33,1938,1682],{"class":87},[33,1940,1833],{"class":60},[33,1942,1184],{"class":87},[33,1944,1945],{"class":60},"), ",[33,1947,1948],{"class":254},"unwrap",[33,1950,1951],{"class":60},"(obj.encryptedDataKey))\n",[11,1953,1954],{},"Ten shards is the threshold, but fetch a couple extra in parallel and take the first ten to return —\nit costs nothing and removes the slowest provider from your critical path.",[15,1956,1958],{"id":1957},"_8-clean-up","8 — Clean up",[23,1960,1962],{"className":25,"code":1961,"language":27,"meta":28,"style":28},"curl -X DELETE \"$TESSERA_API\u002Fobjects\u002F$OBJECT_KEY?$AUTH\"   # 204\ncurl -X POST   \"$TESSERA_API\u002Fslabs\u002Fprune?$AUTH\"           # {\"pruned\": 1}\n",[30,1963,1964,1994],{"__ignoreMap":28},[33,1965,1966,1968,1970,1973,1975,1977,1980,1983,1985,1988,1991],{"class":35,"line":36},[33,1967,84],{"class":39},[33,1969,88],{"class":87},[33,1971,1972],{"class":43}," DELETE",[33,1974,94],{"class":43},[33,1976,97],{"class":60},[33,1978,1979],{"class":43},"\u002Fobjects\u002F",[33,1981,1982],{"class":60},"$OBJECT_KEY",[33,1984,503],{"class":43},[33,1986,1987],{"class":60},"$AUTH",[33,1989,1990],{"class":43},"\"",[33,1992,1993],{"class":620},"   # 204\n",[33,1995,1996,1998,2000,2002,2005,2007,2010,2012,2014],{"class":35,"line":53},[33,1997,84],{"class":39},[33,1999,88],{"class":87},[33,2001,91],{"class":43},[33,2003,2004],{"class":43},"   \"",[33,2006,97],{"class":60},[33,2008,2009],{"class":43},"\u002Fslabs\u002Fprune?",[33,2011,1987],{"class":60},[33,2013,1990],{"class":43},[33,2015,2016],{"class":620},"           # {\"pruned\": 1}\n",[11,2018,2019,2020,2023],{},"Deleting an object does not delete its slabs, because another object may reference them. ",[30,2021,2022],{},"prune","\nreclaims slabs nothing references any more.",[15,2025,2027],{"id":2026},"what-to-build-next","What to build next",[2029,2030,2031,2050,2062,2068],"ul",{},[2032,2033,2034,2037,2038,2041,2042,2045,2046,410],"li",{},[987,2035,2036],{},"Persist your placement records."," ",[30,2039,2040],{},"GET \u002Fobjects"," and ",[30,2043,2044],{},"GET \u002Fslabs\u002F{id}"," give you everything\nneeded to recover without us. Export on a schedule — see\n",[206,2047,2049],{"href":2048},"\u002Fdocs\u002Frecovery","Recovery without Tessera",[2032,2051,2052,2055,2056,2041,2059,2061],{},[987,2053,2054],{},"Pack small objects into shared slabs."," A slab has a 15-provider round trip; amortise it across\nmany small objects using ",[30,2057,2058],{},"offset",[30,2060,1184],{}," rather than paying it per object.",[2032,2063,2064,2067],{},[987,2065,2066],{},"Keep a local index"," if you need listing or search, since the server cannot read your metadata.",[2032,2069,2070,2076,2077,410],{},[987,2071,2072,2073,410],{},"Handle ",[30,2074,2075],{},"429"," The limit is 30 requests per minute per credential; respect ",[30,2078,2079],{},"Retry-After",[2081,2082,2083],"style",{},"html pre.shiki code .sAxfE, html code.shiki .sAxfE{--shiki-default:#FFA657;--shiki-dark:#FFA657}html pre.shiki code .skZ57, html code.shiki .skZ57{--shiki-default:#A5D6FF;--shiki-dark:#A5D6FF}html pre.shiki code .srH4v, html code.shiki .srH4v{--shiki-default:#FF7B72;--shiki-dark:#FF7B72}html pre.shiki code .sb7RM, html code.shiki .sb7RM{--shiki-default:#E6EDF3;--shiki-dark:#E6EDF3}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sEQcL, html code.shiki .sEQcL{--shiki-default:#79C0FF;--shiki-dark:#79C0FF}html pre.shiki code .sV7Mv, html code.shiki .sV7Mv{--shiki-default:#7EE787;--shiki-dark:#7EE787}html pre.shiki code .sYGIp, html code.shiki .sYGIp{--shiki-default:#D2A8FF;--shiki-dark:#D2A8FF}html pre.shiki code .sI3U9, html code.shiki .sI3U9{--shiki-default:#8B949E;--shiki-dark:#8B949E}",{"title":28,"searchDepth":130,"depth":130,"links":2085},[2086,2087,2088,2089,2090,2091,2092,2093,2094,2095],{"id":17,"depth":53,"text":18},{"id":70,"depth":53,"text":71},{"id":196,"depth":53,"text":197},{"id":774,"depth":53,"text":775},{"id":997,"depth":53,"text":998},{"id":1514,"depth":53,"text":1515},{"id":1610,"depth":53,"text":1611},{"id":1746,"depth":53,"text":1747},{"id":1957,"depth":53,"text":1958},{"id":2026,"depth":53,"text":2027},"Provision a credential, upload an object across 15 providers, and read it back. Fifteen minutes, one file of code.","md",{},"\u002Fdocs\u002Fquickstart","Guides",{"title":5,"description":2096},"docs\u002Fquickstart","a1V7nkK-Vpz0th5KXFa2hJ6skVWIklWgkFLg1dgqoq0",[2105,2110,2114,2118,2122,2126,2128,2133,2138,2142,2146,2147],{"path":2106,"title":2107,"description":2108,"section":2109,"order":154,"badge":6},"\u002Fdocs\u002Fapi\u002Faccount","Account","GET \u002Faccount — stored, read, and written byte counters for your credential.","API reference",{"path":2111,"title":2112,"description":2113,"section":2109,"order":143,"badge":6},"\u002Fdocs\u002Fapi\u002Fobjects","Objects","Register, read, list, and delete objects — ordered lists of slab segments with encrypted keys and opaque metadata.",{"path":2115,"title":2116,"description":2117,"section":2109,"order":53,"badge":6},"\u002Fdocs\u002Fapi\u002Fplacement","Placement","POST \u002Fprepare-write — get the providers, contracts, and access tokens for writing a slab's shards.",{"path":2119,"title":2120,"description":2121,"section":2109,"order":36,"badge":6},"\u002Fdocs\u002Fapi\u002Fprovisioning","Credentials","Provision, verify, and revoke the ed25519 credential that is both your API identity and your account.",{"path":2123,"title":2124,"description":2125,"section":2109,"order":130,"badge":6},"\u002Fdocs\u002Fapi\u002Fslabs","Slabs","Register, read, list, unpin, and prune erasure-coded slabs — the layer that records which provider holds which shard.",{"path":208,"title":209,"description":2127,"section":2100,"order":53,"badge":6},"Every request is signed with ed25519 over a blake2b hash of the method, host, path, expiry, and body. Here is the exact construction, with working code.",{"path":2129,"title":2130,"description":2131,"section":2132,"order":53,"badge":6},"\u002Fdocs\u002Fconcepts","Concepts & data model","Sectors, shards, slabs, objects, and accounts — what each one is, why the model has no filenames, and what that means for your integration.","Introduction",{"path":2134,"title":2135,"description":2136,"section":2137,"order":36,"badge":6},"\u002Fdocs\u002Ferrors","Errors","Status codes, the two different error body formats, and the one case where a failure arrives with a 200.","Reference",{"path":2139,"title":2140,"description":2141,"section":2132,"order":36,"badge":6},"\u002Fdocs","Overview","Tessera is an HTTP API for storing encrypted, erasure-coded objects across independent storage providers. This is the reference for it.",{"path":2143,"title":2144,"description":2145,"section":2137,"order":53,"badge":6},"\u002Fdocs\u002Flimits","Limits & quotas","Rate limits, storage caps, geometry constraints, and the size and encoding limits that apply to every request.",{"path":2099,"title":5,"description":2096,"section":2100,"order":36,"badge":6},{"path":2048,"title":2049,"description":2148,"section":2100,"order":130,"badge":6},"How to retrieve your data if Tessera is unavailable, unwilling, or permanently gone — and what you need to keep on hand for that to work.",1786190911609]