[{"data":1,"prerenderedAt":780},["ShallowReactive",2],{"doc-\u002Fen\u002Feditions-licensing":3,"docnav-en":205},{"id":4,"title":5,"body":6,"description":196,"extension":197,"meta":198,"nav":199,"navigation":200,"path":201,"seo":202,"stem":203,"__hash__":204},"docs\u002Fen\u002Feditions-licensing.md","Editions & licensing",{"type":7,"value":8,"toc":189},"minimark",[9,14,31,107,116,120,127,164,167,171,174],[10,11,13],"h2",{"id":12},"open-core","Open core",[15,16,17,18,22,23,26,27,30],"p",{},"kvellman is ",[19,20,21],"strong",{},"open core",". The platform is open source under ",[19,24,25],{},"Apache-2.0","; advanced features ship\nas ",[19,28,29],{},"commercial plugins"," (e.g. SSO, MFA) that activate only with a valid Enterprise license.",[32,33,34,49],"table",{},[35,36,37],"thead",{},[38,39,40,43,46],"tr",{},[41,42],"th",{},[41,44,45],{},"Community",[41,47,48],{},"Enterprise",[50,51,52,63,74,85,96],"tbody",{},[38,53,54,58,60],{},[55,56,57],"td",{},"License",[55,59,25],{},[55,61,62],{},"Commercial subscription",[38,64,65,68,71],{},[55,66,67],{},"Users",[55,69,70],{},"Single \u002F local accounts",[55,72,73],{},"Multi-user, RBAC",[38,75,76,79,82],{},[55,77,78],{},"Auth",[55,80,81],{},"Local",[55,83,84],{},"SSO (OIDC) + MFA (TOTP)",[38,86,87,90,93],{},[55,88,89],{},"Scale",[55,91,92],{},"Single node",[55,94,95],{},"High availability, edge nodes",[38,97,98,101,104],{},[55,99,100],{},"Operations",[55,102,103],{},"Core",[55,105,106],{},"Approval workflow + audit, air-gapped, release scraper",[15,108,109,110,115],{},"See ",[111,112,114],"a",{"href":113},"\u002Fpricing","pricing"," for the full comparison.",[10,117,119],{"id":118},"how-licensing-works","How licensing works",[15,121,122,123,126],{},"Enterprise features are gated by an ",[19,124,125],{},"offline, signature-based"," license — no activation server, so\nit works air-gapped:",[128,129,130,138,145,161],"ol",{},[131,132,133,134,137],"li",{},"A license is an ",[19,135,136],{},"Ed25519-signed token"," issued by the vendor.",[131,139,140,141,144],{},"The product ships only the ",[19,142,143],{},"public key"," and verifies the token locally.",[131,146,147,148,151,152,156,157,160],{},"The token lists the customer and the active ",[19,149,150],{},"entitlements"," (e.g. ",[153,154,155],"code",{},"sso",", ",[153,158,159],{},"mfa",") and an expiry.",[131,162,163],{},"An admin pastes the token in the UI; matching plugins activate immediately — no restart, no\ninternet required.",[15,165,166],{},"Because verification is local, even the full open-source code cannot forge a valid license without\nthe vendor's private key.",[10,168,170],{"id":169},"developer-packages","Developer packages",[15,172,173],{},"The shared, public building blocks are on npm under Apache-2.0:",[175,176,177,183],"ul",{},[131,178,179,182],{},[153,180,181],{},"@kvellman\u002Fwinget-contract"," — the winget REST\u002Ftypes contract shared by origin and nodes.",[131,184,185,188],{},[153,186,187],{},"@kvellman\u002Fplugin-sdk"," — types for building auth\u002Fentitlement plugins.",{"title":190,"searchDepth":191,"depth":191,"links":192},"",2,[193,194,195],{"id":12,"depth":191,"text":13},{"id":118,"depth":191,"text":119},{"id":169,"depth":191,"text":170},"Open-core model — Community (Apache-2.0) vs Enterprise, and how licensing works.","md",{},3,true,"\u002Fen\u002Feditions-licensing",{"title":5,"description":196},"en\u002Feditions-licensing","GG0PkuJPsApFCUuFyP9GP_yXQMJjDVLXffyEuQ3kbmI",[206,416,543,663],{"id":207,"title":208,"body":209,"description":410,"extension":197,"meta":411,"nav":245,"navigation":200,"path":412,"seo":413,"stem":414,"__hash__":415},"docs\u002Fen\u002Fgetting-started.md","Getting started",{"type":7,"value":210,"toc":403},[211,215,222,226,233,315,322,326,337,341,348,370,373,377,399],[10,212,214],{"id":213},"what-is-kvellman","What is kvellman?",[15,216,217,218,221],{},"kvellman is a self-hosted, ",[19,219,220],{},"winget-compatible"," package repository. You register it as an\nadditional winget source — the winget CLI queries it exactly like the official Microsoft source.\nNo client modifications, no custom installers.",[10,223,225],{"id":224},"_1-run-the-origin-docker","1. Run the origin (Docker)",[15,227,228,229,232],{},"The Community edition runs from a single ",[153,230,231],{},"docker compose"," stack (app + PostgreSQL). With a domain\npointing at your host and ports 80\u002F443 open:",[234,235,239],"pre",{"className":236,"code":237,"language":238,"meta":190,"style":190},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","git clone \u003Copen-core-repo> kvellman && cd kvellman\ncp .env.deploy.example .env.deploy   # set DOMAIN, NUXT_SESSION_PASSWORD, POSTGRES_PASSWORD\ndocker compose --env-file .env.deploy up -d\n","bash",[153,240,241,281,296],{"__ignoreMap":190},[242,243,246,250,254,258,261,265,268,271,274,278],"span",{"class":244,"line":245},"line",1,[242,247,249],{"class":248},"sBMFI","git",[242,251,253],{"class":252},"sfazB"," clone",[242,255,257],{"class":256},"sMK4o"," \u003C",[242,259,260],{"class":252},"open-core-rep",[242,262,264],{"class":263},"sTEyZ","o",[242,266,267],{"class":256},">",[242,269,270],{"class":252}," kvellman",[242,272,273],{"class":256}," &&",[242,275,277],{"class":276},"s2Zo4"," cd",[242,279,280],{"class":252}," kvellman\n",[242,282,283,286,289,292],{"class":244,"line":191},[242,284,285],{"class":248},"cp",[242,287,288],{"class":252}," .env.deploy.example",[242,290,291],{"class":252}," .env.deploy",[242,293,295],{"class":294},"sHwdD","   # set DOMAIN, NUXT_SESSION_PASSWORD, POSTGRES_PASSWORD\n",[242,297,298,301,304,307,309,312],{"class":244,"line":199},[242,299,300],{"class":248},"docker",[242,302,303],{"class":252}," compose",[242,305,306],{"class":252}," --env-file",[242,308,291],{"class":252},[242,310,311],{"class":252}," up",[242,313,314],{"class":252}," -d\n",[15,316,317,318,321],{},"Database migrations run automatically on start. Open ",[153,319,320],{},"https:\u002F\u002Fyour-domain"," to create the first\nadmin account.",[10,323,325],{"id":324},"_2-provide-a-package","2. Provide a package",[15,327,328,329,332,333,336],{},"In the web UI: create a ",[19,330,331],{},"site token"," (Admin → Site tokens), then ",[19,334,335],{},"upload a manifest"," or import\none from the upstream winget catalog. Optionally store the installer locally so it is served from\nyour origin.",[10,338,340],{"id":339},"_3-add-the-source-on-a-client","3. Add the source on a client",[15,342,343,344,347],{},"winget requires ",[19,345,346],{},"HTTPS"," for a REST source. On a Windows client (PowerShell):",[234,349,353],{"className":350,"code":351,"language":352,"meta":190,"style":190},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","winget source add --name kvellman --type Microsoft.Rest --arg \"https:\u002F\u002Fyour-domain\u002Fapi\u002F\u003Csite-token>\"\nwinget search --source kvellman \u003Cterm>\nwinget install --source kvellman \u003CPackage.Identifier>\n","powershell",[153,354,355,360,365],{"__ignoreMap":190},[242,356,357],{"class":244,"line":245},[242,358,359],{},"winget source add --name kvellman --type Microsoft.Rest --arg \"https:\u002F\u002Fyour-domain\u002Fapi\u002F\u003Csite-token>\"\n",[242,361,362],{"class":244,"line":191},[242,363,364],{},"winget search --source kvellman \u003Cterm>\n",[242,366,367],{"class":244,"line":199},[242,368,369],{},"winget install --source kvellman \u003CPackage.Identifier>\n",[15,371,372],{},"That's it — clients now install internal software through your own winget source.",[10,374,376],{"id":375},"next-steps","Next steps",[175,378,379,386,393],{},[131,380,381,385],{},[111,382,384],{"href":383},"\u002Fdocs\u002Fdeployment","Deployment"," — Docker, reverse proxies (Caddy\u002FTraefik), edge nodes, TLS.",[131,387,388,392],{},[111,389,391],{"href":390},"\u002Fdocs\u002Farchitecture","Architecture"," — how the winget API, site tokens and mirroring fit together.",[131,394,395,398],{},[111,396,5],{"href":397},"\u002Fdocs\u002Feditions-licensing"," — Community vs Enterprise.",[400,401,402],"style",{},"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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":190,"searchDepth":191,"depth":191,"links":404},[405,406,407,408,409],{"id":213,"depth":191,"text":214},{"id":224,"depth":191,"text":225},{"id":324,"depth":191,"text":325},{"id":339,"depth":191,"text":340},{"id":375,"depth":191,"text":376},"Run a kvellman origin and add it as a winget source in minutes.",{},"\u002Fen\u002Fgetting-started",{"title":208,"description":410},"en\u002Fgetting-started","kK4dTunMMifwqdzNjiI5Y6UPFNawYYWerxVCiGSe-fI",{"id":417,"title":384,"body":418,"description":537,"extension":197,"meta":538,"nav":191,"navigation":200,"path":539,"seo":540,"stem":541,"__hash__":542},"docs\u002Fen\u002Fdeployment.md",{"type":7,"value":419,"toc":531},[420,424,435,439,442,463,493,500,504,511,515,518,528],[10,421,423],{"id":422},"winget-requires-https","winget requires HTTPS",[15,425,426,427,430,431,434],{},"A winget REST source must be served over ",[19,428,429],{},"HTTPS with a trusted certificate"," (this also applies to\n",[153,432,433],{},"localhost"," on recent winget versions). Plan TLS for every endpoint clients talk to.",[10,436,438],{"id":437},"origin-via-docker","Origin via Docker",[15,440,441],{},"The Community stack is app + PostgreSQL. Two reverse-proxy options ship out of the box:",[175,443,444,454],{},[131,445,446,449,450,453],{},[19,447,448],{},"Caddy"," (",[153,451,452],{},"docker-compose.yml",") — automatic Let's Encrypt for a public domain.",[131,455,456,449,459,462],{},[19,457,458],{},"Existing Traefik",[153,460,461],{},"docker-compose.traefik.yml",") — no Caddy; the app joins Traefik's network\nand is routed by labels. Use this when port 80\u002F443 is already taken by Traefik.",[234,464,466],{"className":236,"code":465,"language":238,"meta":190,"style":190},"# behind an existing Traefik:\ndocker compose -f docker-compose.traefik.yml --env-file .env.deploy up -d\n",[153,467,468,473],{"__ignoreMap":190},[242,469,470],{"class":244,"line":245},[242,471,472],{"class":294},"# behind an existing Traefik:\n",[242,474,475,477,479,482,485,487,489,491],{"class":244,"line":191},[242,476,300],{"class":248},[242,478,303],{"class":252},[242,480,481],{"class":252}," -f",[242,483,484],{"class":252}," docker-compose.traefik.yml",[242,486,306],{"class":252},[242,488,291],{"class":252},[242,490,311],{"class":252},[242,492,314],{"class":252},[15,494,495,496,499],{},"Set ",[153,497,498],{},"KVELLMAN_IMAGE"," to a prebuilt image (built elsewhere and pushed to a registry) to avoid\nbuilding on a small server; migrations run automatically at container start.",[10,501,503],{"id":502},"edge-mirror-nodes-enterprise","Edge \u002F mirror nodes (Enterprise)",[15,505,506,507,510],{},"A site can run a headless ",[19,508,509],{},"edge node"," that serves the winget API and installer downloads locally,\ncaching from the origin on demand. Clients add the node as their source; the first install pulls\nthrough the node, the rest hit the LAN. Nodes enroll with the origin (one-time key → durable mTLS\nidentity) and are centrally controlled (package scope, installer filter, push\u002Fpre-stage, health).",[10,512,514],{"id":513},"telemetry-toggles","Telemetry & toggles",[15,516,517],{},"Repository-usage telemetry (searches, manifest fetches, downloads) is off by default and enabled via\nenvironment. The same pattern applies to the upstream-catalog sync and a GitHub token for imports.",[519,520,521],"blockquote",{},[15,522,523,524,527],{},"For the full, step-by-step guide (origin, edge node under WSL, TLS for LAN\u002Flocalhost, the registry\nworkflow) see ",[153,525,526],{},"DEPLOYMENT.md"," in the open-core repository.",[400,529,530],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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);}",{"title":190,"searchDepth":191,"depth":191,"links":532},[533,534,535,536],{"id":422,"depth":191,"text":423},{"id":437,"depth":191,"text":438},{"id":502,"depth":191,"text":503},{"id":513,"depth":191,"text":514},"Deploy the origin with Docker behind Caddy or an existing Traefik, plus edge nodes.",{},"\u002Fen\u002Fdeployment",{"title":384,"description":537},"en\u002Fdeployment","bkkfra33ona6FLJByyaPAXxM4d1aUfGtARgD9iJ6v08",{"id":4,"title":5,"body":544,"description":196,"extension":197,"meta":661,"nav":199,"navigation":200,"path":201,"seo":662,"stem":203,"__hash__":204},{"type":7,"value":545,"toc":656},[546,548,556,610,614,616,620,640,642,644,646],[10,547,13],{"id":12},[15,549,17,550,22,552,26,554,30],{},[19,551,21],{},[19,553,25],{},[19,555,29],{},[32,557,558,568],{},[35,559,560],{},[38,561,562,564,566],{},[41,563],{},[41,565,45],{},[41,567,48],{},[50,569,570,578,586,594,602],{},[38,571,572,574,576],{},[55,573,57],{},[55,575,25],{},[55,577,62],{},[38,579,580,582,584],{},[55,581,67],{},[55,583,70],{},[55,585,73],{},[38,587,588,590,592],{},[55,589,78],{},[55,591,81],{},[55,593,84],{},[38,595,596,598,600],{},[55,597,89],{},[55,599,92],{},[55,601,95],{},[38,603,604,606,608],{},[55,605,100],{},[55,607,103],{},[55,609,106],{},[15,611,109,612,115],{},[111,613,114],{"href":113},[10,615,119],{"id":118},[15,617,122,618,126],{},[19,619,125],{},[128,621,622,626,630,638],{},[131,623,133,624,137],{},[19,625,136],{},[131,627,140,628,144],{},[19,629,143],{},[131,631,147,632,151,634,156,636,160],{},[19,633,150],{},[153,635,155],{},[153,637,159],{},[131,639,163],{},[15,641,166],{},[10,643,170],{"id":169},[15,645,173],{},[175,647,648,652],{},[131,649,650,182],{},[153,651,181],{},[131,653,654,188],{},[153,655,187],{},{"title":190,"searchDepth":191,"depth":191,"links":657},[658,659,660],{"id":12,"depth":191,"text":13},{"id":118,"depth":191,"text":119},{"id":169,"depth":191,"text":170},{},{"title":5,"description":196},{"id":664,"title":391,"body":665,"description":773,"extension":197,"meta":774,"nav":775,"navigation":200,"path":776,"seo":777,"stem":778,"__hash__":779},"docs\u002Fen\u002Farchitecture.md",{"type":7,"value":666,"toc":766},[667,671,674,694,698,729,733,752,756,759,763],[10,668,670],{"id":669},"winget-source-api","winget Source API",[15,672,673],{},"kvellman implements the winget Source REST contract exactly, so the winget CLI treats it like any\nother source:",[175,675,676,682,688],{},[131,677,678,681],{},[153,679,680],{},"GET \u002Fapi\u002F{siteToken}\u002Finformation"," — source metadata and supported versions.",[131,683,684,687],{},[153,685,686],{},"POST \u002Fapi\u002F{siteToken}\u002FmanifestSearch"," — full-text search.",[131,689,690,693],{},[153,691,692],{},"GET \u002Fapi\u002F{siteToken}\u002FpackageManifests\u002F{id}"," — manifest delivery with server-side resolution.",[10,695,697],{"id":696},"site-context","Site context",[15,699,700,701,703,704,707,708,711,712,715,716,156,719,156,722,156,725,728],{},"winget sends no custom headers, so site context is carried in the URL ",[19,702,331],{}," (primary),\nwith ",[19,705,706],{},"subnet"," and ",[19,709,710],{},"mTLS client certificate"," as additional signals. The resolved context drives\nserver-side ",[153,713,714],{},"InstallerUrl"," placeholders (",[153,717,718],{},"$REPO_URL",[153,720,721],{},"$SITE",[153,723,724],{},"$LOCATION",[153,726,727],{},"$LANG",") — so the same\nmanifest can point at a site-local SMB\u002FDFS share without being forked.",[10,730,732],{"id":731},"manifests-overlays-storage","Manifests, overlays & storage",[15,734,735,736,739,740,743,744,747,748,751],{},"Manifests are versioned YAML, validated against the official winget JSON schemas on upload. Local\nedits are kept as an ",[19,737,738],{},"overlay"," on top of the untouched upstream, and per-package ",[19,741,742],{},"overlay\ntemplates"," make repeatable edits (e.g. an internal mirror URL with ",[153,745,746],{},"$VERSION","\u002F",[153,749,750],{},"$ARCH",") easy across\nversions. Installers can be mirrored to S3\u002FMinIO or SMB; hashes are recomputed on delivery.",[10,753,755],{"id":754},"edge-mirror-nodes","Edge \u002F mirror nodes",[15,757,758],{},"Edge nodes are thin caching proxies that serve the winget API + downloads locally and lazily fetch\nfrom the origin. They keep an offline search index, enroll via mTLS, and are centrally scoped\n(which packages, which installer architectures\u002Fscopes) and observable from the origin.",[10,760,762],{"id":761},"stack","Stack",[15,764,765],{},"Nuxt 4 (Vue 3 + Nitro), TypeScript, PostgreSQL + Drizzle ORM, S3-compatible storage, BullMQ\u002FRedis\nfor background jobs. On-premise only — fully self-hostable, including air-gapped operation.",{"title":190,"searchDepth":191,"depth":191,"links":767},[768,769,770,771,772],{"id":669,"depth":191,"text":670},{"id":696,"depth":191,"text":697},{"id":731,"depth":191,"text":732},{"id":754,"depth":191,"text":755},{"id":761,"depth":191,"text":762},"How the winget Source API, site context, mirroring and edge nodes fit together.",{},4,"\u002Fen\u002Farchitecture",{"title":391,"description":773},"en\u002Farchitecture","Eqw1cDRa0-CLXwr65192sIi5s3k47eNKWIDs5A9qIiE",1782195177909]