[{"data":1,"prerenderedAt":1668},["ShallowReactive",2],{"navigation":3,"/sdks/node":258,"/sdks/node-surround":1663},[4,22,63,85,115,131,219,245],{"title":5,"path":6,"stem":7,"children":8,"page":21},"Getting Started","/getting-started","1.getting-started",[9,13,17],{"title":10,"path":11,"stem":12},"Introduction","/getting-started/introduction","1.getting-started/1.introduction",{"title":14,"path":15,"stem":16},"Quick Start","/getting-started/quick-start","1.getting-started/2.quick-start",{"title":18,"path":19,"stem":20},"Key Concepts","/getting-started/key-concepts","1.getting-started/3.key-concepts",false,{"title":23,"path":24,"stem":25,"children":26,"page":21},"Guides","/guides","2.guides",[27,31,35,39,43,47,51,55,59],{"title":28,"path":29,"stem":30},"Quick Share Guide","/guides/quick-share","2.guides/1.quick-share",{"title":32,"path":33,"stem":34},"Slack Integration","/guides/slack-integration","2.guides/2.slack-integration",{"title":36,"path":37,"stem":38},"Enterprise Setup","/guides/enterprise-setup","2.guides/3.enterprise-setup",{"title":40,"path":41,"stem":42},"Creating a Share","/guides/creating-a-share","2.guides/4.creating-a-share",{"title":44,"path":45,"stem":46},"Zero-Knowledge Custody","/guides/zero-knowledge-custody","2.guides/5.zero-knowledge-custody",{"title":48,"path":49,"stem":50},"Secure Requests","/guides/secure-requests","2.guides/6.secure-requests",{"title":52,"path":53,"stem":54},"Receiving a Secure Request","/guides/receiving-a-secure-request","2.guides/7.receiving-a-secure-request",{"title":56,"path":57,"stem":58},"SecurePaste","/guides/securepaste","2.guides/8.securepaste",{"title":60,"path":61,"stem":62},"Notifications","/guides/notifications","2.guides/9.notifications",{"title":64,"icon":65,"path":66,"stem":67,"children":68,"page":21},"Account","i-lucide-user-cog","/account","3.account",[69,73,77,81],{"title":70,"path":71,"stem":72},"Signing In","/account/signing-in","3.account/1.signing-in",{"title":74,"path":75,"stem":76},"Plans and Share Allowance","/account/plans-and-share-allowance","3.account/2.plans-and-share-allowance",{"title":78,"path":79,"stem":80},"Billing and Subscription","/account/billing-and-subscription","3.account/3.billing-and-subscription",{"title":82,"path":83,"stem":84},"Plans and Limits","/account/plans-and-limits","3.account/4.plans-and-limits",{"title":86,"icon":87,"path":88,"stem":89,"children":90,"page":21},"Teams","i-lucide-users","/teams","4.teams",[91,95,99,103,107,111],{"title":92,"path":93,"stem":94},"Teams and Contexts","/teams/teams-and-contexts","4.teams/1.teams-and-contexts",{"title":96,"path":97,"stem":98},"Members, Roles and Seats","/teams/members-roles-and-seats","4.teams/2.members-roles-and-seats",{"title":100,"path":101,"stem":102},"Joining a Team","/teams/joining-a-team","4.teams/3.joining-a-team",{"title":104,"path":105,"stem":106},"Custom Branding","/teams/custom-branding","4.teams/4.custom-branding",{"title":108,"path":109,"stem":110},"Policy and Audit","/teams/policy-and-audit","4.teams/5.policy-and-audit",{"title":112,"path":113,"stem":114},"Zero-Knowledge for Teams","/teams/zero-knowledge-for-teams","4.teams/6.zero-knowledge-for-teams",{"title":116,"path":117,"stem":118,"children":119,"icon":130},"Help","/help","5.help/0.index",[120,122,126],{"title":121,"path":117,"stem":118},"Help and Support",{"title":123,"path":124,"stem":125},"Link Not Working","/help/link-not-working","5.help/1.link-not-working",{"title":127,"path":128,"stem":129},"Error Messages","/help/error-messages","5.help/2.error-messages","i-lucide-life-buoy",{"title":132,"path":133,"stem":134,"children":135},"API Reference","/api","6.api/0.index",[136,137,141,167,189,193,211,215],{"title":132,"path":133,"stem":134},{"title":138,"path":139,"stem":140},"Authentication","/api/authentication","6.api/1.authentication",{"title":142,"path":143,"stem":144,"children":145},"Shares","/api/shares","6.api/2.shares/0.index",[146,147,151,155,159,163],{"title":142,"path":143,"stem":144},{"title":148,"path":149,"stem":150},"Create a share","/api/shares/create","6.api/2.shares/1.create",{"title":152,"path":153,"stem":154},"List shares","/api/shares/list","6.api/2.shares/2.list",{"title":156,"path":157,"stem":158},"Retrieve a share","/api/shares/retrieve","6.api/2.shares/3.retrieve",{"title":160,"path":161,"stem":162},"Expire a share","/api/shares/delete","6.api/2.shares/4.delete",{"title":164,"path":165,"stem":166},"Client-side encryption","/api/shares/client-side-encryption","6.api/2.shares/5.client-side-encryption",{"title":168,"path":169,"stem":170,"children":171},"Secure requests","/api/requests","6.api/3.requests/0.index",[172,173,177,181,185],{"title":168,"path":169,"stem":170},{"title":174,"path":175,"stem":176},"Create a request","/api/requests/create","6.api/3.requests/1.create",{"title":178,"path":179,"stem":180},"List and retrieve requests","/api/requests/list","6.api/3.requests/2.list",{"title":182,"path":183,"stem":184},"Read submissions","/api/requests/submissions","6.api/3.requests/3.submissions",{"title":186,"path":187,"stem":188},"Expire or delete a request","/api/requests/delete","6.api/3.requests/4.delete",{"title":190,"path":191,"stem":192},"Stats","/api/stats","6.api/4.stats",{"title":194,"path":195,"stem":196,"children":197},"Webhooks","/api/webhooks","6.api/5.webhooks/0.index",[198,199,203,207],{"title":194,"path":195,"stem":196},{"title":200,"path":201,"stem":202},"Event reference","/api/webhooks/events","6.api/5.webhooks/1.events",{"title":204,"path":205,"stem":206},"Verifying signatures","/api/webhooks/verifying-signatures","6.api/5.webhooks/2.verifying-signatures",{"title":208,"path":209,"stem":210},"Delivery and retries","/api/webhooks/delivery-and-retries","6.api/5.webhooks/3.delivery-and-retries",{"title":212,"path":213,"stem":214},"MCP server","/api/mcp","6.api/6.mcp",{"title":216,"path":217,"stem":218},"Errors and Rate Limits","/api/errors-and-limits","6.api/7.errors-and-limits",{"title":220,"path":221,"stem":222,"children":223},"SDKs","/sdks","7.sdks/0.index",[224,225,229,233,237,241],{"title":220,"path":221,"stem":222},{"title":226,"path":227,"stem":228},"Node SDK","/sdks/node","7.sdks/1.node",{"title":230,"path":231,"stem":232},"Python SDK","/sdks/python","7.sdks/2.python",{"title":234,"path":235,"stem":236},"Go SDK","/sdks/go","7.sdks/3.go",{"title":238,"path":239,"stem":240},"Rust SDK","/sdks/rust","7.sdks/4.rust",{"title":242,"path":243,"stem":244},"Conformance vectors","/sdks/conformance-vectors","7.sdks/5.conformance-vectors",{"title":246,"path":247,"stem":248,"children":249,"page":21},"Security","/security","8.security",[250,254],{"title":251,"path":252,"stem":253},"Encryption","/security/encryption","8.security/1.encryption",{"title":255,"path":256,"stem":257},"Compliance","/security/compliance","8.security/2.compliance",{"id":259,"title":226,"api":260,"body":261,"description":1658,"extension":1659,"links":260,"meta":1660,"navigation":441,"path":227,"seo":1661,"stem":228,"__hash__":1662},"docs/7.sdks/1.node.md",null,{"type":262,"value":263,"toc":1647},"minimark",[264,274,286,291,316,330,344,347,399,410,414,597,608,642,648,652,659,681,718,728,732,828,835,852,859,863,959,989,1003,1019,1029,1033,1201,1214,1220,1247,1268,1278,1282,1349,1363,1367,1370,1577,1581,1599,1610,1617,1634,1643],[265,266,267],"p",{},[268,269,273],"a",{"href":270,"rel":271},"https://github.com/CredenShare/credenshare-sdk-node",[272],"nofollow","github.com/CredenShare/credenshare-sdk-node",[265,275,276,277,281,282,285],{},"Runs on Node 20+, and also on Deno, Bun, Cloudflare Workers and browsers — everything goes through ",[278,279,280],"code",{},"globalThis.crypto.subtle"," rather than ",[278,283,284],{},"node:crypto",", which is what keeps it working on the runtimes it is most useful in. There are no runtime dependencies.",[287,288,290],"h2",{"id":289},"installing","Installing",[292,293,298],"pre",{"className":294,"code":295,"language":296,"meta":297,"style":297},"language-bash shiki shiki-themes github-light github-dark github-dark","npm install @credenshare/sdk\n","bash","",[278,299,300],{"__ignoreMap":297},[301,302,305,309,313],"span",{"class":303,"line":304},"line",1,[301,306,308],{"class":307},"shcOC","npm",[301,310,312],{"class":311},"sfrk1"," install",[301,314,315],{"class":311}," @credenshare/sdk\n",[265,317,318,319,322,323,326,327,329],{},"Installing straight from the repository also works, if you want a specific commit or an unreleased fix — ",[278,320,321],{},"dist/"," is not committed, but the package's ",[278,324,325],{},"prepare"," hook runs the build and npm runs ",[278,328,325],{}," for a git install:",[292,331,333],{"className":294,"code":332,"language":296,"meta":297,"style":297},"npm install github:CredenShare/credenshare-sdk-node#v0.1.3\n",[278,334,335],{"__ignoreMap":297},[301,336,337,339,341],{"class":303,"line":304},[301,338,308],{"class":307},[301,340,312],{"class":311},[301,342,343],{"class":311}," github:CredenShare/credenshare-sdk-node#v0.1.3\n",[265,345,346],{},"If you would rather work against a clone — to read the source, or to try a change — build it and link it instead:",[292,348,350],{"className":294,"code":349,"language":296,"meta":297,"style":297},"git clone https://github.com/CredenShare/credenshare-sdk-node\ncd credenshare-sdk-node\nnpm install && npm run build && npm link\n",[278,351,352,363,373],{"__ignoreMap":297},[301,353,354,357,360],{"class":303,"line":304},[301,355,356],{"class":307},"git",[301,358,359],{"class":311}," clone",[301,361,362],{"class":311}," https://github.com/CredenShare/credenshare-sdk-node\n",[301,364,366,370],{"class":303,"line":365},2,[301,367,369],{"class":368},"suiK_","cd",[301,371,372],{"class":311}," credenshare-sdk-node\n",[301,374,376,378,380,384,386,389,392,394,396],{"class":303,"line":375},3,[301,377,308],{"class":307},[301,379,312],{"class":311},[301,381,383],{"class":382},"slsVL"," && ",[301,385,308],{"class":307},[301,387,388],{"class":311}," run",[301,390,391],{"class":311}," build",[301,393,383],{"class":382},[301,395,308],{"class":307},[301,397,398],{"class":311}," link\n",[265,400,401,402,405,406,409],{},"then ",[278,403,404],{},"npm link @credenshare/sdk"," from your project. A built clone on its own is not reachable from your project; ",[278,407,408],{},"npm link"," is what makes the import resolve.",[287,411,413],{"id":412},"quickstart","Quickstart",[292,415,420],{"className":416,"code":417,"filename":418,"language":419,"meta":297,"style":297},"language-ts shiki shiki-themes github-light github-dark github-dark","import { CredenShare } from '@credenshare/sdk'\n\nconst crs = new CredenShare(process.env.CREDENSHARE_KEY!)\n\nconst share = await crs.shares.create({\n  title: 'Staging deploy credentials',\n  fields: [\n    { key: 'Username', value: 'deploy-bot', type: 'text' },\n    { key: 'Password', value: 'correct horse', type: 'password' },\n  ],\n})\n\nconsole.log(share.link)\n// https://crs.sh/aB3dEf12#1xK9...\n","share.ts","ts",[278,421,422,437,443,472,477,499,511,517,541,561,567,573,578,590],{"__ignoreMap":297},[301,423,424,428,431,434],{"class":303,"line":304},[301,425,427],{"class":426},"so5gQ","import",[301,429,430],{"class":382}," { CredenShare } ",[301,432,433],{"class":426},"from",[301,435,436],{"class":311}," '@credenshare/sdk'\n",[301,438,439],{"class":303,"line":365},[301,440,442],{"emptyLinePlaceholder":441},true,"\n",[301,444,445,448,451,454,457,460,463,466,469],{"class":303,"line":375},[301,446,447],{"class":426},"const",[301,449,450],{"class":368}," crs",[301,452,453],{"class":426}," =",[301,455,456],{"class":426}," new",[301,458,459],{"class":307}," CredenShare",[301,461,462],{"class":382},"(process.env.",[301,464,465],{"class":368},"CREDENSHARE_KEY",[301,467,468],{"class":426},"!",[301,470,471],{"class":382},")\n",[301,473,475],{"class":303,"line":474},4,[301,476,442],{"emptyLinePlaceholder":441},[301,478,480,482,485,487,490,493,496],{"class":303,"line":479},5,[301,481,447],{"class":426},[301,483,484],{"class":368}," share",[301,486,453],{"class":426},[301,488,489],{"class":426}," await",[301,491,492],{"class":382}," crs.shares.",[301,494,495],{"class":307},"create",[301,497,498],{"class":382},"({\n",[301,500,502,505,508],{"class":303,"line":501},6,[301,503,504],{"class":382},"  title: ",[301,506,507],{"class":311},"'Staging deploy credentials'",[301,509,510],{"class":382},",\n",[301,512,514],{"class":303,"line":513},7,[301,515,516],{"class":382},"  fields: [\n",[301,518,520,523,526,529,532,535,538],{"class":303,"line":519},8,[301,521,522],{"class":382},"    { key: ",[301,524,525],{"class":311},"'Username'",[301,527,528],{"class":382},", value: ",[301,530,531],{"class":311},"'deploy-bot'",[301,533,534],{"class":382},", type: ",[301,536,537],{"class":311},"'text'",[301,539,540],{"class":382}," },\n",[301,542,544,546,549,551,554,556,559],{"class":303,"line":543},9,[301,545,522],{"class":382},[301,547,548],{"class":311},"'Password'",[301,550,528],{"class":382},[301,552,553],{"class":311},"'correct horse'",[301,555,534],{"class":382},[301,557,558],{"class":311},"'password'",[301,560,540],{"class":382},[301,562,564],{"class":303,"line":563},10,[301,565,566],{"class":382},"  ],\n",[301,568,570],{"class":303,"line":569},11,[301,571,572],{"class":382},"})\n",[301,574,576],{"class":303,"line":575},12,[301,577,442],{"emptyLinePlaceholder":441},[301,579,581,584,587],{"class":303,"line":580},13,[301,582,583],{"class":382},"console.",[301,585,586],{"class":307},"log",[301,588,589],{"class":382},"(share.link)\n",[301,591,593],{"class":303,"line":592},14,[301,594,596],{"class":595},"sCsY4","// https://crs.sh/aB3dEf12#1xK9...\n",[265,598,599,602,603,607],{},[278,600,601],{},"CredenShare"," is a ",[604,605,606],"strong",{},"named"," export, and the constructor takes the credential string positionally.",[609,610,613],"callout",{"color":611,"icon":612},"info","i-lucide-info",[265,614,615,618,619,622,623,626,627,629,630,633,634,637,638,641],{},[604,616,617],{},"The package is ESM only"," — there is no CommonJS build and no ",[278,620,621],{},"require"," condition in ",[278,624,625],{},"exports",". On Node 20.19+ and 22.12+ that is not a barrier: those releases load an ESM graph through ",[278,628,621],{},", so ",[278,631,632],{},"require('@credenshare/sdk')"," returns the module namespace and works. On older 20.x it throws ",[278,635,636],{},"ERR_REQUIRE_ESM",", and a dynamic ",[278,639,640],{},"await import()"," is the way in.",[265,643,644,647],{},[604,645,646],{},"That link is the secret."," The key rides in the fragment, which browsers never transmit. Anyone holding the link can read the content; we cannot, and cannot recover it for you.",[287,649,651],{"id":650},"the-field-object","The field object",[265,653,654,655,658],{},"Each field is ",[278,656,657],{},"{ key, value, type }",".",[265,660,661,664,665,668,669,672,673,676,677,680],{},[278,662,663],{},"key"," is the ",[604,666,667],{},"visible label",", not an identifier — it is what the recipient reads. It is not ",[278,670,671],{},"label",", ",[278,674,675],{},"name"," or ",[278,678,679],{},"title","; those spellings encrypt, post, decrypt and render perfectly, with every field blank and nothing erroring anywhere. The SDK refuses them rather than letting the mistake through.",[265,682,683,686,687,672,690,672,693,672,696,672,699,672,702,705,706,709,710,712,713,717],{},[278,684,685],{},"type"," is one of ",[278,688,689],{},"text",[278,691,692],{},"password",[278,694,695],{},"date",[278,697,698],{},"multiline",[278,700,701],{},"markdown",[278,703,704],{},"source_code",", exported as ",[278,707,708],{},"FIELD_TYPES",". Note that validation checks only that ",[278,711,685],{}," is ",[714,715,716],"em",{},"present",", not that it is a member of that tuple — a typo encrypts and misrenders silently, so check against the constant if the value is dynamic.",[265,719,720,723,724,727],{},[278,721,722],{},"selectedProgrammingLanguage"," and ",[278,725,726],{},"filename"," are optional, and this client preserves them along with any other member you add.",[287,729,731],{"id":730},"creating","Creating",[292,733,735],{"className":416,"code":734,"language":419,"meta":297,"style":297},"await crs.shares.create({\n  title: 'Production database',\n  fields: [{ key: 'Password', value: 's3cr3t', type: 'password' }],\n  passcode: 'hunter2',\n  expiredAt: '2026-09-01T00:00:00Z',\n  accessCountsLeft: 3,   // readable three times, max 10000\n  timedView: 60,         // visible for 60s once opened\n})\n",[278,736,737,748,757,776,786,796,810,824],{"__ignoreMap":297},[301,738,739,742,744,746],{"class":303,"line":304},[301,740,741],{"class":426},"await",[301,743,492],{"class":382},[301,745,495],{"class":307},[301,747,498],{"class":382},[301,749,750,752,755],{"class":303,"line":365},[301,751,504],{"class":382},[301,753,754],{"class":311},"'Production database'",[301,756,510],{"class":382},[301,758,759,762,764,766,769,771,773],{"class":303,"line":375},[301,760,761],{"class":382},"  fields: [{ key: ",[301,763,548],{"class":311},[301,765,528],{"class":382},[301,767,768],{"class":311},"'s3cr3t'",[301,770,534],{"class":382},[301,772,558],{"class":311},[301,774,775],{"class":382}," }],\n",[301,777,778,781,784],{"class":303,"line":474},[301,779,780],{"class":382},"  passcode: ",[301,782,783],{"class":311},"'hunter2'",[301,785,510],{"class":382},[301,787,788,791,794],{"class":303,"line":479},[301,789,790],{"class":382},"  expiredAt: ",[301,792,793],{"class":311},"'2026-09-01T00:00:00Z'",[301,795,510],{"class":382},[301,797,798,801,804,807],{"class":303,"line":501},[301,799,800],{"class":382},"  accessCountsLeft: ",[301,802,803],{"class":368},"3",[301,805,806],{"class":382},",   ",[301,808,809],{"class":595},"// readable three times, max 10000\n",[301,811,812,815,818,821],{"class":303,"line":513},[301,813,814],{"class":382},"  timedView: ",[301,816,817],{"class":368},"60",[301,819,820],{"class":382},",         ",[301,822,823],{"class":595},"// visible for 60s once opened\n",[301,825,826],{"class":303,"line":519},[301,827,572],{"class":382},[265,829,830,831,834],{},"A passcode is mixed into the ",[604,832,833],{},"content key derivation",", not just checked by the server — so it is not a server-side gate you could bypass, and a passcode-protected share cannot be opened from the link alone. The server receives only a one-way verifier. Send the link and the passcode over different channels.",[265,836,837,838,841,842,845,846,676,849,658],{},"Pass ",[278,839,840],{},"custody: true"," to also wrap the content key to the custody public key derived from your credential's third part, which keeps the share readable from your dashboard rather than only from its link. The wrap is computed locally and the custody secret never leaves your machine; the response's ",[278,843,844],{},"custody"," field reports ",[278,847,848],{},"stored",[278,850,851],{},"failed",[265,853,854,855,858],{},"Requires the ",[278,856,857],{},"shares:write"," scope.",[287,860,862],{"id":861},"listing-and-expiring","Listing and expiring",[292,864,866],{"className":416,"code":865,"language":419,"meta":297,"style":297},"const page = await crs.shares.list({ limit: 50 })\n\nfor await (const row of crs.shares.iterateAll()) {\n  console.log(row.shortCode, row.expiredAt)\n}\n\nawait crs.shares.expire('aB3dEf12')\n",[278,867,868,893,897,923,933,938,942],{"__ignoreMap":297},[301,869,870,872,875,877,879,881,884,887,890],{"class":303,"line":304},[301,871,447],{"class":426},[301,873,874],{"class":368}," page",[301,876,453],{"class":426},[301,878,489],{"class":426},[301,880,492],{"class":382},[301,882,883],{"class":307},"list",[301,885,886],{"class":382},"({ limit: ",[301,888,889],{"class":368},"50",[301,891,892],{"class":382}," })\n",[301,894,895],{"class":303,"line":365},[301,896,442],{"emptyLinePlaceholder":441},[301,898,899,902,904,907,909,912,915,917,920],{"class":303,"line":375},[301,900,901],{"class":426},"for",[301,903,489],{"class":426},[301,905,906],{"class":382}," (",[301,908,447],{"class":426},[301,910,911],{"class":368}," row",[301,913,914],{"class":426}," of",[301,916,492],{"class":382},[301,918,919],{"class":307},"iterateAll",[301,921,922],{"class":382},"()) {\n",[301,924,925,928,930],{"class":303,"line":474},[301,926,927],{"class":382},"  console.",[301,929,586],{"class":307},[301,931,932],{"class":382},"(row.shortCode, row.expiredAt)\n",[301,934,935],{"class":303,"line":479},[301,936,937],{"class":382},"}\n",[301,939,940],{"class":303,"line":501},[301,941,442],{"emptyLinePlaceholder":441},[301,943,944,946,948,951,954,957],{"class":303,"line":513},[301,945,741],{"class":426},[301,947,492],{"class":382},[301,949,950],{"class":307},"expire",[301,952,953],{"class":382},"(",[301,955,956],{"class":311},"'aB3dEf12'",[301,958,471],{"class":382},[265,960,961,723,963,966,967,970,971,723,973,966,975,977,978,980,981,984,985,988],{},[278,962,883],{},[278,964,965],{},"get"," need ",[278,968,969],{},"shares:read","; ",[278,972,495],{},[278,974,950],{},[278,976,857],{},". There is no hierarchy between them, so a key minted with only ",[278,979,857],{}," fails on ",[278,982,983],{},"list()"," with a ",[278,986,987],{},"PermissionError"," — the most common first surprise.",[265,990,991,992,995,996,999,1000,1002],{},"Both return ",[604,993,994],{},"metadata only",", never content and never a key. ",[278,997,998],{},"ShareSummary"," deliberately has no ",[278,1001,679],{},". A short code belonging to another account reports exactly as one that does not exist.",[265,1004,1005,1007,1008,1011,1012,1014,1015,1018],{},[278,1006,950],{}," ",[604,1009,1010],{},"removes"," the share rather than flagging it, so a later ",[278,1013,965],{}," throws ",[278,1016,1017],{},"NotFoundError",". A share you expired and one that never existed are indistinguishable afterwards.",[265,1020,1021,1024,1025,658],{},[278,1022,1023],{},"readLink()"," exists on the class and always throws. It is there to be discoverable, not usable — see ",[268,1026,1028],{"href":1027},"/sdks#what-none-of-them-do","what none of them do",[287,1030,1032],{"id":1031},"verifying-webhooks","Verifying webhooks",[292,1034,1036],{"className":416,"code":1035,"language":419,"meta":297,"style":297},"import express from 'express'\nimport { webhooks } from '@credenshare/sdk'\n\napp.post('/hooks/credenshare', express.raw({ type: 'application/json' }), async (req, res) => {\n  try {\n    await webhooks.verify(req.body, req.get('X-CredenShare-Signature')!, process.env.WEBHOOK_SECRET!)\n  } catch {\n    return res.sendStatus(400)\n  }\n  // ...\n})\n",[278,1037,1038,1050,1061,1065,1116,1123,1159,1169,1187,1192,1197],{"__ignoreMap":297},[301,1039,1040,1042,1045,1047],{"class":303,"line":304},[301,1041,427],{"class":426},[301,1043,1044],{"class":382}," express ",[301,1046,433],{"class":426},[301,1048,1049],{"class":311}," 'express'\n",[301,1051,1052,1054,1057,1059],{"class":303,"line":365},[301,1053,427],{"class":426},[301,1055,1056],{"class":382}," { webhooks } ",[301,1058,433],{"class":426},[301,1060,436],{"class":311},[301,1062,1063],{"class":303,"line":375},[301,1064,442],{"emptyLinePlaceholder":441},[301,1066,1067,1070,1073,1075,1078,1081,1084,1087,1090,1093,1096,1098,1102,1104,1107,1110,1113],{"class":303,"line":474},[301,1068,1069],{"class":382},"app.",[301,1071,1072],{"class":307},"post",[301,1074,953],{"class":382},[301,1076,1077],{"class":311},"'/hooks/credenshare'",[301,1079,1080],{"class":382},", express.",[301,1082,1083],{"class":307},"raw",[301,1085,1086],{"class":382},"({ type: ",[301,1088,1089],{"class":311},"'application/json'",[301,1091,1092],{"class":382}," }), ",[301,1094,1095],{"class":426},"async",[301,1097,906],{"class":382},[301,1099,1101],{"class":1100},"sQHwn","req",[301,1103,672],{"class":382},[301,1105,1106],{"class":1100},"res",[301,1108,1109],{"class":382},") ",[301,1111,1112],{"class":426},"=>",[301,1114,1115],{"class":382}," {\n",[301,1117,1118,1121],{"class":303,"line":479},[301,1119,1120],{"class":426},"  try",[301,1122,1115],{"class":382},[301,1124,1125,1128,1131,1134,1137,1139,1141,1144,1147,1149,1152,1155,1157],{"class":303,"line":501},[301,1126,1127],{"class":426},"    await",[301,1129,1130],{"class":382}," webhooks.",[301,1132,1133],{"class":307},"verify",[301,1135,1136],{"class":382},"(req.body, req.",[301,1138,965],{"class":307},[301,1140,953],{"class":382},[301,1142,1143],{"class":311},"'X-CredenShare-Signature'",[301,1145,1146],{"class":382},")",[301,1148,468],{"class":426},[301,1150,1151],{"class":382},", process.env.",[301,1153,1154],{"class":368},"WEBHOOK_SECRET",[301,1156,468],{"class":426},[301,1158,471],{"class":382},[301,1160,1161,1164,1167],{"class":303,"line":513},[301,1162,1163],{"class":382},"  } ",[301,1165,1166],{"class":426},"catch",[301,1168,1115],{"class":382},[301,1170,1171,1174,1177,1180,1182,1185],{"class":303,"line":519},[301,1172,1173],{"class":426},"    return",[301,1175,1176],{"class":382}," res.",[301,1178,1179],{"class":307},"sendStatus",[301,1181,953],{"class":382},[301,1183,1184],{"class":368},"400",[301,1186,471],{"class":382},[301,1188,1189],{"class":303,"line":543},[301,1190,1191],{"class":382},"  }\n",[301,1193,1194],{"class":303,"line":563},[301,1195,1196],{"class":595},"  // ...\n",[301,1198,1199],{"class":303,"line":569},[301,1200,572],{"class":382},[265,1202,1203,1007,1206,1209,1210,1213],{},[604,1204,1205],{},"Verify the raw body.",[278,1207,1208],{},"express.raw()",", never ",[278,1211,1212],{},"express.json()",". Re-serialising parsed JSON changes the bytes — key order, spacing, escapes — and the signature will not match. It is the most common reason a correct integration looks broken.",[265,1215,1216,1219],{},[604,1217,1218],{},"Pass both secrets while rotating."," For 24 hours after a rotation, deliveries carry both signatures:",[292,1221,1223],{"className":416,"code":1222,"language":419,"meta":297,"style":297},"await webhooks.verify(body, header, [NEW_SECRET, OLD_SECRET])\n",[278,1224,1225],{"__ignoreMap":297},[301,1226,1227,1229,1231,1233,1236,1239,1241,1244],{"class":303,"line":304},[301,1228,741],{"class":426},[301,1230,1130],{"class":382},[301,1232,1133],{"class":307},[301,1234,1235],{"class":382},"(body, header, [",[301,1237,1238],{"class":368},"NEW_SECRET",[301,1240,672],{"class":382},[301,1242,1243],{"class":368},"OLD_SECRET",[301,1245,1246],{"class":382},"])\n",[265,1248,1249,1251,1252,1255,1256,1259,1260,1263,1264,1267],{},[278,1250,1133],{}," resolves to ",[278,1253,1254],{},"true"," or rejects; it never resolves to ",[278,1257,1258],{},"false",", because a falsy return is too easy to drop with an ",[278,1261,1262],{},"if"," and no ",[278,1265,1266],{},"else",", which yields a receiver that accepts everything while looking like it checks.",[265,1269,1270,1271,1274,1275,658],{},"The header name is exported as ",[278,1272,1273],{},"webhooks.SIGNATURE_HEADER",", and the ±5-minute replay window as ",[278,1276,1277],{},"webhooks.DEFAULT_TOLERANCE_SECONDS",[287,1279,1281],{"id":1280},"configuration","Configuration",[292,1283,1285],{"className":416,"code":1284,"language":419,"meta":297,"style":297},"new CredenShare(credential, {\n  baseUrl: 'https://api.credenshare.io/v1',\n  linkOrigin: 'https://crs.sh',\n  timeoutMs: 30_000,\n  maxRetries: 2,\n  fetch: myFetch,          // injectable, for tests\n})\n",[278,1286,1287,1297,1307,1317,1327,1337,1345],{"__ignoreMap":297},[301,1288,1289,1292,1294],{"class":303,"line":304},[301,1290,1291],{"class":426},"new",[301,1293,459],{"class":307},[301,1295,1296],{"class":382},"(credential, {\n",[301,1298,1299,1302,1305],{"class":303,"line":365},[301,1300,1301],{"class":382},"  baseUrl: ",[301,1303,1304],{"class":311},"'https://api.credenshare.io/v1'",[301,1306,510],{"class":382},[301,1308,1309,1312,1315],{"class":303,"line":375},[301,1310,1311],{"class":382},"  linkOrigin: ",[301,1313,1314],{"class":311},"'https://crs.sh'",[301,1316,510],{"class":382},[301,1318,1319,1322,1325],{"class":303,"line":474},[301,1320,1321],{"class":382},"  timeoutMs: ",[301,1323,1324],{"class":368},"30_000",[301,1326,510],{"class":382},[301,1328,1329,1332,1335],{"class":303,"line":479},[301,1330,1331],{"class":382},"  maxRetries: ",[301,1333,1334],{"class":368},"2",[301,1336,510],{"class":382},[301,1338,1339,1342],{"class":303,"line":501},[301,1340,1341],{"class":382},"  fetch: myFetch,          ",[301,1343,1344],{"class":595},"// injectable, for tests\n",[301,1346,1347],{"class":303,"line":513},[301,1348,572],{"class":382},[265,1350,1351,1354,1355,1358,1359,1362],{},[278,1352,1353],{},"linkOrigin"," changes only the links ",[278,1356,1357],{},"create()"," hands back; it is never sent to the API. The SDK reads no environment variables — ",[278,1360,1361],{},"process.env"," in the examples above is your own read.",[287,1364,1366],{"id":1365},"rough-edges","Rough edges",[265,1368,1369],{},"Real behaviour worth knowing before it surprises you.",[1371,1372,1373,1412,1429,1435,1447,1474,1498,1509,1525,1562],"ul",{},[1374,1375,1376,1379,1380,1383,1384,1387,1388,1391,1392,1395,1396,1399,1400,1402,1403,1405,1406,1408,1409,1411],"li",{},[604,1377,1378],{},"The error hierarchy changed, if you wrote against the old one."," Field validation now throws ",[278,1381,1382],{},"InvalidFieldError"," where it threw a bare ",[278,1385,1386],{},"TypeError",", and ",[278,1389,1390],{},"WebhookVerificationError"," extends ",[278,1393,1394],{},"CredenShareError"," — so a blanket ",[278,1397,1398],{},"catch (e) { if (e instanceof CredenShareError) … }"," now reaches both, including the ",[278,1401,663],{},"-versus-",[278,1404,671],{}," mistake the SDK exists to catch. A ",[278,1407,1166],{}," written for ",[278,1410,1386],{}," no longer matches.",[1374,1413,1414,1417,1418,1421,1422,1424,1425,1428],{},[604,1415,1416],{},"The idempotency key is generated per call and handed back"," as ",[278,1419,1420],{},"share.idempotencyKey",", so the documented recovery — repeat the identical request with the same key — is reachable. It still does not make a second ",[278,1423,1357],{}," a no-op: salt and IV are fresh per call, so the body differs and the API answers ",[278,1426,1427],{},"409",". And a CI job that crashes after POSTing still mints a second copy on re-run unless you persist that key and pass it back.",[1374,1430,1431,1434],{},[604,1432,1433],{},"Only transport failures are retried",", never an HTTP status. A 500 is surfaced because it may have committed.",[1374,1436,1437,1446],{},[604,1438,1439,1442,1443],{},[278,1440,1441],{},"ApiError"," carries the server's ",[278,1444,1445],{},"additional_data"," on a validation failure, so you can see which field was rejected rather than only that something was.",[1374,1448,1449,1455,1456,1459,1460,1463,1464,1467,1468,1471,1472,658],{},[604,1450,1451,1452,658],{},"Transport failures no longer arrive as ",[278,1453,1454],{},"ServiceUnavailableError"," That class is now only a real HTTP ",[278,1457,1458],{},"503",", which does mean nothing was created. Exhausted retries raise ",[278,1461,1462],{},"NetworkError"," when nothing reached the API at all, and ",[278,1465,1466],{},"DeliveryUnknownError"," when headers had already arrived and the outcome is genuinely unknown. Both carry ",[278,1469,1470],{},"attempts"," and both extend ",[278,1473,1394],{},[1374,1475,1476,1482,1483,1486,1487,1490,1491,1494,1495,1497],{},[604,1477,1478,1481],{},[278,1479,1480],{},"VERSION"," reports the wrong number."," The exported constant reads ",[278,1484,1485],{},"0.1.0"," in the published ",[278,1488,1489],{},"0.1.3"," package — it is hardcoded separately from ",[278,1492,1493],{},"package.json"," and was not bumped. Read the version from ",[278,1496,1493],{}," if you need it.",[1374,1499,1500,1505,1506,1508],{},[604,1501,1502,1504],{},[278,1503,919],{}," can fail rather than loop."," It walks until a page comes back short, and refuses a response that echoes a page number other than the one requested — a server doing that makes progress unobservable, so it raises ",[278,1507,1441],{}," instead of continuing. There is also a hard ceiling of 100,000 pages, which raises rather than returning a partial result silently. The constant is internal — only the Rust crate re-exports its equivalent.",[1374,1510,1511,1517,1518,1209,1521,1524],{},[604,1512,1513,1516],{},[278,1514,1515],{},"retryAfter"," reads both forms of the header"," — delta-seconds, and an HTTP-date converted to whole seconds from now. It is ",[278,1519,1520],{},"undefined",[278,1522,1523],{},"0",", when the header is absent or unreadable, so a caller waiting on it notices rather than retrying immediately. Nothing sleeps on a 429 for you.",[1374,1526,1527,1534,1535,672,1538,723,1541,1544,1545,629,1548,723,1551,1554,1555,723,1558,1561],{},[604,1528,1529,1530,1533],{},"Logging a ",[278,1531,1532],{},"Share"," no longer spills the link."," It is a class whose ",[278,1536,1537],{},"toString",[278,1539,1540],{},"toJSON",[278,1542,1543],{},"util.inspect"," hook all render ",[278,1546,1547],{},"Share(\u003CshortCode>, link redacted)",[278,1549,1550],{},"console.log(share)",[278,1552,1553],{},"JSON.stringify(share)"," are safe — matching Python, Go and Rust. ",[278,1556,1557],{},"share.link",[278,1559,1560],{},"share.contentKey"," are still readable by name, which is the only way you should reach them.",[1374,1563,1564,1007,1567,1569,1570,1573,1574,1576],{},[604,1565,1566],{},"A webhook secret with surrounding whitespace is refused by name.",[278,1568,1133],{}," rejects any secret that differs from its own ",[278,1571,1572],{},"trim()",", with a ",[278,1575,1390],{}," saying so, rather than letting the HMAC fail and blaming the signature. Python, Go and Rust still do the old thing, so this is the one client that tells you what is actually wrong.",[287,1578,1580],{"id":1579},"checking-your-build","Checking your build",[292,1582,1584],{"className":294,"code":1583,"language":296,"meta":297,"style":297},"node dist/conformance-cli.js\n# 24 passed. This installation conforms to the wire specification.\n",[278,1585,1586,1594],{"__ignoreMap":297},[301,1587,1588,1591],{"class":303,"line":304},[301,1589,1590],{"class":307},"node",[301,1592,1593],{"class":311}," dist/conformance-cli.js\n",[301,1595,1596],{"class":303,"line":365},[301,1597,1598],{"class":595},"# 24 passed. This installation conforms to the wire specification.\n",[265,1600,1601,1602,1605,1606,1609],{},"Once the package is published, the binary is reachable as ",[278,1603,1604],{},"npx --package @credenshare/sdk credenshare-conformance"," — the bin name and the package name differ, so a bare ",[278,1607,1608],{},"npx credenshare-conformance"," would look for a package that does not exist. It needs no test runner and exits non-zero on failure, so it works as a deployment gate.",[265,1611,1612,1613,1616],{},"The checks are also available programmatically, from the ",[278,1614,1615],{},"./conformance"," subpath, if you would rather assert them inside your own test suite than shell out:",[292,1618,1620],{"className":416,"code":1619,"language":419,"meta":297,"style":297},"import { run } from '@credenshare/sdk/conformance'\n",[278,1621,1622],{"__ignoreMap":297},[301,1623,1624,1626,1629,1631],{"class":303,"line":304},[301,1625,427],{"class":426},[301,1627,1628],{"class":382}," { run } ",[301,1630,433],{"class":426},[301,1632,1633],{"class":311}," '@credenshare/sdk/conformance'\n",[265,1635,1636,1637,1640,1641,658],{},"The fixture ships inside the artifact as ",[278,1638,1639],{},"conformance-vectors.json"," — the same bytes as the other three clients, under a different filename. See ",[268,1642,242],{"href":243},[1644,1645,1646],"style",{},"html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}",{"title":297,"searchDepth":304,"depth":365,"links":1648},[1649,1650,1651,1652,1653,1654,1655,1656,1657],{"id":289,"depth":365,"text":290},{"id":412,"depth":365,"text":413},{"id":650,"depth":365,"text":651},{"id":730,"depth":365,"text":731},{"id":861,"depth":365,"text":862},{"id":1031,"depth":365,"text":1032},{"id":1280,"depth":365,"text":1281},{"id":1365,"depth":365,"text":1366},{"id":1579,"depth":365,"text":1580},"The official TypeScript client — encrypts locally, assembles the link, verifies webhooks. ESM only, no runtime dependencies.","md",{},{"title":226,"description":1658},"WsJxmI-CatjyCwxnAF4rIz6gTKWFAhwry81CUY6hyxI",[1664,1666],{"title":220,"path":221,"stem":222,"description":1665,"children":-1},"Official CredenShare clients for Node, Python, Go and Rust — they perform the encryption, so you pass plaintext and get back a link.",{"title":230,"path":231,"stem":232,"description":1667,"children":-1},"The official Python client — encrypts locally, assembles the link, verifies webhooks. Python 3.9+, two dependencies.",1788908850687]