tunecamp 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.local CHANGED
@@ -1,2 +1,2 @@
1
1
  # Created by Vercel CLI
2
- VERCEL_OIDC_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im1yay00MzAyZWMxYjY3MGY0OGE5OGFkNjFkYWRlNGEyM2JlNyJ9.eyJpc3MiOiJodHRwczovL29pZGMudmVyY2VsLmNvbS9zY29icnUtcy10ZWFtIiwic3ViIjoib3duZXI6c2NvYnJ1LXMtdGVhbTpwcm9qZWN0OmhvbW9sb2dvbXVzaWM6ZW52aXJvbm1lbnQ6ZGV2ZWxvcG1lbnQiLCJzY29wZSI6Im93bmVyOnNjb2JydS1zLXRlYW06cHJvamVjdDpob21vbG9nb211c2ljOmVudmlyb25tZW50OmRldmVsb3BtZW50IiwiYXVkIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3Njb2JydS1zLXRlYW0iLCJvd25lciI6InNjb2JydS1zLXRlYW0iLCJvd25lcl9pZCI6InRlYW1fUU1vUlcwTGY5OXpiQUZPdnlzaHdycE9HIiwicHJvamVjdCI6ImhvbW9sb2dvbXVzaWMiLCJwcm9qZWN0X2lkIjoicHJqX0JiNXVkV0NPUUI1ZUd6dHlyaXZ2bUFPU2V1aXIiLCJlbnZpcm9ubWVudCI6ImRldmVsb3BtZW50IiwicGxhbiI6ImhvYmJ5IiwidXNlcl9pZCI6IkpITk02UkMyN2lEMHMxQ1JSa3o2dEJQRSIsIm5iZiI6MTc2ODM5NzczOSwiaWF0IjoxNzY4Mzk3NzM5LCJleHAiOjE3Njg0NDA5Mzl9.hoIwo5r8MYxCSfq-jL0rZgFr1zaHI0qaks2JMBpjVQ3HbrdSJMitQ8dAdO0N9DwZVxRLF7j_tPozrf8BNje03Cg6rmEJMRZyfqvAIwUO3HBBIsxSs5hvh5L4L_jIZgz5pAHk_tgF7N8I4G0N8LCmpnEaRHRmdeaACxExGUQlkU9YkGYFWNcCyfo4YBY6_-Ej_HLBvv2Sfo0gg_AMpSv8mBkK701tAhwyCtDIhTTK9ORTUwnRU5CmYTVIARgWaW30W_52FrfimmNOBZz-qVbKp3rkCg6r1w0CVwGg3TUqI1T-IOkh98SRvvIRCjzEO-g-frIytT7T19Ab-pUy8Yv35A"
2
+ VERCEL_OIDC_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im1yay00MzAyZWMxYjY3MGY0OGE5OGFkNjFkYWRlNGEyM2JlNyJ9.eyJpc3MiOiJodHRwczovL29pZGMudmVyY2VsLmNvbS9zY29icnUtcy10ZWFtIiwic3ViIjoib3duZXI6c2NvYnJ1LXMtdGVhbTpwcm9qZWN0OnR1bmVjYW1wOmVudmlyb25tZW50OmRldmVsb3BtZW50Iiwic2NvcGUiOiJvd25lcjpzY29icnUtcy10ZWFtOnByb2plY3Q6dHVuZWNhbXA6ZW52aXJvbm1lbnQ6ZGV2ZWxvcG1lbnQiLCJhdWQiOiJodHRwczovL3ZlcmNlbC5jb20vc2NvYnJ1LXMtdGVhbSIsIm93bmVyIjoic2NvYnJ1LXMtdGVhbSIsIm93bmVyX2lkIjoidGVhbV9RTW9SVzBMZjk5emJBRk92eXNod3JwT0ciLCJwcm9qZWN0IjoidHVuZWNhbXAiLCJwcm9qZWN0X2lkIjoicHJqX0hXRUk3MzhVd1VHb3c5TzRFZTVpSGhnaHo3d2kiLCJlbnZpcm9ubWVudCI6ImRldmVsb3BtZW50IiwicGxhbiI6ImhvYmJ5IiwidXNlcl9pZCI6IkpITk02UkMyN2lEMHMxQ1JSa3o2dEJQRSIsIm5iZiI6MTc2ODM5ODI4MSwiaWF0IjoxNzY4Mzk4MjgxLCJleHAiOjE3Njg0NDE0ODF9.jOTfVH4x952dNJBYkQ-OZ9DR6bBBMc6EVrfeWn2CTKdB0-F35KU47JP5ProKru7EVNOpQpvW-ynJf2dfayAxAtq6xmxw8XZ6_7xV2alHYzdibeOhgKYTneNKqgYttP0eJiXhIho989K-AhKMN7Mp41lBzuBydqvpkY-NFwDL9mhSMN3YDAoQSoZylnZvPhK8-Z_5nRKtnIs37y5X-ChrLCgOyzFBULcGuEaNLbgGvcWTyPZfNw4aRsOG_yYrMYdvyrjtqsyvc7F7LDilVxkJI-os_IPLGMlNQwC-GkqpLn8LcawUelPA5h_WLrAOT74PpPBfB1tRqrE9uls7tYJK7g"
@@ -1 +1 @@
1
- {"projectId":"prj_Bb5udWCOQB5eGztyrivvmAOSeuir","orgId":"team_QMoRW0Lf99zbAFOvyshwrpOG","projectName":"homologomusic"}
1
+ {"projectId":"prj_HWEI738UwUGow9O4Ee5iHhghz7wi","orgId":"team_QMoRW0Lf99zbAFOvyshwrpOG","projectName":"tunecamp"}
package/README.md CHANGED
@@ -282,7 +282,7 @@ unlockCodes:
282
282
  namespace: tunecamp # Optional, default: tunecamp
