wiki-plugin-shoppe 0.0.43 → 0.0.46
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
package/server/server.js
CHANGED
|
@@ -84,10 +84,24 @@ function getSanoraUrl() {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function getAddieUrl() {
|
|
87
|
-
|
|
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 ? `${
|
|
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
|
|
@@ -3243,6 +3257,8 @@ async function startServer(params) {
|
|
|
3243
3257
|
tenantUuid: tenant.uuid,
|
|
3244
3258
|
keywords: extractKeywords(product),
|
|
3245
3259
|
shopName: tenant.name || '',
|
|
3260
|
+
shopName_json: JSON.stringify(tenant.name || ''),
|
|
3261
|
+
title_json: JSON.stringify(product.title || title),
|
|
3246
3262
|
category: product.category || 'book',
|
|
3247
3263
|
});
|
|
3248
3264
|
|
|
@@ -3278,7 +3294,7 @@ async function startServer(params) {
|
|
|
3278
3294
|
const schedule = await getAppointmentSchedule(tenant, product);
|
|
3279
3295
|
const wikiOrigin = `${reqProto(req)}://${req.get('host')}`;
|
|
3280
3296
|
const shoppeUrl = `${wikiOrigin}/plugin/shoppe/${tenant.uuid}`;
|
|
3281
|
-
const imageUrl = product.image ? `${
|
|
3297
|
+
const imageUrl = product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : '';
|
|
3282
3298
|
|
|
3283
3299
|
const price = product.price || 0;
|
|
3284
3300
|
const html = fillTemplate(APPOINTMENT_BOOKING_TMPL, {
|
|
@@ -3293,7 +3309,8 @@ async function startServer(params) {
|
|
|
3293
3309
|
proceedLabel: price === 0 ? 'Confirm Booking →' : 'Continue to Payment →',
|
|
3294
3310
|
shoppeUrl,
|
|
3295
3311
|
tenantUuid: tenant.uuid,
|
|
3296
|
-
keywords: extractKeywords(product)
|
|
3312
|
+
keywords: extractKeywords(product),
|
|
3313
|
+
title_json: JSON.stringify(product.title || title),
|
|
3297
3314
|
});
|
|
3298
3315
|
|
|
3299
3316
|
res.set('Content-Type', 'text/html');
|
|
@@ -3346,7 +3363,7 @@ async function startServer(params) {
|
|
|
3346
3363
|
const tierInfo = await getTierInfo(tenant, product);
|
|
3347
3364
|
const wikiOrigin = `${reqProto(req)}://${req.get('host')}`;
|
|
3348
3365
|
const shoppeUrl = `${wikiOrigin}/plugin/shoppe/${tenant.uuid}`;
|
|
3349
|
-
const imageUrl = product.image ? `${
|
|
3366
|
+
const imageUrl = product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : '';
|
|
3350
3367
|
const benefits = tierInfo && tierInfo.benefits
|
|
3351
3368
|
? tierInfo.benefits.map(b => `<li>${escHtml(b)}</li>`).join('')
|
|
3352
3369
|
: '';
|
|
@@ -3362,7 +3379,8 @@ async function startServer(params) {
|
|
|
3362
3379
|
renewalDays: String(tierInfo ? (tierInfo.renewalDays || 30) : 30),
|
|
3363
3380
|
shoppeUrl,
|
|
3364
3381
|
tenantUuid: tenant.uuid,
|
|
3365
|
-
keywords: extractKeywords(product)
|
|
3382
|
+
keywords: extractKeywords(product),
|
|
3383
|
+
title_json: JSON.stringify(product.title || title),
|
|
3366
3384
|
});
|
|
3367
3385
|
|
|
3368
3386
|
res.set('Content-Type', 'text/html');
|
|
@@ -3527,7 +3545,7 @@ async function startServer(params) {
|
|
|
3527
3545
|
productId: product.productId,
|
|
3528
3546
|
description: product.description || '',
|
|
3529
3547
|
price: product.price || 0,
|
|
3530
|
-
image: product.image ? `${
|
|
3548
|
+
image: product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : null,
|
|
3531
3549
|
benefits: tierInfo ? (tierInfo.benefits || []) : [],
|
|
3532
3550
|
renewalDays: tierInfo ? (tierInfo.renewalDays || 30) : 30,
|
|
3533
3551
|
active: status.active,
|
|
@@ -4036,14 +4054,15 @@ async function startServer(params) {
|
|
|
4036
4054
|
if (!purchased) return res.status(403).send('<h1>No purchase found for this key</h1>');
|
|
4037
4055
|
}
|
|
4038
4056
|
|
|
4039
|
-
const
|
|
4057
|
+
const sanoraPublicUrl = getSanoraPublicUrl(req);
|
|
4058
|
+
const imageUrl = product.image ? `${sanoraPublicUrl}/images/${product.image}` : '';
|
|
4040
4059
|
|
|
4041
4060
|
// Map artifact UUIDs to download paths by extension
|
|
4042
4061
|
let epubPath = '', pdfPath = '', mobiPath = '';
|
|
4043
4062
|
(product.artifacts || []).forEach(artifact => {
|
|
4044
|
-
if (artifact.includes('epub')) epubPath = `${
|
|
4045
|
-
if (artifact.includes('pdf')) pdfPath = `${
|
|
4046
|
-
if (artifact.includes('mobi')) mobiPath = `${
|
|
4063
|
+
if (artifact.includes('epub')) epubPath = `${sanoraPublicUrl}/artifacts/${artifact}`;
|
|
4064
|
+
if (artifact.includes('pdf')) pdfPath = `${sanoraPublicUrl}/artifacts/${artifact}`;
|
|
4065
|
+
if (artifact.includes('mobi')) mobiPath = `${sanoraPublicUrl}/artifacts/${artifact}`;
|
|
4047
4066
|
});
|
|
4048
4067
|
|
|
4049
4068
|
const html = fillTemplate(EBOOK_DOWNLOAD_TMPL, {
|
|
@@ -4089,7 +4108,7 @@ async function startServer(params) {
|
|
|
4089
4108
|
const fm = parseFrontMatter(mdContent);
|
|
4090
4109
|
const postTitle = fm.title || title;
|
|
4091
4110
|
const postDate = fm.date || '';
|
|
4092
|
-
const imageUrl = product.image ? `${
|
|
4111
|
+
const imageUrl = product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : null;
|
|
4093
4112
|
|
|
4094
4113
|
res.set('Content-Type', 'text/html');
|
|
4095
4114
|
res.send(generatePostHTML(tenant, postTitle, postDate, imageUrl, fm.body || mdContent));
|
|
@@ -4164,7 +4183,7 @@ async function startServer(params) {
|
|
|
4164
4183
|
productId: product.productId,
|
|
4165
4184
|
title: product.title,
|
|
4166
4185
|
category: product.category,
|
|
4167
|
-
image: product.image ? `${
|
|
4186
|
+
image: product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : null,
|
|
4168
4187
|
price: product.price,
|
|
4169
4188
|
paidAt: match.paidAt,
|
|
4170
4189
|
status: match.status,
|
|
@@ -4190,7 +4209,7 @@ async function startServer(params) {
|
|
|
4190
4209
|
try {
|
|
4191
4210
|
const tenant = getTenantByIdentifier(req.params.identifier);
|
|
4192
4211
|
if (!tenant) return res.status(404).json({ error: 'Shoppe not found' });
|
|
4193
|
-
const goods = await getShoppeGoods(tenant);
|
|
4212
|
+
const goods = await getShoppeGoods(tenant, getSanoraPublicUrl(req));
|
|
4194
4213
|
const cat = req.query.category;
|
|
4195
4214
|
res.json({ success: true, goods: (cat && goods[cat]) ? goods[cat] : goods });
|
|
4196
4215
|
} catch (err) {
|
|
@@ -4212,7 +4231,7 @@ async function startServer(params) {
|
|
|
4212
4231
|
const tracks = [];
|
|
4213
4232
|
for (const [key, product] of Object.entries(products)) {
|
|
4214
4233
|
if (product.category !== 'music') continue;
|
|
4215
|
-
const cover = product.image ? `${
|
|
4234
|
+
const cover = product.image ? `${getSanoraPublicUrl(req)}/images/${product.image}` : null;
|
|
4216
4235
|
const artifacts = product.artifacts || [];
|
|
4217
4236
|
if (artifacts.length > 1) {
|
|
4218
4237
|
albums.push({
|
|
@@ -4246,7 +4265,7 @@ async function startServer(params) {
|
|
|
4246
4265
|
try {
|
|
4247
4266
|
const tenant = getTenantByIdentifier(req.params.identifier);
|
|
4248
4267
|
if (!tenant) return res.status(404).send('<h1>Shoppe not found</h1>');
|
|
4249
|
-
const goods = await getShoppeGoods(tenant);
|
|
4268
|
+
const goods = await getShoppeGoods(tenant, getSanoraPublicUrl(req));
|
|
4250
4269
|
|
|
4251
4270
|
// Check if the request carries a valid owner signature — if so, embed auth
|
|
4252
4271
|
// params in the page so the upload button can authenticate with upload-info.
|
|
@@ -506,7 +506,7 @@
|
|
|
506
506
|
headers: {'Content-Type': 'application/json'},
|
|
507
507
|
body: JSON.stringify({
|
|
508
508
|
productId: '{{productId}}',
|
|
509
|
-
title:
|
|
509
|
+
title: {{title_json}},
|
|
510
510
|
...(URL_PAYEES && { payees: URL_PAYEES })
|
|
511
511
|
})
|
|
512
512
|
});
|
|
@@ -548,7 +548,7 @@
|
|
|
548
548
|
body: JSON.stringify({
|
|
549
549
|
orderRef,
|
|
550
550
|
productId: '{{productId}}',
|
|
551
|
-
title:
|
|
551
|
+
title: {{title_json}},
|
|
552
552
|
amount: {{amount}},
|
|
553
553
|
address: window.pendingAddress,
|
|
554
554
|
paymentIntentId
|
|
@@ -193,7 +193,7 @@
|
|
|
193
193
|
return p;
|
|
194
194
|
}).filter(p => p.pubKey);
|
|
195
195
|
}
|
|
196
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -227,7 +227,7 @@
|
|
|
227
227
|
timestamp: _buyerTimestamp,
|
|
228
228
|
signature: _buyerSignature,
|
|
229
229
|
productId: '{{productId}}',
|
|
230
|
-
title:
|
|
230
|
+
title: {{title_json}},
|
|
231
231
|
...(URL_PAYEES && { payees: URL_PAYEES }),
|
|
232
232
|
...(IS_AFFILIATE_CHARGE && { affiliatePubKey: _affiliatePubKey })
|
|
233
233
|
})
|
|
@@ -294,7 +294,7 @@
|
|
|
294
294
|
timestamp: _buyerTimestamp,
|
|
295
295
|
signature: _buyerSignature,
|
|
296
296
|
productId: '{{productId}}',
|
|
297
|
-
title:
|
|
297
|
+
title: {{title_json}},
|
|
298
298
|
...(paymentIntentId && { paymentIntentId })
|
|
299
299
|
})
|
|
300
300
|
});
|
|
@@ -329,8 +329,8 @@
|
|
|
329
329
|
const deepLink = 'shoppere://buy?' + new URLSearchParams({
|
|
330
330
|
domain: window.location.hostname,
|
|
331
331
|
shopId: '{{tenantUuid}}',
|
|
332
|
-
shopName:
|
|
333
|
-
productTitle:
|
|
332
|
+
shopName: {{shopName_json}},
|
|
333
|
+
productTitle: {{title_json}},
|
|
334
334
|
productId: '{{productId}}',
|
|
335
335
|
price: '{{amount}}',
|
|
336
336
|
category: '{{category}}',
|
|
@@ -553,7 +553,7 @@
|
|
|
553
553
|
body: JSON.stringify({
|
|
554
554
|
recoveryKey,
|
|
555
555
|
productId: '{{productId}}',
|
|
556
|
-
title:
|
|
556
|
+
title: {{title_json}},
|
|
557
557
|
...(URL_PAYEES && { payees: URL_PAYEES })
|
|
558
558
|
})
|
|
559
559
|
});
|