@glyphteck/veyl 0.71.2 → 0.72.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/docs/api.md CHANGED
@@ -25,6 +25,8 @@ The auth and account compositions consume explicit runtime ports and have no dir
25
25
 
26
26
  Most product methods ensure login and vault unlock when saved account and vault keys are available. Long-running callers should explicitly login/unlock once and call `close()` when finished.
27
27
 
28
+ `open({ onOperation(event) })` can observe local firebase operations, default chat/presence WebSocket frame counts, and SDK wallet-claim calls. events contain operation names, lifecycle status, counts, latency, and cache/pending-write flags; they omit payloads, document paths, account/chat IDs, and capabilities. this hook observes the default adapters, not custom cloud/live ports or server internals, and its counts are not billing units. wallet-claim observations count the SDK invocation, not Spark's internal requests. see the repository's `costs/benchmarks.md` for controlled dev scenarios and provider reconciliation.
29
+
28
30
  ### Local access and connectivity
29
31
 
30
32
  The shared account owner separates `localReady`, `online`, and `connection` in its snapshot. `localReady` means the exact locally signed-in account has enough encrypted bootstrap data for vault unlock; it is not server authorization. Unlock opens encrypted cached chats and wallet history without waiting for cloud services. Cached balance is display-only and must be labeled last known. `online` becomes true after cloud reads and online proof succeed; reconnect attaches services to the same unlocked session. Text sends wait up to 30 seconds for connectivity, then remain encrypted on-device as failed attempts for manual retry; reactions expire without a retry row. Avatar changes wait only for the current session, as described below. These are domain-owned pending operations, not a general cloud mutation queue. Live wallet readiness remains mandatory for payments.
@@ -174,7 +176,7 @@ await account.close();
174
176
 
175
177
  `account.peers` is the shared peer-directory owner used by Node, web, and iOS. `openAccount()` supplies its chat, wallet, blocked-user, and encrypted-cache sources directly, including missing-profile chat cleanup. Graphical adapters only subscribe to the same snapshot and profile selectors already defined by core. `openSearch('profiles')` creates profile-only search; web may also use `openSearch('mainmenu')` for its combined local-action and remote-profile menu. Active searches track peer and blocked-user changes and release those subscriptions when cleared or closed.
176
178
 
177
- `account.chat` is the one account-scoped protocol-v3 chat owner used by Node, web, and iOS. It owns notes/direct/group creation, stable logical chat IDs, membership epochs, encrypted list/inbox convergence, epoch-spanning history, delivery, messages, receipts, signed encrypted chat settings, member changes, leaving, and deletion. It clears every route, cache, timer, and key-bearing state on lock/account switch. Graphical providers only expose this owner through React; platform media preparation and native behavior enter through explicit ports.
179
+ `account.chat` is the one account-scoped protocol-4 chat owner used by Node, web, and iOS. It owns notes/direct/group creation, stable logical chat IDs, membership epochs, encrypted list/inbox convergence, epoch-spanning history, delivery, messages, receipts, signed encrypted chat settings, member changes, leaving, and deletion. It clears every route, cache, timer, and key-bearing state on lock/account switch. Graphical providers only expose this owner through React; platform media preparation and native behavior enter through explicit ports.
178
180
 
179
181
  `account.wallet` is the stable account-scoped wallet composition used by Node, web, and iOS. It owns the one live `core/wallet/session.js` engine, its transfer store, cached pre-Spark display state, transaction aggregation, wallet-derived peer recency, late Spark attachment, and lock teardown. `getSnapshot()` preserves the shared `{ value, txValue }` contract; `transactions` exposes aggregate/search/chart data and `transfers` exposes focused list and keyed subscriptions. Graphical wallet providers only adapt those SDK subscriptions and add browser/native behavior through the `wallet` platform ports.
180
182
 
@@ -391,11 +393,15 @@ await veyl.chat.sendAttachment('@alice', {
391
393
  });
392
394
 
393
395
  await veyl.chat.sendAttachmentMany(['@alice', '@bob'], attachment);
394
- await veyl.chat.share('@alice', messageId, ['@bob']);
396
+ await veyl.chat.forward('@alice', messageId, ['@bob']);
395
397
  const downloaded = await veyl.chat.readAttachment('@alice', messageId);
396
398
  ```
397
399
 
398
- The caller supplies/consumes bytes; shared owners still derive paths, encrypt/decrypt, upload/download, create message actions, and project media cache state.
400
+ the caller supplies/consumes bytes; shared owners derive paths, encrypt/decrypt, upload/download, create message actions, and project media cache state. `chat.forward` forwards an existing attachment. forwarded attachments cannot be saved forever, and forwarding reuses the original encrypted object without extending its expiry or transmitting management authority. participants in the original conversation keep the existing save/unsave authority.
401
+
402
+ audio attachment objects may include `duration` in fractional seconds and optional `waveform`: canonical padded base64 encoding of 32 unsigned bytes, representing peak-normalized rms amplitude in equal-duration bins. compact audio events expose the same validated `message.waveform`, and sharing/echoing should preserve it. generic sdk/cli uploads do not decode audio to generate it; the command schema does not accept it, and graphical clients display a stable generic waveform when it is absent. that placeholder is presentation-only and is never attached to a message as measured audio. real waveform data stays inside the encrypted message.
403
+
404
+ media metadata is removed automatically before encryption, including when recognizable media is sent as a generic file. supply prepared jpeg, png, webp, gif, or supported mp4/mov/m4a bytes; video must use h.264 or hevc. normalize other image/video formats first. raw heic/avif/webm, unsupported movie tracks/codecs, and malformed media reject with `media-sanitization-failed` instead of uploading the original. orientation, color transforms, animation timing, audio/video synchronization, and display matrices are retained. this does not scrub ordinary documents, visible/audible content, or authored filenames/captions. public `account.profile.setAvatar` also sanitizes prepared webp bytes before publishing.
399
405
 
400
406
  ## Invites
401
407
 
package/docs/cli.md CHANGED
@@ -117,7 +117,7 @@ Attachments use filesystem paths in the CLI while the shared owners still perfor
117
117
  ```bash
