wiki-plugin-shoppe 0.0.43 → 0.0.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-plugin-shoppe",
3
- "version": "0.0.43",
3
+ "version": "0.0.45",
4
4
  "description": "Multi-tenant digital goods shoppe for federated wiki, powered by Sanora",
5
5
  "keywords": [
6
6
  "wiki",
package/server/server.js CHANGED
@@ -84,10 +84,24 @@ function getSanoraUrl() {
84
84
  }
85
85
 
86
86
  function getAddieUrl() {
87
- try { return new URL(getSanoraUrl()).origin + '/plugin/allyabase/addie'; } catch { /* fall through */ }
87
+ const sanora = getSanoraUrl();
88
+ try {
89
+ const url = new URL(sanora);
90
+ // Only derive from origin when sanora is a wiki proxy URL (has a path component).
91
+ // A bare host:port URL (e.g. http://localhost:7243) means Addie is on its own port.
92
+ if (url.pathname && url.pathname !== '/') {
93
+ return url.origin + '/plugin/allyabase/addie';
94
+ }
95
+ } catch { /* fall through */ }
88
96
  return `http://localhost:${process.env.ADDIE_PORT || 3005}`;
89
97
  }
90
98
 
99
+ // Returns the public-facing Sanora URL (via wiki proxy) for browser-visible resource URLs.
100
+ // Always constructed from the current request so it matches the host the browser is using.
101
+ function getSanoraPublicUrl(req) {
102
+ return `${reqProto(req)}://${req.get('host')}/plugin/allyabase/sanora`;
103
+ }
104
+
91
105
  function getLucilleUrl() {
92
106
  const config = loadConfig();
93
107
  if (config.lucilleUrl) return config.lucilleUrl.replace(/\/$/, '');
@@ -1501,7 +1515,7 @@ async function processArchive(zipPath, onProgress = () => {}) {
1501
1515
  // PORTFOLIO PAGE GENERATION
1502
1516
  // ============================================================
1503
1517
 
1504
- async function getShoppeGoods(tenant) {
1518
+ async function getShoppeGoods(tenant, imageBaseUrl) {
1505
1519
  let products = {};
1506
1520
  try {
1507
1521
  const resp = await fetch(`${getSanoraUrl()}/products/${tenant.uuid}`, { timeout: 15000 });
@@ -1556,7 +1570,7 @@ async function getShoppeGoods(tenant) {
1556
1570
  description: product.description || '',
1557
1571
  price: product.price || 0,
1558
1572
  shipping: product.shipping || 0,
1559
- image: product.image ? `${getSanoraUrl()}/images/${product.image}` : null,
1573
+ image: product.image ? `${imageBaseUrl || getSanoraUrl()}/images/${product.image}` : null,
1560
1574
  url: resolvedUrl,
1561
1575
  ...(isPost && { category: product.category, tags: product.tags || '' }),
1562
1576
  ...(lucillePlayerUrl && { lucillePlayerUrl }),
@@ -3207,7 +3221,7 @@ async function startServer(params) {
3207
3221
  const product = products[title] || Object.values(products).find(p => p.title === title);
3208
3222
  if (!product) return res.status(404).send('<h1>Product not found</h1>');
3209
3223
 
3210
- const imageUrl = product.image ? `${sanoraUrlInternal}/images/${product.image}` : '';
3224
+ const imageUrl = product.image ? `${sanoraUrl}/images/${product.image}` : '';
3211
3225
  const ebookUrl = `${wikiOrigin}/plugin/shoppe/${tenant.uuid}/download/${encodeURIComponent(title)}`;
3212
3226
  const shoppeUrl = `${wikiOrigin}/plugin/shoppe/${tenant.uuid}`;
3213
3227
  const payees = tenant.addieKeys
@@ -3278,7 +3292,7 @@ async function startServer(params) {
3278
3292
  const schedule = await getAppointmentSchedule(tenant, product);
3279
3293
  const wikiOrigin = `${reqProto(req)}://${req.get('host')}`;
3280
3294
  const shoppeUrl = `${wikiOrigin}/plugin/shoppe/${tenant.uuid}`;
3281
- const imageUrl = product.image ? `${sanoraUrl}/images/${product.image}` : '';
3295
+ const imageUrl = product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : '';
3282
3296
 
3283
3297
  const price = product.price || 0;
3284
3298
  const html = fillTemplate(APPOINTMENT_BOOKING_TMPL, {
@@ -3346,7 +3360,7 @@ async function startServer(params) {
3346
3360
  const tierInfo = await getTierInfo(tenant, product);
3347
3361
  const wikiOrigin = `${reqProto(req)}://${req.get('host')}`;
3348
3362
  const shoppeUrl = `${wikiOrigin}/plugin/shoppe/${tenant.uuid}`;
3349
- const imageUrl = product.image ? `${sanoraUrl}/images/${product.image}` : '';
3363
+ const imageUrl = product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : '';
3350
3364
  const benefits = tierInfo && tierInfo.benefits
3351
3365
  ? tierInfo.benefits.map(b => `<li>${escHtml(b)}</li>`).join('')
3352
3366
  : '';
@@ -3527,7 +3541,7 @@ async function startServer(params) {
3527
3541
  productId: product.productId,
3528
3542
  description: product.description || '',
3529
3543
  price: product.price || 0,
3530
- image: product.image ? `${sanoraUrl}/images/${product.image}` : null,
3544
+ image: product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : null,
3531
3545
  benefits: tierInfo ? (tierInfo.benefits || []) : [],
3532
3546
  renewalDays: tierInfo ? (tierInfo.renewalDays || 30) : 30,
3533
3547
  active: status.active,
@@ -4036,14 +4050,15 @@ async function startServer(params) {
4036
4050
  if (!purchased) return res.status(403).send('<h1>No purchase found for this key</h1>');
4037
4051
  }
4038
4052
 
4039
- const imageUrl = product.image ? `${sanoraUrl}/images/${product.image}` : '';
4053
+ const sanoraPublicUrl = getSanoraPublicUrl(req);
4054
+ const imageUrl = product.image ? `${sanoraPublicUrl}/images/${product.image}` : '';
4040
4055
 
4041
4056
  // Map artifact UUIDs to download paths by extension
4042
4057
  let epubPath = '', pdfPath = '', mobiPath = '';
4043
4058
  (product.artifacts || []).forEach(artifact => {
4044
- if (artifact.includes('epub')) epubPath = `${sanoraUrl}/artifacts/${artifact}`;
4045
- if (artifact.includes('pdf')) pdfPath = `${sanoraUrl}/artifacts/${artifact}`;
4046
- if (artifact.includes('mobi')) mobiPath = `${sanoraUrl}/artifacts/${artifact}`;
4059
+ if (artifact.includes('epub')) epubPath = `${sanoraPublicUrl}/artifacts/${artifact}`;
4060
+ if (artifact.includes('pdf')) pdfPath = `${sanoraPublicUrl}/artifacts/${artifact}`;
4061
+ if (artifact.includes('mobi')) mobiPath = `${sanoraPublicUrl}/artifacts/${artifact}`;
4047
4062
  });
4048
4063
 
4049
4064
  const html = fillTemplate(EBOOK_DOWNLOAD_TMPL, {
@@ -4089,7 +4104,7 @@ async function startServer(params) {
4089
4104
  const fm = parseFrontMatter(mdContent);
4090
4105
  const postTitle = fm.title || title;
4091
4106
  const postDate = fm.date || '';
4092
- const imageUrl = product.image ? `${getSanoraUrl()}/images/${product.image}` : null;
4107
+ const imageUrl = product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : null;
4093
4108
 
4094
4109
  res.set('Content-Type', 'text/html');
4095
4110
  res.send(generatePostHTML(tenant, postTitle, postDate, imageUrl, fm.body || mdContent));
@@ -4164,7 +4179,7 @@ async function startServer(params) {
4164
4179
  productId: product.productId,
4165
4180
  title: product.title,
4166
4181
  category: product.category,
4167
- image: product.image ? `${sanoraUrl}/images/${product.image}` : null,
4182
+ image: product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : null,
4168
4183
  price: product.price,
4169
4184
  paidAt: match.paidAt,
4170
4185
  status: match.status,
@@ -4190,7 +4205,7 @@ async function startServer(params) {
4190
4205
  try {
4191
4206
  const tenant = getTenantByIdentifier(req.params.identifier);
4192
4207
  if (!tenant) return res.status(404).json({ error: 'Shoppe not found' });
4193
- const goods = await getShoppeGoods(tenant);
4208
+ const goods = await getShoppeGoods(tenant, getSanoraPublicUrl(req));
4194
4209
  const cat = req.query.category;
4195
4210
  res.json({ success: true, goods: (cat && goods[cat]) ? goods[cat] : goods });
4196
4211
  } catch (err) {
@@ -4212,7 +4227,7 @@ async function startServer(params) {
4212
4227
  const tracks = [];
4213
4228
  for (const [key, product] of Object.entries(products)) {
4214
4229
  if (product.category !== 'music') continue;
4215
- const cover = product.image ? `${sanoraUrl}/images/${product.image}` : null;
4230
+ const cover = product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : null;
4216
4231
  const artifacts = product.artifacts || [];
4217
4232
  if (artifacts.length > 1) {
4218
4233
  albums.push({
@@ -4246,7 +4261,7 @@ async function startServer(params) {
4246
4261
  try {
4247
4262
  const tenant = getTenantByIdentifier(req.params.identifier);
4248
4263
  if (!tenant) return res.status(404).send('<h1>Shoppe not found</h1>');
4249
- const goods = await getShoppeGoods(tenant);
4264
+ const goods = await getShoppeGoods(tenant, getSanoraPublicUrl(req));
4250
4265
 
4251
4266
  // Check if the request carries a valid owner signature — if so, embed auth
4252
4267
  // params in the page so the upload button can authenticate with upload-info.
@@ -193,7 +193,7 @@
193
193
  return p;
194
194
  }).filter(p => p.pubKey);
195
195
  }
196
- const URL_PAYEES = parseUrlPayees();
196
+ var URL_PAYEES = parseUrlPayees();
197
197
  </script>
198
198
 
199
199
  <!-- ── Shoppere (pubKey) path ────────────────────────────────────────────── -->
@@ -202,7 +202,7 @@
202
202
  const _buyerPubKey = '{{buyerPubKey}}' || new URLSearchParams(window.location.search).get('pubKey') || '';
203
203
  const _buyerTimestamp = '{{buyerTimestamp}}' || new URLSearchParams(window.location.search).get('timestamp') || '';
204
204
  const _buyerSignature = '{{buyerSignature}}' || new URLSearchParams(window.location.search).get('signature') || '';
205
- const IS_SHOPPERE = !!(_buyerPubKey && _buyerTimestamp && _buyerSignature);
205
+ var IS_SHOPPERE = !!(_buyerPubKey && _buyerTimestamp && _buyerSignature);
206
206
  // Affiliate (NFC proximity charge / referral link) param — present when buyer arrived via a referred link
207
207
  const _affiliatePubKey = new URLSearchParams(window.location.search).get('affiliatePubKey') || '';
208
208
  const IS_AFFILIATE_CHARGE = !!_affiliatePubKey;