javascript-solid-server 0.0.129 → 0.0.131
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/.claude/settings.local.json +2 -1
- package/package.json +1 -1
- package/src/auth/middleware.js +2 -2
- package/src/ldp/headers.js +1 -1
- package/src/server.js +8 -1
- package/src/token.js +21 -20
- package/src/wac/checker.js +3 -3
|
@@ -342,7 +342,8 @@
|
|
|
342
342
|
"Bash(sed -i 's/\"currency\": \"sats\"/\"currency\": \"tbtc4\"/g' /home/melvin/articles/solid-402.html /home/melvin/articles/solid-pay.html /home/melvin/articles/solid-balance.html)",
|
|
343
343
|
"Bash(sed -i 's/\"currency\":\"sats\"/\"currency\":\"tbtc4\"/g' /home/melvin/articles/solid-402.html /home/melvin/articles/solid-pay.html /home/melvin/articles/solid-balance.html)",
|
|
344
344
|
"WebFetch(domain:lists.w3.org)",
|
|
345
|
-
"Bash(git:*)"
|
|
345
|
+
"Bash(git:*)",
|
|
346
|
+
"Bash(npm publish:*)"
|
|
346
347
|
]
|
|
347
348
|
}
|
|
348
349
|
}
|
package/package.json
CHANGED
package/src/auth/middleware.js
CHANGED
|
@@ -104,7 +104,7 @@ export async function authorize(request, reply, options = {}) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// Check WAC permissions
|
|
107
|
-
const { allowed, wacAllow, paymentRequired } = await checkAccess({
|
|
107
|
+
const { allowed, wacAllow, paymentRequired, paid, balance, currency } = await checkAccess({
|
|
108
108
|
resourceUrl: checkUrl,
|
|
109
109
|
resourcePath: checkPath,
|
|
110
110
|
isContainer: checkIsContainer,
|
|
@@ -112,7 +112,7 @@ export async function authorize(request, reply, options = {}) {
|
|
|
112
112
|
requiredMode
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
return { authorized: allowed, webId, wacAllow, authError, paymentRequired };
|
|
115
|
+
return { authorized: allowed, webId, wacAllow, authError, paymentRequired, paid, balance, currency };
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
/**
|
package/src/ldp/headers.js
CHANGED
|
@@ -96,7 +96,7 @@ export function getCorsHeaders(origin) {
|
|
|
96
96
|
'Access-Control-Allow-Origin': origin || '*',
|
|
97
97
|
'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS',
|
|
98
98
|
'Access-Control-Allow-Headers': 'Accept, Authorization, Content-Type, DPoP, If-Match, If-None-Match, Link, Range, Slug, Origin',
|
|
99
|
-
'Access-Control-Expose-Headers': 'Accept-Patch, Accept-Post, Accept-Ranges, Allow, Content-Length, Content-Range, Content-Type, ETag, Link, Location, Updates-Via, WAC-Allow',
|
|
99
|
+
'Access-Control-Expose-Headers': 'Accept-Patch, Accept-Post, Accept-Ranges, Allow, Content-Length, Content-Range, Content-Type, ETag, Link, Location, Updates-Via, WAC-Allow, X-Cost, X-Balance, X-Pay-Currency',
|
|
100
100
|
'Access-Control-Allow-Credentials': 'true',
|
|
101
101
|
'Access-Control-Max-Age': '86400'
|
|
102
102
|
};
|
package/src/server.js
CHANGED
|
@@ -448,7 +448,7 @@ export function createServer(options = {}) {
|
|
|
448
448
|
return;
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
-
const { authorized, webId, wacAllow, authError, paymentRequired } = await authorize(request, reply);
|
|
451
|
+
const { authorized, webId, wacAllow, authError, paymentRequired, paid, balance, currency } = await authorize(request, reply);
|
|
452
452
|
|
|
453
453
|
// Store webId and wacAllow on request for handlers to use
|
|
454
454
|
request.webId = webId;
|
|
@@ -457,6 +457,13 @@ export function createServer(options = {}) {
|
|
|
457
457
|
// Set WAC-Allow header for all responses (handlers may override)
|
|
458
458
|
reply.header('WAC-Allow', wacAllow);
|
|
459
459
|
|
|
460
|
+
// Set payment headers for paid access
|
|
461
|
+
if (paid !== undefined) {
|
|
462
|
+
reply.header('X-Cost', String(paid));
|
|
463
|
+
reply.header('X-Balance', String(balance));
|
|
464
|
+
if (currency) reply.header('X-Pay-Currency', currency);
|
|
465
|
+
}
|
|
466
|
+
|
|
460
467
|
// Handle payment-gated resources
|
|
461
468
|
if (paymentRequired) {
|
|
462
469
|
return reply.code(402).send({
|
package/src/token.js
CHANGED
|
@@ -187,33 +187,34 @@ async function broadcastTx(rawTxHex, mempoolUrl) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
// --- Trail persistence ---
|
|
190
|
-
function trailDir() {
|
|
191
|
-
return path.join(process.env.DATA_ROOT || './data', '.well-known', 'token');
|
|
190
|
+
function trailDir(root) {
|
|
191
|
+
return path.join(root || process.env.DATA_ROOT || './data', '.well-known', 'token');
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
function trailPath(ticker) {
|
|
195
|
-
return path.join(trailDir(), `${ticker.toLowerCase()}.json`);
|
|
194
|
+
function trailPath(ticker, root) {
|
|
195
|
+
return path.join(trailDir(root), `${ticker.toLowerCase()}.json`);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
export async function loadTrail(ticker) {
|
|
198
|
+
export async function loadTrail(ticker, root) {
|
|
199
199
|
try {
|
|
200
|
-
const data = await fs.readFile(trailPath(ticker), 'utf8');
|
|
200
|
+
const data = await fs.readFile(trailPath(ticker, root), 'utf8');
|
|
201
201
|
return JSON.parse(data);
|
|
202
202
|
} catch { return null; }
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
async function saveTrail(trail) {
|
|
206
|
-
await fs.ensureDir(trailDir());
|
|
207
|
-
await fs.writeFile(trailPath(trail.ticker), JSON.stringify(trail, null, 2));
|
|
205
|
+
async function saveTrail(trail, root) {
|
|
206
|
+
await fs.ensureDir(trailDir(root));
|
|
207
|
+
await fs.writeFile(trailPath(trail.ticker, root), JSON.stringify(trail, null, 2));
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
export async function listTrails() {
|
|
210
|
+
export async function listTrails(root) {
|
|
211
211
|
try {
|
|
212
|
-
const
|
|
212
|
+
const dir = trailDir(root);
|
|
213
|
+
const files = await fs.readdir(dir);
|
|
213
214
|
const trails = [];
|
|
214
215
|
for (const f of files) {
|
|
215
216
|
if (f.endsWith('.json')) {
|
|
216
|
-
const data = await fs.readFile(path.join(
|
|
217
|
+
const data = await fs.readFile(path.join(dir, f), 'utf8');
|
|
217
218
|
trails.push(JSON.parse(data));
|
|
218
219
|
}
|
|
219
220
|
}
|
|
@@ -235,14 +236,14 @@ export function parseTxoUri(uri) {
|
|
|
235
236
|
}
|
|
236
237
|
|
|
237
238
|
// --- Mint: create genesis MRC20 token ---
|
|
238
|
-
export async function mintToken({ ticker, name, supply, voucher, mempoolUrl = 'https://mempool.space/testnet4', network = 'testnet4' }) {
|
|
239
|
+
export async function mintToken({ ticker, name, supply, voucher, mempoolUrl = 'https://mempool.space/testnet4', network = 'testnet4', root }) {
|
|
239
240
|
const txo = parseTxoUri(voucher);
|
|
240
241
|
const privkeyBytes = hexToU8(txo.privkey);
|
|
241
242
|
const pubkeyBase = new Uint8Array(secp256k1.getPublicKey(privkeyBytes, true));
|
|
242
243
|
const pubkeyBaseHex = bytesToHex(pubkeyBase);
|
|
243
244
|
|
|
244
245
|
// Check if token already exists
|
|
245
|
-
const existing = await loadTrail(ticker);
|
|
246
|
+
const existing = await loadTrail(ticker, root);
|
|
246
247
|
if (existing) throw new Error(`Token ${ticker} already exists`);
|
|
247
248
|
|
|
248
249
|
// Create genesis MRC20 state
|
|
@@ -300,14 +301,14 @@ export async function mintToken({ ticker, name, supply, voucher, mempoolUrl = 'h
|
|
|
300
301
|
network,
|
|
301
302
|
dateCreated: new Date().toISOString()
|
|
302
303
|
};
|
|
303
|
-
await saveTrail(trail);
|
|
304
|
+
await saveTrail(trail, root);
|
|
304
305
|
|
|
305
306
|
return { trail, txid: newTxid, address: genesisAddr };
|
|
306
307
|
}
|
|
307
308
|
|
|
308
309
|
// --- Transfer: send tokens to an address ---
|
|
309
|
-
export async function transferToken({ ticker, from, to, amount, mempoolUrl = 'https://mempool.space/testnet4' }) {
|
|
310
|
-
const trail = await loadTrail(ticker);
|
|
310
|
+
export async function transferToken({ ticker, from, to, amount, mempoolUrl = 'https://mempool.space/testnet4', root }) {
|
|
311
|
+
const trail = await loadTrail(ticker, root);
|
|
311
312
|
if (!trail) throw new Error(`Token ${ticker} not found`);
|
|
312
313
|
|
|
313
314
|
const privkeyBytes = hexToU8(trail.privkey);
|
|
@@ -382,14 +383,14 @@ export async function transferToken({ ticker, from, to, amount, mempoolUrl = 'ht
|
|
|
382
383
|
trail.currentTxid = newTxid;
|
|
383
384
|
trail.currentVout = 0;
|
|
384
385
|
trail.currentAmount = outputAmount;
|
|
385
|
-
await saveTrail(trail);
|
|
386
|
+
await saveTrail(trail, root);
|
|
386
387
|
|
|
387
388
|
return { trail, txid: newTxid, address: newAddr, state: newState, prevState: currentState };
|
|
388
389
|
}
|
|
389
390
|
|
|
390
391
|
// --- Info: show token state ---
|
|
391
|
-
export async function tokenInfo(ticker) {
|
|
392
|
-
const trail = await loadTrail(ticker);
|
|
392
|
+
export async function tokenInfo(ticker, { root } = {}) {
|
|
393
|
+
const trail = await loadTrail(ticker, root);
|
|
393
394
|
if (!trail) throw new Error(`Token ${ticker} not found`);
|
|
394
395
|
|
|
395
396
|
const currentState = trail.states[trail.states.length - 1];
|
package/src/wac/checker.js
CHANGED
|
@@ -49,7 +49,7 @@ export async function checkAccess({
|
|
|
49
49
|
// Calculate WAC-Allow header
|
|
50
50
|
const wacAllow = calculateWacAllow(authorizations, resourceUrl, agentWebId, isDefault);
|
|
51
51
|
|
|
52
|
-
return { allowed: result.allowed, wacAllow, paymentRequired: result.paymentRequired || null };
|
|
52
|
+
return { allowed: result.allowed, wacAllow, paymentRequired: result.paymentRequired || null, paid: result.paid, balance: result.balance, currency: result.currency };
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
@@ -183,10 +183,10 @@ async function checkAuthorizations(authorizations, targetUrl, agentWebId, requir
|
|
|
183
183
|
// Paid access: check balance and deduct
|
|
184
184
|
const balance = getBalance(ledger, agentWebId, currency);
|
|
185
185
|
if (cost > 0 && balance >= cost) {
|
|
186
|
-
debit(ledger, agentWebId, cost, currency);
|
|
186
|
+
const result = debit(ledger, agentWebId, cost, currency);
|
|
187
187
|
const { writeLedger } = await import('../webledger.js');
|
|
188
188
|
await writeLedger(ledger);
|
|
189
|
-
return { allowed: true, paid: cost };
|
|
189
|
+
return { allowed: true, paid: cost, balance: result.balance, currency };
|
|
190
190
|
}
|
|
191
191
|
} catch (e) {
|
|
192
192
|
// Ledger read failed — fall through to payment required
|