@glyphteck/veyl 0.75.1 → 0.77.0
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/dist/account.js +2274 -848
- package/dist/accountprofiles.js +6 -0
- package/dist/auth.js +159 -3
- package/dist/cli.js +2594 -1171
- package/dist/index.js +2594 -1171
- package/docs/api.md +38 -17
- package/docs/cli.md +3 -4
- package/docs/validation.md +3 -3
- package/examples/bot-fleet/policy.js +17 -5
- package/package.json +1 -1
package/docs/api.md
CHANGED
|
@@ -46,16 +46,12 @@ const auth = openAuth({
|
|
|
46
46
|
cloud,
|
|
47
47
|
origin: () => window.location.origin,
|
|
48
48
|
ceremony: {
|
|
49
|
-
create:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
await navigator.credentials.get({
|
|
56
|
-
publicKey: decodePublicKeyOptions(options),
|
|
57
|
-
}),
|
|
58
|
-
),
|
|
49
|
+
create: (options) => navigator.credentials.create({
|
|
50
|
+
publicKey: decodePublicKeyOptions(options),
|
|
51
|
+
}),
|
|
52
|
+
get: (options) => navigator.credentials.get({
|
|
53
|
+
publicKey: decodePublicKeyOptions(options),
|
|
54
|
+
}),
|
|
59
55
|
},
|
|
60
56
|
});
|
|
61
57
|
|
|
@@ -78,7 +74,7 @@ unsubscribeAuth();
|
|
|
78
74
|
await auth.logout();
|
|
79
75
|
```
|
|
80
76
|
|
|
81
|
-
`openAuth()` owns the shared register, login, token, one-use link, passkey inventory, verified deletion, session observation, and sign-out choreography. `activateToken()` is the generic in-memory account-session activation boundary for a custom token returned by a token-only login, registration, or passkey-link flow; it is not nested under passkey links because those flows share the same isolated auth-slot operation. Never persist that token. The `cloud` input is a transport rather than a Firebase dependency. A platform supplies only the local credential ceremony: browser WebAuthn on web, `react-native-passkeys` on iOS, or a browser-assisted port in the Node runtime.
|
|
77
|
+
`openAuth()` owns the shared register, login, token, one-use link, passkey inventory, verified deletion, session observation, and sign-out choreography. `activateToken()` is the generic in-memory account-session activation boundary for a custom token returned by a token-only login, registration, or passkey-link flow; it is not nested under passkey links because those flows share the same isolated auth-slot operation. Never persist that token. The `cloud` input is a transport rather than a Firebase dependency. A platform supplies only the local credential ceremony: browser WebAuthn on web, `react-native-passkeys` on iOS, or a browser-assisted port in the Node runtime. browser adapters decode binary options and return the native credential object; ios returns its library's credential json. the shared owner extracts an explicit allowlist of authentication proof fields before any transport call. never serialize a raw browser credential with `toJSON()` or `JSON.stringify()`: extension results can contain encryption secrets. Errors are normalized at this boundary so every client receives the same recoverable registration and login outcomes. The platform still owns when to prompt, how to present the prompt, navigation, local credential storage, and UI feedback.
|
|
82
78
|
|
|
83
79
|
## Account profiles
|
|
84
80
|
|
|
@@ -140,8 +136,7 @@ const publicRequest = await account.payment.createRequest({ amountSats: 1250 });
|
|
|
140
136
|
console.log(publicRequest.link);
|
|
141
137
|
await account.profile.clearAvatar();
|
|
142
138
|
|
|
143
|
-
await account.support.
|
|
144
|
-
type: 'other',
|
|
139
|
+
await account.support.submit('message', {
|
|
145
140
|
platform: 'web',
|
|
146
141
|
route: '/settings',
|
|
147
142
|
appVersion,
|
|
@@ -414,7 +409,9 @@ const parsed = veyl.invite.read(created.link);
|
|
|
414
409
|
|
|
415
410
|
## Wallet
|
|
416
411
|
|
|
417
|
-
|
|
412
|
+
bitcoin amounts are integer sats. `send` and `request` also accept an exact integer string or bigint of token base units when `tokenIdentifier` is supplied. the network-specific asset registry validates the identifier, issuer, and decimals; token values are never converted through btc or a floating-point number.
|
|
413
|
+
|
|
414
|
+
structured `wallet_send` and `wallet_request` commands use `{ peer, amount, tokenIdentifier? }`, with `amount` as an integer string. `wallet_pay_request` derives the asset and full amount from the request.
|
|
418
415
|
|
|
419
416
|
```js
|
|
420
417
|
await veyl.wallet.balance();
|
|
@@ -436,6 +433,27 @@ await veyl.wallet.search('@alice', { count: 50 });
|
|
|
436
433
|
|
|
437
434
|
Wallet boot, signing, balance, transaction aggregation, peer attribution, claim, payment-request validation, and wallet mutation serialization are shared. `raw: true` adds JSON-safe SDK detail only where supported.
|
|
438
435
|
|
|
436
|
+
the regtest prototype asset is usd veyl (`USDV`), with six decimals and a fixed test valuation of exactly one usd per token. the one-million-token supply is held by `@faucet`. no mainnet stablecoin is enabled.
|
|
437
|
+
|
|
438
|
+
```js
|
|
439
|
+
const balance = await veyl.wallet.balance();
|
|
440
|
+
const usdv = balance.tokens.find(asset => asset.ticker === 'USDV');
|
|
441
|
+
// the registry has already verified this record; use its identifier for actions.
|
|
442
|
+
const request = await veyl.wallet.request('@faucet', '1250000', {
|
|
443
|
+
tokenIdentifier: usdv.tokenIdentifier, // 1.25 usdv, expressed in base units
|
|
444
|
+
});
|
|
445
|
+
await veyl.wallet.send('@alice', '1000000', { tokenIdentifier: usdv.tokenIdentifier });
|
|
446
|
+
const page = await veyl.wallet.transactions({ tokenIdentifier: usdv.tokenIdentifier, count: 50 });
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`balance.tokens` reports `ownedUnits`, `availableUnits`, `unavailableUnits`, formatted `amount`, `usdPrice`, and `usdValue`. null quantities mean unavailable rather than zero; inspect `tokenBalancesReady` and `tokenBalanceError`. only usdv has the fixed test valuation. values have no mainnet backing or redemption rights.
|
|
450
|
+
|
|
451
|
+
token history uses `cursor` and `direction` (`PREVIOUS` for newest-first pages), returning `{ transfers, page }`; it rejects btc-style offsets. rows carry exact `amountUnits`, asset, direction, status, timestamp, and counterparties. the recent page is encrypted in the existing vault cache and scoped to wallet identity/network. token amounts are excluded from btc-only charts and aggregates. pay a token request with the ordinary `wallet.pay(requestId)` command; its encrypted asset identity determines which balance is spent and must match the confirmation.
|
|
452
|
+
|
|
453
|
+
token requests use message type `tokenreq`, and their encrypted settlement actions use `tokenreqpay`. bitcoin retains `req` and `reqpay`. sdk token request events carry `tokenIdentifier`, `amountUnits`, `paidAmountUnits`, and `remainingAmountUnits` without an `amountSats` field. ios `0.76.0 (26)` ignores the new token message types; its bitcoin wallet remains usable, but it cannot display or pay token requests. never place token base units in a bitcoin request payload.
|
|
454
|
+
|
|
455
|
+
the current request renderer and payment review preserve token identity on web and ios. the web cash selector chooses the payment asset independently of display currency: showing a token amount in btc never authorizes spending bitcoin. token invoices/qr and stablecoin swaps remain separate product work. the approved ios build's limitations are described above.
|
|
456
|
+
|
|
439
457
|
## Lightning and withdrawal
|
|
440
458
|
|
|
441
459
|
```js
|
|
@@ -473,12 +491,15 @@ Rows combine pending links and verified passkeys, mark the passkey currently aut
|
|
|
473
491
|
## Support
|
|
474
492
|
|
|
475
493
|
```js
|
|
476
|
-
await veyl.support.
|
|
477
|
-
|
|
494
|
+
const ticket = await veyl.support.submit('description', {
|
|
495
|
+
id: 'stable_submission_id', // reuse this id for retries of the same draft
|
|
496
|
+
attachments: [{ name: 'screenshot.png', mimeType: 'image/png', bytes }],
|
|
497
|
+
});
|
|
498
|
+
console.log(ticket.id);
|
|
478
499
|
await veyl.support.report('@alice', { messageId, note: 'context' });
|
|
479
500
|
```
|
|
480
501
|
|
|
481
|
-
|
|
502
|
+
Support submissions use the same ticket owner as web/iOS. The agent classifies them after submission. A ticket accepts up to 4,000 characters and three files of up to 5 MiB each (PNG, JPEG, WebP, GIF, PDF or UTF-8 text). Attachments are deliberately shared with the operator for support. Abuse reports separately use account-scoped encrypted-message lookup, report metadata and evidence reservation. When `messageId` selects an attachment, the runtime reads and uploads the attachment as report evidence before submitting because attachment reports are invalid without their evidence path. Automated tests should not submit fake reports or support messages to shared environments.
|
|
482
503
|
|
|
483
504
|
## Live events
|
|
484
505
|
|
package/docs/cli.md
CHANGED
|
@@ -135,8 +135,8 @@ Amounts are integer sats.
|
|
|
135
135
|
veyl wallet balance
|
|
136
136
|
veyl wallet address
|
|
137
137
|
veyl wallet claim [--count 100]
|
|
138
|
-
veyl wallet send @alice 10 [--operation-id AGENT_JOB_ID]
|
|
139
|
-
veyl wallet request @alice 10
|
|
138
|
+
veyl wallet send @alice 10 [--operation-id AGENT_JOB_ID] [--token-identifier id]
|
|
139
|
+
veyl wallet request @alice 10 [--token-identifier id]
|
|
140
140
|
veyl wallet pay-request REQUEST_ID [--operation-id AGENT_JOB_ID]
|
|
141
141
|
veyl wallet pay-invoice INVOICE [--amount SATS] [--operation-id AGENT_JOB_ID]
|
|
142
142
|
veyl wallet transactions [--count 50] [--offset 0]
|
|
@@ -179,8 +179,7 @@ veyl passkeys list
|
|
|
179
179
|
veyl passkeys link [--web-url ORIGIN]
|
|
180
180
|
veyl passkeys delete ID [--web-url ORIGIN]
|
|
181
181
|
|
|
182
|
-
veyl support
|
|
183
|
-
veyl support bug "message"
|
|
182
|
+
veyl support submit "message"
|
|
184
183
|
veyl support report @alice [MESSAGE_ID] [--note TEXT] [--no-attachment]
|
|
185
184
|
```
|
|
186
185
|
|
package/docs/validation.md
CHANGED
|
@@ -18,7 +18,7 @@ The Node SDK composes the same framework-free owners as web and iOS:
|
|
|
18
18
|
| Public invites | `core/invite.js` | direct Veyl URL strings |
|
|
19
19
|
| Passkeys | shared passkey eligibility and normal backend link/passkey owners | browser URL for WebAuthn verification |
|
|
20
20
|
| Settings/cache | shared settings normalization and vault-encrypted cache | JSON patches and byte counts |
|
|
21
|
-
| Support | shared
|
|
21
|
+
| Support | shared ticket, report, and evidence builders | terminal text and existing message attachment |
|
|
22
22
|
|
|
23
23
|
The obsolete direct-cloud `createAccountSessionActions` implementation was removed during this pass. There is now one live product path: the SDK adapts inputs around the same chat, wallet, peer, user, vault, cache, search, and cloud owners used by the interactive clients.
|
|
24
24
|
|
|
@@ -51,7 +51,7 @@ API version 4 keeps `open()` as the public SDK composition root and adds stable-
|
|
|
51
51
|
| Withdrawal | 3 / 3 | shared wallet session, fee normalization, and generic payment-intent/L1 review owner |
|
|
52
52
|
| Invite | 2 / 2 | `core/invite.js`; direct URL strings only |
|
|
53
53
|
| Passkeys | 3 / 2 | shared passkey eligibility plus the normal cloud passkey owners; bearer-link creation is one-shot only and WebAuthn stays browser-assisted |
|
|
54
|
-
| Support |
|
|
54
|
+
| Support | 2 / 2 | shared ticket, report, message lookup, and evidence builders |
|
|
55
55
|
| Session | 4 / 0 | local process/socket lifecycle around the same account runtime |
|
|
56
56
|
| Docs | 1 / 0 | local stdio MCP exposing allowlisted packaged Markdown resources only |
|
|
57
57
|
|
|
@@ -76,7 +76,7 @@ API version 4 keeps `open()` as the public SDK composition root and adds stable-
|
|
|
76
76
|
| Withdrawal quote/prepare/confirm | yes | a live 3,000-sat cooperative exit paid a 2,190-sat medium fee and funded the receiver's static address with 810 sats; the run exposed and fixed CLI re-quoting at confirm, and post-fee dust now rejects before spend |
|
|
77
77
|
| Invite create/read | yes | all four shared invite kinds round-trip as direct URL strings; invalid kinds and amounts reject |
|
|
78
78
|
| Passkey list/link/delete | yes | pending link create/delete exercised; list marks current credential and shared deletion eligibility |
|
|
79
|
-
|
|
|
79
|
+
| Tickets/reports | yes | report-without-evidence succeeded live; ticket submission and reporting share one SDK account owner and remaining cross-client checks are in the root manual queue |
|
|
80
80
|
| Docs discovery | yes | focused tests prove the stdio MCP advertises only documentation resources, reads only allowlisted packaged Markdown, and rejects action tool calls without loading a Veyl client |
|
|
81
81
|
|
|
82
82
|
## Edge cases exercised
|
|
@@ -99,6 +99,10 @@ function isFleetGeneratedMessage(event) {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
function requestAmount(event) {
|
|
102
|
+
if (event?.message?.tokenIdentifier != null) {
|
|
103
|
+
tokenAsset(event.message.tokenIdentifier, event.message.network);
|
|
104
|
+
return tokenUnits(event.message.amountUnits).toString();
|
|
105
|
+
}
|
|
102
106
|
const amount = Number(event?.message?.amountSats);
|
|
103
107
|
return Number.isSafeInteger(amount) && amount > 0 ? amount : null;
|
|
104
108
|
}
|
|
@@ -215,7 +219,9 @@ async function sendUnderfunded(
|
|
|
215
219
|
() => sendToEventChat(
|
|
216
220
|
client,
|
|
217
221
|
event,
|
|
218
|
-
|
|
222
|
+
event.message.tokenIdentifier
|
|
223
|
+
? `i only have ${formatTokenAmount(String(availableSats), tokenAsset(event.message.tokenIdentifier, event.message.network))} ${tokenAsset(event.message.tokenIdentifier, event.message.network).ticker.toLowerCase()}`
|
|
224
|
+
: `i only have ${availableSats} sats`,
|
|
219
225
|
{ cid: botActionCid(event, 'funds-balance', account) }
|
|
220
226
|
)
|
|
221
227
|
);
|
|
@@ -267,7 +273,7 @@ async function mirrorEcho(journal, account, client, event) {
|
|
|
267
273
|
() => mirrorReaction(account, client, event)
|
|
268
274
|
);
|
|
269
275
|
}
|
|
270
|
-
if (event.message.type
|
|
276
|
+
if (['req', 'tokenreq'].includes(event.message.type)) {
|
|
271
277
|
if (event.chat?.lineage && event.chat.lineage !== 'direct') return null;
|
|
272
278
|
const amountSats = requestAmount(event);
|
|
273
279
|
if (!amountSats) return null;
|
|
@@ -279,6 +285,7 @@ async function mirrorEcho(journal, account, client, event) {
|
|
|
279
285
|
{ replaySafe: true },
|
|
280
286
|
() => client.wallet.request(event.peer, amountSats, {
|
|
281
287
|
cid: botActionCid(event, 'echo-request', account),
|
|
288
|
+
tokenIdentifier: event.message.tokenIdentifier,
|
|
282
289
|
})
|
|
283
290
|
);
|
|
284
291
|
}
|
|
@@ -335,13 +342,16 @@ async function serveFaucet(journal, account, client, event) {
|
|
|
335
342
|
);
|
|
336
343
|
}
|
|
337
344
|
const balance = await client.wallet.balance();
|
|
338
|
-
|
|
345
|
+
const tokenBalance = event.message.tokenIdentifier ? balance.tokens?.find((asset) => asset.tokenIdentifier === event.message.tokenIdentifier) : null;
|
|
346
|
+
if (event.message.tokenIdentifier && (balance.tokenBalancesReady !== true || tokenBalance?.availableUnits == null)) throw new Error('faucet token balance unavailable');
|
|
347
|
+
const available = event.message.tokenIdentifier ? tokenUnits(tokenBalance.availableUnits, { allowZero: true }) : BigInt(balance.availableSats);
|
|
348
|
+
if (available < BigInt(amountSats)) {
|
|
339
349
|
await sendUnderfunded(
|
|
340
350
|
journal,
|
|
341
351
|
account,
|
|
342
352
|
client,
|
|
343
353
|
event,
|
|
344
|
-
|
|
354
|
+
available.toString()
|
|
345
355
|
);
|
|
346
356
|
return { paid: false, reason: 'insufficient-funds' };
|
|
347
357
|
}
|
|
@@ -368,6 +378,7 @@ async function serveFaucet(journal, account, client, event) {
|
|
|
368
378
|
{ replaySafe: true },
|
|
369
379
|
() => client.wallet.request(event.peer, amountSats, {
|
|
370
380
|
cid: botActionCid(event, 'faucet-request', account),
|
|
381
|
+
tokenIdentifier: event.message.tokenIdentifier,
|
|
371
382
|
})
|
|
372
383
|
);
|
|
373
384
|
return { paid: true, payment: paid };
|
|
@@ -664,7 +675,7 @@ export function createBotFleetPolicy(options = {}) {
|
|
|
664
675
|
) {
|
|
665
676
|
if (
|
|
666
677
|
roles.has('faucet') &&
|
|
667
|
-
event.message.type
|
|
678
|
+
['req', 'tokenreq'].includes(event.message.type)
|
|
668
679
|
) {
|
|
669
680
|
result = await serveFaucet(
|
|
670
681
|
journal,
|
|
@@ -689,3 +700,4 @@ export function createBotFleetPolicy(options = {}) {
|
|
|
689
700
|
},
|
|
690
701
|
});
|
|
691
702
|
}
|
|
703
|
+
import { formatTokenAmount, tokenAsset, tokenUnits } from '@veyl/core/wallet/assets';
|
package/package.json
CHANGED