118
118
  veyl chat send-file @alice ./photo.webp --mime image/webp --caption "caption"
119
119
  veyl chat send-file-many @alice,@bob ./document.pdf --name document.pdf
120
- veyl chat share @alice MESSAGE_ID @bob,@carol
120
+ veyl chat forward @alice MESSAGE_ID @bob,@carol
121
121
  veyl chat download @alice MESSAGE_ID ./downloaded-file
122
122
  ```
123
123
 
@@ -169,15 +169,7 @@ Cold one-off commands are inherently inefficient for agent loops because Spark b
169
169
 
170
170
  ## Server-operation cost shape
171
171
 
172
- The executable source is `costs/model.mjs`.
173
-
174
- Protocol v3 separates constant content cost from recipient availability cost. One visible action commits one ciphertext, one logical-chat budget update, and at most one coalesced sender owner row: 6 planning reads and 3 writes independent of group size. Each accepted recipient wake adds two route/slot reads, one minimum push-route query when APNs is due, one overwritten slot write, and one Function invocation. The default one-edge/direct upper bound is therefore 9 reads, 4 writes, and 1 invocation. Read receipts add one shared 6-read/2-write action with no wake.
175
-
176
- The current one-edge planning bundle is about 542 Firestore read-equivalent operations, 163 writes, 28 Function invocations, and one Storage Class A operation per active user/day. Headline projections are about `$2,519/month` at 100k DAU and `$25,217/month` at 1M DAU. At a sustained one visible send per second, the model is `$33.70` gross per month, or `$52.36` with one receipt per send. Set `MESSAGE_RECIPIENT_EDGES` to model larger groups; sender, wake-slot, and APNs coalescing reduce the isolated-send upper bound.
177
-
178
- Earlier live Cloud Run measurements covered the retired direct-chat delivery contract and must not be treated as v3 evidence. Current source uses anonymous opaque capability delivery, a recipient-owned overwritten slot, prompt-plus-trailing sender burst coalescing, a 250 ms slot debounce, and a 2 s APNs debounce. Dev traces must establish the real accepted-wake ratio before production projections are tightened.
179
-
180
- These totals intentionally exclude Function CPU/memory duration, outbound network, APNS delivery, Spark/vendor/network fees, media download bytes, and moderation labor until real rates are measured.
172
+ the repository's `costs/README.md` owns cost documentation, `costs/model.mjs` owns the partial workload calculation, and `costs/dau-scale.md` contains generated projections. packaged SDK validation deliberately does not duplicate their prices or operation coefficients. source-level behavior and dated runtime samples do not establish current billing.
181
173
 
182
174
  The live L1 path confirmed that withdrawal, confirmed-UTXO discovery, claim, balance, and transfer status do not call a Veyl wallet Function or write wallet state to Firestore. They are client-local Spark SDK operations against Spark/network services. Active unlocked wallets currently run one identity-scoped deposit check every 20 seconds on REGTEST or every minute on MAINNET; a pending cooperative exit adds one exact-transfer Spark check at most every 15 seconds for ten minutes. Neither cadence is a Firebase cost. The sample consumed 2,190 sats for cooperative exit and 99 sats for the static claim, while all 3,711 recoverable sats were returned to the faucet.
183
175
 
@@ -12,7 +12,7 @@ const BOT_UNDERFUNDED_TEXT = 'insufficient funds';
12
12
  const ATTACHMENT_TYPES = new Set(['img', 'gif', 'm4a', 'mp4', 'file']);
13
13
  const NORMAL_CLAIM_INTERVAL_MS = 5 * 60_000;
14
14
  const FAUCET_CLAIM_INTERVAL_MS = 30_000;
15
- const MAX_CLAIM_BACKOFF_MS = 2 * 60_000;
15
+ const MAX_CLAIM_BACKOFF_MS = 30 * 60_000;
16
16
  const TYPING_HEARTBEAT_MS = 2_000;
17
17
 
18
18
  function rolesFor(account) {
@@ -236,6 +236,9 @@ async function mirrorAttachment(account, client, event) {
236
236
  height: event.message.height || payload.h,
237
237
  duration: event.message.duration || payload.d,
238
238
  audio: typeof event.message.audio === 'boolean' ? event.message.audio : payload.audio,
239
+ ...(event.message.type === 'm4a' && event.message.waveform
240
+ ? { waveform: event.message.waveform }
241
+ : {}),
239
242
  }, {
240
243
  cid: botActionCid(event, 'echo', account),
241
244
  });
package/package.json CHANGED
@@ -53,5 +53,5 @@
53
53
  "start": "node src/cli.js",
54
54
  "lint": "eslint src --quiet"
55
55
  },
56
- "version": "0.71.2"
56
+ "version": "0.72.0"
57
57
  }