283
283
  ```
284
284
 
285
- Protect downloads with unlock codes validated via GunDB (decentralized, no backend required). See [Unlock Codes Guide](./docs/unlock-codes-guida.md) for details.
285
+ Protect downloads with unlock codes validated via GunDB (decentralized, no backend required). See [Unlock Codes Guide](./docs/UNLOCK_CODES.md) for details.
286
286
 
287
287
  **⚠️ Important - Self-Hosting Required**: The code generation tool (`generate-codes.ts`) must be run locally on your machine where you have access to the Tunecamp source code. If you deploy only the static HTML output (e.g., to Vercel, Netlify, GitHub Pages), you won't be able to generate new codes from the deployed site - it's just static HTML.
288
288
 
@@ -377,7 +377,7 @@ templates/my-theme/
377
377
  └── player.js
378
378
  ```
379
379
 
380
- For detailed information about themes, see [Theme Documentation](./docs/THEMES.md).
380
+ For detailed information about themes, see [Theme Showcase](./docs/THEME_SHOWCASE.md).
381
381
 
382
382
  ## Generated Files
383
383
 
@@ -549,6 +549,6 @@ body {
549
549
  - [Deployment Guide](./docs/DEPLOYMENT.md)
550
550
  - [API Documentation](./docs/API.md)
551
551
  - [Theme Showcase](./docs/THEME_SHOWCASE.md)
552
- - [Unlock Codes Guide](./docs/unlock-codes-guida.md)
552
+ - [Unlock Codes Guide](./docs/UNLOCK_CODES.md)
553
553
  - [Examples](./examples)
554
554
  - [Changelog](./CHANGELOG.md)
@@ -127,7 +127,7 @@ ${coverEnclosure}
127
127
  <link href="${feedUrl}" rel="self" type="application/atom+xml"/>
128
128
  <id>${link}</id>
129
129
  <updated>${now}</updated>
130
- <generator uri="https://github.com/scobru/tunecamp" version="0.1.0">Tunecamp</generator>
130
+ <generator uri="https://github.com/scobru/tunecamp" version="1.0.0">Tunecamp</generator>
131
131
  <author>
132
132
  <name>${this.escapeXml(artistName)}</name>
133
133
  </author>
@@ -256,8 +256,11 @@ Examples:
256
256
  console.log(` enabled: true`);
257
257
  console.log(` namespace: ${namespace}`);
258
258
  if (keypair) {
259
+ console.log(` publicKey: "${keypair.pub}" # <-- REQUIRED!`);
259
260
  console.log(`\n🔒 Codes stored in your private GunDB space`);
260
261
  console.log(` Only you can access and manage these codes`);
262
+ console.log(`\n⚠️ IMPORTANT: You MUST add the publicKey to release.yaml!`);
263
+ console.log(` Without it, the frontend won't find your codes.`);
261
264
  }
262
265
  else {
263
266
  console.log(`\n⚠️ Codes stored in public space`);
@@ -1 +1 @@
1
- {"version":3,"file":"generate-codes.js","sourceRoot":"","sources":["../../src/tools/generate-codes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generate-codes.js","sourceRoot":"","sources":["../../src/tools/generate-codes.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG;AAEH,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;AAGpB,6BAA6B;AAC7B,MAAM,aAAa,GAAG;IAClB,2BAA2B;IAC3B,6BAA6B;IAC7B,4BAA4B;IAC5B,wCAAwC;CAC3C,CAAC;AAmBF;;GAEG;AACH,SAAS,YAAY;IACjB,4DAA4D;IAC5D,MAAM,KAAK,GAAG,kCAAkC,CAAC,CAAC,gBAAgB;IAClE,MAAM,QAAQ,GAAG,CAAC,CAAC;IACnB,MAAM,aAAa,GAAG,CAAC,CAAC;IAExB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC1B,OAAO,MAAM;SACR,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;SACjC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,WAAmB;IACpC,IAAI,CAAC;QACD,MAAM,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAEvC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACnE,CAAC;QAED,OAAO;YACH,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK;SACtB,CAAC;IACN,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,+BAA+B,WAAW,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACpF,CAAC;AACL,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,iBAAiB,CAAC,GAAQ,EAAE,IAAgB;IACvD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAExB,sBAAsB;QACtB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAQ,EAAE,EAAE;YACzB,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,oDAAoD;gBACpD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAc,EAAE,EAAE;oBACjC,IAAI,SAAS,CAAC,GAAG,IAAI,SAAS,CAAC,GAAG,KAAK,uBAAuB,EAAE,CAAC;wBAC7D,MAAM,CAAC,IAAI,KAAK,CAAC,uCAAuC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;wBAC1E,OAAO;oBACX,CAAC;oBAED,gCAAgC;oBAChC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,OAAY,EAAE,EAAE;wBAC7B,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;4BACd,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;4BAC5D,OAAO;wBACX,CAAC;wBACD,OAAO,EAAE,CAAC;oBACd,CAAC,CAAC,CAAC;gBACP,CAAC,CAAC,CAAC;YACP,CAAC;iBAAM,CAAC;gBACJ,OAAO,EAAE,CAAC;YACd,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAAC,OAAoB;IAC7C,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAE/F,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,YAAY,WAAW,EAAE,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,2BAA2B,YAAY,EAAE,CAAC,CAAC;IACvD,IAAI,aAAa;QAAE,OAAO,CAAC,GAAG,CAAC,eAAe,aAAa,OAAO,CAAC,CAAC;IACpE,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACxD,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAE9C,iBAAiB;IACjB,MAAM,GAAG,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAE3B,sBAAsB;IACtB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAExD,sCAAsC;IACtC,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACjD,IAAI,CAAC;YACD,MAAM,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,4BAA4B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3D,MAAM,KAAK,CAAC;QAChB,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,aAAa;QAC3B,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,aAAa,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACpD,CAAC,CAAC,IAAI,CAAC;IAEX,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,WAAW,CAAC,CAAC;IAE9C,gEAAgE;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAE1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEhC,oEAAoE;QACpE,MAAM;aACD,GAAG,CAAC,SAAS,CAAC;aACd,GAAG,CAAC,UAAU,CAAC;aACf,GAAG,CAAC,WAAW,CAAC;aAChB,GAAG,CAAC,OAAO,CAAC;aACZ,GAAG,CAAC,QAAQ,CAAC;aACb,GAAG,CAAC;YACD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,CAAC;YACZ,YAAY;YACZ,SAAS;SACZ,CAAC,CAAC;QAEP,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,gBAAgB;IAChB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAExD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,IAAI;IACf,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;CAmBnB,CAAC,CAAC;QACK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IAClE,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IAC5E,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC5C,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/C,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,UAAU,CAAC;IACtE,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC1C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC,CAAC,IAAI,CAAC;IACX,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;QACxC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC,CAAC,IAAI,CAAC;IAEX,2BAA2B;IAC3B,IAAI,OAA+B,CAAC;IACpC,IAAI,WAAW,EAAE,CAAC;QACd,IAAI,CAAC;YACD,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7D,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACnD,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACL,CAAC;IAED,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC;YAC9B,WAAW;YACX,KAAK;YACL,YAAY;YACZ,aAAa;YACb,SAAS;YACT,KAAK,EAAE,aAAa;YACpB,OAAO;SACV,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,CAAC,MAAM,WAAW,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACjC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAEjC,4BAA4B;QAC5B,IAAI,UAAU,EAAE,CAAC;YACb,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,MAAM,OAAO,GAAG;gBACZ,uBAAuB,WAAW,EAAE;gBACpC,gBAAgB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;gBAC1C,6BAA6B,YAAY,EAAE;gBAC3C,aAAa,CAAC,CAAC,CAAC,iBAAiB,aAAa,OAAO,CAAC,CAAC,CAAC,EAAE;gBAC1D,EAAE;gBACF,GAAG,KAAK;aACX,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE7B,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,wBAAwB,UAAU,EAAE,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,kBAAkB,SAAS,EAAE,CAAC,CAAC;QAC3C,IAAI,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,mBAAmB,OAAO,CAAC,GAAG,oBAAoB,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;YAC5E,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QACtE,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tunecamp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A modern static site generator for musicians and music labels, inspired by Faircamp",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -7,6 +7,11 @@
7
7
  * 2. Include this script
8
8
  * 3. Initialize: const unlockCodes = new TunecampUnlockCodes();
9
9
  * 4. Validate: unlockCodes.validateCode(releaseSlug, userCode).then(valid => {...})
10
+ *
11
+ * For private space (with keypair):
12
+ * const unlockCodes = new TunecampUnlockCodes({
13
+ * publicKey: 'artist-public-key-here'
14
+ * });
10
15
  */
11
16
 
12
17
  (function() {
@@ -14,8 +19,10 @@
14
19
 
15
20
  // Default public GunDB peers
16
21
  const DEFAULT_PEERS = [
17
- 'https://gun-manhattan.herokuapp.com/gun',
18
- 'https://gun-us.herokuapp.com/gun',
22
+ 'https://gun.defucc.me/gun',
23
+ 'https://gun.o8.is/gun',
24
+ 'https://shogun-relay.scobrudot.dev/gun',
25
+ 'https://relay.peer.ooo/gun',
19
26
  ];
20
27
 
21
28
  /**
@@ -28,10 +35,12 @@
28
35
  * @param {Object} options - Configuration options
29
36
  * @param {Array} options.peers - GunDB peer URLs (default: public peers)
30
37
  * @param {string} options.namespace - GunDB namespace (default: 'tunecamp')
38
+ * @param {string} options.publicKey - Artist's public key (for reading from private space)
31
39
  */
32
40
  constructor(options = {}) {
33
41
  this.peers = options.peers || DEFAULT_PEERS;
34
42
  this.namespace = options.namespace || 'tunecamp';
43
+ this.publicKey = options.publicKey || null; // Artist's public key for private space
35
44
  this.gun = null;
36
45
  this.initialized = false;
37
46
 
@@ -56,7 +65,22 @@
56
65
  });
57
66
 
58
67
  this.initialized = true;
59
- console.log('🔐 Tunecamp Unlock Codes initialized');
68
+ const spaceType = this.publicKey ? 'private (artist space)' : 'public';
69
+ console.log(`🔐 Tunecamp Unlock Codes initialized (${spaceType})`);
70
+ }
71
+
72
+ /**
73
+ * Get the root node for code storage
74
+ * If publicKey is set, reads from artist's user space
75
+ * Otherwise reads from public space
76
+ */
77
+ getCodesRoot() {
78
+ if (this.publicKey) {
79
+ // Read from artist's private/user space using their public key
80
+ return this.gun.user(this.publicKey).get(this.namespace);
81
+ }
82
+ // Read from public space
83
+ return this.gun.get(this.namespace);
60
84
  }
61
85
 
62
86
  /**
@@ -106,8 +130,7 @@
106
130
  const codeHash = await this.hashCode(code);
107
131
 
108
132
  return new Promise((resolve) => {
109
- this.gun
110
- .get(this.namespace)
133
+ this.getCodesRoot()
111
134
  .get('releases')
112
135
  .get(releaseSlug)
113
136
  .get('codes')
@@ -151,8 +174,7 @@
151
174
  const codeHash = await this.hashCode(code);
152
175
 
153
176
  return new Promise((resolve) => {
154
- const codeRef = this.gun
155
- .get(this.namespace)
177
+ const codeRef = this.getCodesRoot()
156
178
  .get('releases')
157
179
  .get(releaseSlug)
158
180
  .get('codes')
@@ -174,7 +196,8 @@
174
196
  const maxDownloads = data.maxDownloads || 1;
175
197
  const used = downloads >= maxDownloads;
176
198
 
177
- // Update the code
199
+ // Update the code (note: this only works if codes are in public space
200
+ // or if artist has write access - for private space, updates won't persist)
178
201
  codeRef.put({
179
202
  ...data,
180
203
  downloads,
@@ -200,8 +223,7 @@
200
223
  return new Promise((resolve) => {
201
224
  const codes = [];
202
225
 
203
- this.gun
204
- .get(this.namespace)
226
+ this.getCodesRoot()
205
227
  .get('releases')
206
228
  .get(releaseSlug)
207
229
  .get('codes')
@@ -218,6 +240,14 @@
218
240
  }, 1000);
219
241
  });
220
242
  }
243
+
244
+ /**
245
+ * Check if using private space (artist's user space)
246
+ * @returns {boolean} True if using private space
247
+ */
248
+ isPrivateSpace() {
249
+ return !!this.publicKey;
250
+ }
221
251
  }
222
252
 
223
253
  // Expose globally
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Tunecamp Unlock Codes - GunDB Client
3
+ * Decentralized unlock code validation using GunDB public peers
4
+ *
5
+ * Usage for beginners:
6
+ * 1. Include GunDB: <script src="https://cdn.jsdelivr.net/npm/gun/gun.js"></script>
7
+ * 2. Include this script
8
+ * 3. Initialize: const unlockCodes = new TunecampUnlockCodes();
9
+ * 4. Validate: unlockCodes.validateCode(releaseSlug, userCode).then(valid => {...})
10
+ *
11
+ * For private space (with keypair):
12
+ * const unlockCodes = new TunecampUnlockCodes({
13
+ * publicKey: 'artist-public-key-here'
14
+ * });
15
+ */
16
+
17
+ (function() {
18
+ 'use strict';
19
+
20
+ // Default public GunDB peers
21
+ const DEFAULT_PEERS = [
22
+ 'https://gun.defucc.me/gun',
23
+ 'https://gun.o8.is/gun',
24
+ 'https://shogun-relay.scobrudot.dev/gun',
25
+ 'https://relay.peer.ooo/gun',
26
+ ];
27
+
28
+ /**
29
+ * TunecampUnlockCodes class
30
+ * Handles code validation and redemption via GunDB
31
+ */
32
+ class TunecampUnlockCodes {
33
+ /**
34
+ * Initialize the unlock codes system
35
+ * @param {Object} options - Configuration options
36
+ * @param {Array} options.peers - GunDB peer URLs (default: public peers)
37
+ * @param {string} options.namespace - GunDB namespace (default: 'tunecamp')
38
+ * @param {string} options.publicKey - Artist's public key (for reading from private space)
39
+ */
40
+ constructor(options = {}) {
41
+ this.peers = options.peers || DEFAULT_PEERS;
42
+ this.namespace = options.namespace || 'tunecamp';
43
+ this.publicKey = options.publicKey || null; // Artist's public key for private space
44
+ this.gun = null;
45
+ this.initialized = false;
46
+
47
+ // Initialize GunDB when script loads
48
+ this.init();
49
+ }
50
+
51
+ /**
52
+ * Initialize GunDB connection
53
+ */
54
+ async init() {
55
+ // Check if Gun is available
56
+ if (typeof Gun === 'undefined') {
57
+ console.warn('GunDB not loaded. Please include gun.js before unlock-codes.js');
58
+ return;
59
+ }
60
+
61
+ // Initialize Gun with peers
62
+ this.gun = Gun({
63
+ peers: this.peers,
64
+ localStorage: true, // Use localStorage for offline caching
65
+ });
66
+
67
+ this.initialized = true;
68
+ const spaceType = this.publicKey ? 'private (artist space)' : 'public';
69
+ console.log(`🔐 Tunecamp Unlock Codes initialized (${spaceType})`);
70
+ }
71
+
72
+ /**
73
+ * Get the root node for code storage
74
+ * If publicKey is set, reads from artist's user space
75
+ * Otherwise reads from public space
76
+ */
77
+ getCodesRoot() {
78
+ if (this.publicKey) {
79
+ // Read from artist's private/user space using their public key
80
+ return this.gun.user(this.publicKey).get(this.namespace);
81
+ }
82
+ // Read from public space
83
+ return this.gun.get(this.namespace);
84
+ }
85
+
86
+ /**
87
+ * Wait for Gun to be ready
88
+ */
89
+ async waitForInit() {
90
+ if (this.initialized) return;
91
+
92
+ return new Promise((resolve) => {
93
+ const check = () => {
94
+ if (this.initialized) {
95
+ resolve();
96
+ } else {
97
+ setTimeout(check, 100);
98
+ }
99
+ };
100
+ check();
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Hash a code for secure storage
106
+ * @param {string} code - The unlock code
107
+ * @returns {string} Hashed code
108
+ */
109
+ async hashCode(code) {
110
+ const encoder = new TextEncoder();
111
+ const data = encoder.encode(code.toLowerCase().trim());
112
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
113
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
114
+ return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
115
+ }
116
+
117
+ /**
118
+ * Validate an unlock code
119
+ * @param {string} releaseSlug - The release identifier
120
+ * @param {string} code - The unlock code entered by user
121
+ * @returns {Promise<Object>} Validation result
122
+ */
123
+ async validateCode(releaseSlug, code) {
124
+ await this.waitForInit();
125
+
126
+ if (!this.gun) {
127
+ return { valid: false, error: 'GunDB not initialized' };
128
+ }
129
+
130
+ const codeHash = await this.hashCode(code);
131
+
132
+ return new Promise((resolve) => {
133
+ this.getCodesRoot()
134
+ .get('releases')
135
+ .get(releaseSlug)
136
+ .get('codes')
137
+ .get(codeHash)
138
+ .once((data) => {
139
+ if (!data) {
140
+ resolve({ valid: false, error: 'Invalid code' });
141
+ return;
142
+ }
143
+
144
+ if (data.used) {
145
+ resolve({ valid: false, error: 'Code already used' });
146
+ return;
147
+ }
148
+
149
+ resolve({
150
+ valid: true,
151
+ data: {
152
+ maxDownloads: data.maxDownloads || 1,
153
+ currentDownloads: data.downloads || 0,
154
+ expiresAt: data.expiresAt,
155
+ }
156
+ });
157
+ });
158
+ });
159
+ }
160
+
161
+ /**
162
+ * Redeem a code (mark as used)
163
+ * @param {string} releaseSlug - The release identifier
164
+ * @param {string} code - The unlock code
165
+ * @returns {Promise<Object>} Redemption result
166
+ */
167
+ async redeemCode(releaseSlug, code) {
168
+ await this.waitForInit();
169
+
170
+ if (!this.gun) {
171
+ return { success: false, error: 'GunDB not initialized' };
172
+ }
173
+
174
+ const codeHash = await this.hashCode(code);
175
+
176
+ return new Promise((resolve) => {
177
+ const codeRef = this.getCodesRoot()
178
+ .get('releases')
179
+ .get(releaseSlug)
180
+ .get('codes')
181
+ .get(codeHash);
182
+
183
+ codeRef.once((data) => {
184
+ if (!data) {
185
+ resolve({ success: false, error: 'Invalid code' });
186
+ return;
187
+ }
188
+
189
+ if (data.used) {
190
+ resolve({ success: false, error: 'Code already used' });
191
+ return;
192
+ }
193
+
194
+ // Check max downloads
195
+ const downloads = (data.downloads || 0) + 1;
196
+ const maxDownloads = data.maxDownloads || 1;
197
+ const used = downloads >= maxDownloads;
198
+
199
+ // Update the code (note: this only works if codes are in public space
200
+ // or if artist has write access - for private space, updates won't persist)
201
+ codeRef.put({
202
+ ...data,
203
+ downloads,
204
+ used,
205
+ lastUsedAt: Date.now(),
206
+ });
207
+
208
+ resolve({
209
+ success: true,
210
+ downloadsRemaining: maxDownloads - downloads
211
+ });
212
+ });
213
+ });
214
+ }
215
+
216
+ /**
217
+ * Get release info (for artists to check their codes)
218
+ * @param {string} releaseSlug - The release identifier
219
+ */
220
+ async getReleaseInfo(releaseSlug) {
221
+ await this.waitForInit();
222
+
223
+ return new Promise((resolve) => {
224
+ const codes = [];
225
+
226
+ this.getCodesRoot()
227
+ .get('releases')
228
+ .get(releaseSlug)
229
+ .get('codes')
230
+ .map()
231
+ .once((data, key) => {
232
+ if (data) {
233
+ codes.push({ hash: key, ...data });
234
+ }
235
+ });
236
+
237
+ // Give it some time to collect all codes
238
+ setTimeout(() => {
239
+ resolve(codes);
240
+ }, 1000);
241
+ });
242
+ }
243
+
244
+ /**
245
+ * Check if using private space (artist's user space)
246
+ * @returns {boolean} True if using private space
247
+ */
248
+ isPrivateSpace() {
249
+ return !!this.publicKey;
250
+ }
251
+ }
252
+
253
+ // Expose globally
254
+ window.TunecampUnlockCodes = TunecampUnlockCodes;
255
+ })();
@@ -7,6 +7,11 @@
7
7
  * 2. Include this script
8
8
  * 3. Initialize: const unlockCodes = new TunecampUnlockCodes();
9
9
  * 4. Validate: unlockCodes.validateCode(releaseSlug, userCode).then(valid => {...})
10
+ *
11
+ * For private space (with keypair):
12
+ * const unlockCodes = new TunecampUnlockCodes({
13
+ * publicKey: 'artist-public-key-here'
14
+ * });
10
15
  */
11
16
 
12
17
  (function() {
@@ -14,8 +19,10 @@
14
19
 
15
20
  // Default public GunDB peers
16
21
  const DEFAULT_PEERS = [
17
- 'https://gun-manhattan.herokuapp.com/gun',
18
- 'https://gun-us.herokuapp.com/gun',
22
+ 'https://gun.defucc.me/gun',
23
+ 'https://gun.o8.is/gun',
24
+ 'https://shogun-relay.scobrudot.dev/gun',
25
+ 'https://relay.peer.ooo/gun',
19
26
  ];
20
27
 
21
28
  /**
@@ -28,10 +35,12 @@
28
35
  * @param {Object} options - Configuration options
29
36
  * @param {Array} options.peers - GunDB peer URLs (default: public peers)
30
37
  * @param {string} options.namespace - GunDB namespace (default: 'tunecamp')
38
+ * @param {string} options.publicKey - Artist's public key (for reading from private space)
31
39
  */
32
40
  constructor(options = {}) {
33
41
  this.peers = options.peers || DEFAULT_PEERS;
34
42
  this.namespace = options.namespace || 'tunecamp';
43
+ this.publicKey = options.publicKey || null; // Artist's public key for private space
35
44
  this.gun = null;
36
45
  this.initialized = false;
37
46
 
@@ -56,7 +65,22 @@
56
65
  });
57
66
 
58
67
  this.initialized = true;
59
- console.log('🔐 Tunecamp Unlock Codes initialized');
68
+ const spaceType = this.publicKey ? 'private (artist space)' : 'public';
69
+ console.log(`🔐 Tunecamp Unlock Codes initialized (${spaceType})`);
70
+ }
71
+
72
+ /**
73
+ * Get the root node for code storage
74
+ * If publicKey is set, reads from artist's user space
75
+ * Otherwise reads from public space
76
+ */
77
+ getCodesRoot() {
78
+ if (this.publicKey) {
79
+ // Read from artist's private/user space using their public key
80
+ return this.gun.user(this.publicKey).get(this.namespace);
81
+ }
82
+ // Read from public space
83
+ return this.gun.get(this.namespace);
60
84
  }
61
85
 
62
86
  /**
@@ -106,8 +130,7 @@
106
130
  const codeHash = await this.hashCode(code);
107
131
 
108
132
  return new Promise((resolve) => {
109
- this.gun
110
- .get(this.namespace)
133
+ this.getCodesRoot()
111
134
  .get('releases')
112
135
  .get(releaseSlug)
113
136
  .get('codes')
@@ -151,8 +174,7 @@
151
174
  const codeHash = await this.hashCode(code);
152
175
 
153
176
  return new Promise((resolve) => {
154
- const codeRef = this.gun
155
- .get(this.namespace)
177
+ const codeRef = this.getCodesRoot()
156
178
  .get('releases')
157
179
  .get(releaseSlug)
158
180
  .get('codes')
@@ -174,7 +196,8 @@
174
196
  const maxDownloads = data.maxDownloads || 1;
175
197
  const used = downloads >= maxDownloads;
176
198
 
177
- // Update the code
199
+ // Update the code (note: this only works if codes are in public space
200
+ // or if artist has write access - for private space, updates won't persist)
178
201
  codeRef.put({
179
202
  ...data,
180
203
  downloads,
@@ -200,8 +223,7 @@
200
223
  return new Promise((resolve) => {
201
224
  const codes = [];
202
225
 
203
- this.gun
204
- .get(this.namespace)
226
+ this.getCodesRoot()
205
227
  .get('releases')
206
228
  .get(releaseSlug)
207
229
  .get('codes')
@@ -218,6 +240,14 @@
218
240
  }, 1000);
219
241
  });
220
242
  }
243
+
244
+ /**
245
+ * Check if using private space (artist's user space)
246
+ * @returns {boolean} True if using private space
247
+ */
248
+ isPrivateSpace() {
249
+ return !!this.publicKey;
250
+ }
221
251
  }
222
252
 
223
253
  // Expose globally
@@ -9,7 +9,7 @@
9
9
  <meta name="description" content="{{catalog.description}}">
10
10
  {{/if}}
11
11
  <!-- Tunecamp Metadata (for community registry) -->
12
- <meta name="generator" content="Tunecamp 0.1.0">
12
+ <meta name="generator" content="Tunecamp 1.0.0">
13
13
  <meta name="tunecamp-title" content="{{catalog.title}}">
14
14
  {{#if artist}}
15
15
  <meta name="tunecamp-artist" content="{{artist.name}}">
@@ -208,6 +208,7 @@
208
208
  (function () {
209
209
  const releaseSlug = '{{release.slug}}';
210
210
  const namespace = '{{#if release.config.unlockCodes.namespace}}{{release.config.unlockCodes.namespace}}{{else}}tunecamp{{/if}}';
211
+ const publicKey = '{{#if release.config.unlockCodes.publicKey}}{{release.config.unlockCodes.publicKey}}{{/if}}';
211
212
 
212
213
  // Initialize unlock codes
213
214
  let unlockCodes;
@@ -221,7 +222,13 @@
221
222
  }
222
223
 
223
224
  // Initialize GunDB unlock codes
224
- unlockCodes = new TunecampUnlockCodes({ namespace });
225
+ // If publicKey is set, codes are read from artist's private space
226
+ const options = { namespace };
227
+ if (publicKey) {
228
+ options.publicKey = publicKey;
229
+ console.log('🔐 Using artist private space for unlock codes');
230
+ }
231
+ unlockCodes = new TunecampUnlockCodes(options);
225
232
 
226
233
  // Bind form events
227
234
  const input = document.getElementById('unlockCodeInput');