@toon-protocol/rig 2.14.0 → 3.0.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/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { c as GitObjectType, P as Publisher, F as FeeRates, b as PublishReceipt } from './publisher-ftQeZSib.js';
2
- export { C as COMMENT_KIND, d as GitObject, G as GitObjectUpload, M as MAINTAINERS_TAG, e as MAX_OBJECT_SIZE, R as REPOSITORY_STATE_KIND, S as StatusKind, U as UnsignedEvent, a as UploadReceipt, f as authorizedStatusAuthors, g as buildComment, h as buildIssue, i as buildPatch, j as buildRepoAnnouncement, k as buildRepoRefs, l as buildStatus, m as createGitBlob, n as createGitCommit, o as createGitTag, p as createGitTree, q as flooredUploadFee, r as hashGitObject, s as parseMaintainers } from './publisher-ftQeZSib.js';
1
+ import { c as GitObjectType, P as Publisher, F as FeeRates, b as PublishReceipt } from './publisher-BFcnZeJI.js';
2
+ export { C as COMMENT_KIND, d as GitObject, G as GitObjectUpload, M as MAINTAINERS_TAG, e as MAX_OBJECT_SIZE, R as REPOSITORY_STATE_KIND, S as StatusKind, U as UnsignedEvent, a as UploadReceipt, f as authorizedStatusAuthors, g as buildComment, h as buildIssue, i as buildPatch, j as buildRepoAnnouncement, k as buildRepoRefs, l as buildStatus, m as createGitBlob, n as createGitCommit, o as createGitTag, p as createGitTree, q as hashGitObject, r as parseMaintainers } from './publisher-BFcnZeJI.js';
3
3
  import '@toon-protocol/core/nip34';
4
4
 
5
5
  /**
@@ -659,7 +659,7 @@ interface PushFeeEstimate {
659
659
  objectCount: number;
660
660
  /** Total bytes across all planned object bodies. */
661
661
  totalObjectBytes: number;
662
- /** Σ max(size × uploadFeePerByte, minUploadFee) — smallest asset unit. */
662
+ /** objectCount × the store route's flat price — smallest asset unit. */
663
663
  uploadFee: bigint;
664
664
  /** Number of events to publish (refs event + announcement on first push). */
665
665
  eventCount: number;
@@ -853,7 +853,7 @@ interface GitEstimateRequest {
853
853
  interface GitFeeEstimate {
854
854
  objectCount: number;
855
855
  totalObjectBytes: number;
856
- /** Σ max(size × uploadFeePerByte, per-upload route-price floor). */
856
+ /** objectCount × the store route's flat price. */
857
857
  uploadFee: string;
858
858
  /** Events to publish (refs event + announcement on first push). */
859
859
  eventCount: number;
package/dist/index.js CHANGED
@@ -27,16 +27,15 @@ import {
27
27
  walkClosure,
28
28
  writeGitObject,
29
29
  writeGitObjects
30
- } from "./chunk-EEUHZNWS.js";
30
+ } from "./chunk-FBIHO3RS.js";
31
31
  import {
32
32
  MAX_OBJECT_SIZE,
33
33
  createGitBlob,
34
34
  createGitCommit,
35
35
  createGitTag,
36
36
  createGitTree,
37
- flooredUploadFee,
38
37
  hashGitObject
39
- } from "./chunk-35ALWUDJ.js";
38
+ } from "./chunk-B5ISARMU.js";
40
39
  import {
41
40
  COMMENT_KIND,
42
41
  MAINTAINERS_TAG,
@@ -80,7 +79,6 @@ export {
80
79
  executePush,
81
80
  fetchRemoteState,
82
81
  fetchTxBytes,
83
- flooredUploadFee,
84
82
  hashGitObject,
85
83
  hexToNpub,
86
84
  isSafeRefname,
@@ -281,33 +281,32 @@ interface PublishReceipt {
281
281
  /** Fee paid for this publish, in the smallest asset unit. */
282
282
  feePaid: bigint;
283
283
  }
284
- /** Fee rates used by `planPush` for the pre-push estimate. */
284
+ /**
285
+ * Fee rates used by `planPush` for the pre-push estimate.
286
+ *
287
+ * Both figures are FLAT per packet. ADR 0020 (toon-client#452) removed
288
+ * byte-proportional pricing from the protocol: one handler, one price, and an
289
+ * app that wants to charge differently exposes more handlers. A 100-byte and
290
+ * a 100 KB upload to the same store route now cost the same, and the
291
+ * connector charges accordingly regardless of what a client computes — so
292
+ * there is no `uploadFeePerByte` to multiply and no floor to apply, because
293
+ * the route's price is the whole fee rather than a lower bound on one.
294
+ */
285
295
  interface FeeRates {
286
- /** Upload cost per body byte (smallest asset unit). */
287
- uploadFeePerByte: bigint;
296
+ /**
297
+ * Flat cost per git-object/blob upload (smallest asset unit): the store
298
+ * destination's route price, as reported by the terminating connector's
299
+ * `GET /ilp/routes/price`. The connector gates every paid packet at that
300
+ * price, so an estimate built from it is exactly what a push pays.
301
+ */
302
+ uploadFee: bigint;
288
303
  /**
289
304
  * Flat cost per published event (smallest asset unit). Implementations
290
305
  * already fold any per-packet route-price floor into this flat value, so
291
306
  * estimates using it match the claims actually signed.
292
307
  */
293
308
  eventFee: bigint;
294
- /**
295
- * FLAT minimum per upload claim (smallest asset unit): the store
296
- * destination's announced route price. The connector gates every paid
297
- * packet at the destination route's price — a balance-proof claim
298
- * advancing the channel by less is rejected (F06) — so each per-upload fee
299
- * is `max(bytes × uploadFeePerByte, minUploadFee)`. Absent: no floor
300
- * (pre-floor behavior, e.g. when the peer announces no capability prices).
301
- */
302
- minUploadFee?: bigint;
303
309
  }
304
- /**
305
- * Per-upload fee: `bytes × ratePerByte`, floored at `minFee` (the
306
- * destination's announced flat route price — see
307
- * {@link FeeRates.minUploadFee}). The single shared implementation keeps
308
- * every estimate site equal to what the publisher actually claims.
309
- */
310
- declare function flooredUploadFee(bytes: number, ratePerByte: bigint, minFee?: bigint): bigint;
311
310
  /**
312
311
  * Paid transport for `executePush` — implemented by the daemon route
313
312
  * handlers (#227) and the standalone embedded client (#228).
@@ -336,4 +335,4 @@ interface Publisher {
336
335
  publishEvent(event: UnsignedEvent, relayUrls: string[]): Promise<PublishReceipt>;
337
336
  }
338
337
 
339
- export { type BlobUpload as B, COMMENT_KIND as C, type FeeRates as F, type GitObjectUpload as G, MAINTAINERS_TAG as M, type Publisher as P, REPOSITORY_STATE_KIND as R, type StatusKind as S, type UnsignedEvent as U, type UploadReceipt as a, type PublishReceipt as b, type GitObjectType as c, type GitObject as d, MAX_OBJECT_SIZE as e, authorizedStatusAuthors as f, buildComment as g, buildIssue as h, buildPatch as i, buildRepoAnnouncement as j, buildRepoRefs as k, buildStatus as l, createGitBlob as m, createGitCommit as n, createGitTag as o, createGitTree as p, flooredUploadFee as q, hashGitObject as r, parseMaintainers as s };
338
+ export { type BlobUpload as B, COMMENT_KIND as C, type FeeRates as F, type GitObjectUpload as G, MAINTAINERS_TAG as M, type Publisher as P, REPOSITORY_STATE_KIND as R, type StatusKind as S, type UnsignedEvent as U, type UploadReceipt as a, type PublishReceipt as b, type GitObjectType as c, type GitObject as d, MAX_OBJECT_SIZE as e, authorizedStatusAuthors as f, buildComment as g, buildIssue as h, buildPatch as i, buildRepoAnnouncement as j, buildRepoRefs as k, buildStatus as l, createGitBlob as m, createGitCommit as n, createGitTag as o, createGitTree as p, hashGitObject as q, parseMaintainers as r };
@@ -1,5 +1,6 @@
1
1
  import { ToonClientConfig, SignedBalanceProof, PublishEventResult } from '@toon-protocol/client';
2
- import { U as UnsignedEvent, P as Publisher, F as FeeRates, G as GitObjectUpload, a as UploadReceipt, B as BlobUpload, b as PublishReceipt } from '../publisher-ftQeZSib.js';
2
+ export { extractArweaveTxId } from '@toon-protocol/client';
3
+ import { U as UnsignedEvent, P as Publisher, F as FeeRates, G as GitObjectUpload, a as UploadReceipt, B as BlobUpload, b as PublishReceipt } from '../publisher-BFcnZeJI.js';
3
4
  import '@toon-protocol/core/nip34';
4
5
 
5
6
  /**
@@ -412,17 +413,21 @@ interface StandalonePublisherOptions {
412
413
  channelDestination?: string;
413
414
  /** Flat fee per published event (daemon `feePerEvent` convention). Default 1n. */
414
415
  eventFee?: bigint;
415
- /** Upload fee per object body byte (seed pipeline's bid rate). Default 10n. */
416
- uploadFeePerByte?: bigint;
417
- /**
418
- * FLAT per-packet route prices the payment peer announces for the
419
- * publish/store destinations (kind:10032 `capabilities` — e.g.
420
- * `{capability:'os.publish', address:'g.proxy.relay', price:'1000'}`).
421
- * The connector gates every paid packet at the destination route's price:
422
- * a balance-proof claim advancing the channel by less is rejected (F06).
423
- * Applied as a FLOOR on the computed per-packet fee — `publish` floors
424
- * event claims, `store` floors upload claims. A destination without a
425
- * known price keeps the computed fee unchanged (pre-floor behavior).
416
+ /**
417
+ * FLAT per-packet route prices for the publish/store destinations, as the
418
+ * payment peer announces them (kind:10032 `capabilities` — e.g.
419
+ * `{capability:'os.publish', address:'g.proxy.relay', price:'1000'}`) or as
420
+ * the terminating connector reports them from `GET /ilp/routes/price`.
421
+ *
422
+ * The connector gates every paid packet at the destination route's price: a
423
+ * balance-proof claim advancing the channel by less is rejected (F06). Since
424
+ * ADR 0020 (toon-client#452) a price is flat per handler, so `store` is the
425
+ * WHOLE upload fee rather than a floor under a per-byte computation — an
426
+ * upload of any size costs it. `publish` still floors {@link eventFee},
427
+ * which remains a caller-chosen flat figure.
428
+ *
429
+ * A destination without a known price prices its packets at 0 here and lets
430
+ * the connector be the one to refuse — this class never invents a rate.
426
431
  */
427
432
  routePrices?: {
428
433
  publish?: bigint;
@@ -479,15 +484,7 @@ declare function deriveRouteDestinations(anchor: string): {
479
484
  publish: string;
480
485
  store: string;
481
486
  };
482
- /**
483
- * Decode the Arweave txId from a store-write FULFILL. The deployed payment
484
- * proxy returns the store's verbatim HTTP/1.1 response
485
- * (`{"accept":true,"txId":…}` body); legacy non-proxy providers return bare
486
- * `base64(utf8(txId))`.
487
- *
488
- * @throws {StandalonePublishError} when no valid txId can be extracted.
489
- */
490
- declare function extractArweaveTxId(base64Data: string): string;
487
+
491
488
  declare class StandalonePublisher implements Publisher {
492
489
  private readonly client;
493
490
  private readonly ownsClient;
@@ -495,7 +492,6 @@ declare class StandalonePublisher implements Publisher {
495
492
  private readonly storeDestination;
496
493
  private readonly channelDestination;
497
494
  private readonly eventFee;
498
- private readonly uploadFeePerByte;
499
495
  private readonly routePrices;
500
496
  private readonly daemonPort;
501
497
  private readonly skipDaemonCheck;
@@ -604,13 +600,10 @@ declare class StandalonePublisher implements Publisher {
604
600
  */
605
601
  readWalletChainBalances(fallback?: WalletViewFallback): Promise<WalletChainBalanceInfo[]>;
606
602
  /**
607
- * Fee rates for `planPush` estimation: the flat per-event fee and the
608
- * per-byte upload rate this publisher pays (daemon `feePerEvent` and seed
609
- * bid-rate conventions; override via options), with the announced route
610
- * prices folded in so the ESTIMATE always equals the CLAIMS: the flat
611
- * `eventFee` is returned pre-floored at the publish route price, and the
612
- * store route price rides as `minUploadFee` (the per-upload floor —
613
- * per-byte pricing can't fold a flat floor into the rate).
603
+ * Fee rates for `planPush` estimation, both flat per packet (ADR 0020),
604
+ * with the announced route prices folded in so the ESTIMATE always equals
605
+ * the CLAIMS: `eventFee` is returned pre-floored at the publish route price,
606
+ * and `uploadFee` IS the store route price.
614
607
  */
615
608
  getFeeRates(): Promise<FeeRates>;
616
609
  /**
@@ -619,15 +612,18 @@ declare class StandalonePublisher implements Publisher {
619
612
  */
620
613
  private effectiveEventFee;
621
614
  /**
622
- * The per-upload claim: `bytes × uploadFeePerByte`, floored at the store
623
- * route's announced price (the connector rejects a claim below it — F06).
615
+ * The per-upload claim: the store route's flat price, whatever the object's
616
+ * size. Byte-proportional pricing has no successor (ADR 0020) — the route
617
+ * table is the price list — and the connector charges this figure whether
618
+ * the body is 100 bytes or 100 KB.
624
619
  */
625
620
  private uploadFee;
626
621
  /**
627
622
  * Upload one git object as a kind:5094 store write (Git-SHA/Git-Type/Repo
628
623
  * tagged — the proven seed-pipeline shape), signing one balance-proof claim
629
- * for `body.length × uploadFeePerByte`, floored at the store route's
630
- * announced price ({@link StandalonePublisherOptions.routePrices}).
624
+ * for the store route's flat price
625
+ * ({@link StandalonePublisherOptions.routePrices}) — ADR 0020 prices a
626
+ * packet per handler, not per byte.
631
627
  *
632
628
  * #368: a blob's `Content-Type` is derived from its path extension (else
633
629
  * octet-stream) and sent in the `output` tag, which the store forwards onto
@@ -642,8 +638,7 @@ declare class StandalonePublisher implements Publisher {
642
638
  * tags (and an optional `Repo` provenance tag), NOT the Git-SHA/Git-Type
643
639
  * tags. Without those the store keeps the bytes verbatim instead of
644
640
  * re-deriving a git envelope, which is exactly what the ar.io path manifest
645
- * needs. One balance-proof claim for `body.length × uploadFeePerByte`,
646
- * floored at the store route's announced price.
641
+ * needs. One balance-proof claim for the store route's flat price.
647
642
  */
648
643
  uploadBlob(upload: BlobUpload): Promise<UploadReceipt>;
649
644
  /**
@@ -770,4 +765,4 @@ declare class NonceLock {
770
765
  release(): void;
771
766
  }
772
767
 
773
- export { type AcquireLockOptions, type ChannelCloseOutcome, ChannelMapCorruptError, type ChannelMapKey, type ChannelMapRecord, ChannelMapStore, type ChannelMapStoreOptions, type ChannelOpenOutcome, type ChannelSettleOutcome, type CheckDaemonOptions, DEFAULT_DAEMON_PORT, DaemonIdentityConflictError, NonceLock, type PersistedChannelContext, RIG_CHANNEL_MAP_FILENAME, type SignedNostrEvent, StandaloneLockError, type StandaloneMoneyOps, StandalonePublishError, StandalonePublisher, type StandalonePublisherOptions, type ToonClientLike, type WalletChainBalanceInfo, type WalletTokenAmountInfo, type WatermarkEntry, channelStatus, checkDaemonIdentity, defaultDaemonPort, defaultLockDir, deriveRouteDestinations, extractArweaveTxId, recordKey, resolveChannelPaths };
768
+ export { type AcquireLockOptions, type ChannelCloseOutcome, ChannelMapCorruptError, type ChannelMapKey, type ChannelMapRecord, ChannelMapStore, type ChannelMapStoreOptions, type ChannelOpenOutcome, type ChannelSettleOutcome, type CheckDaemonOptions, DEFAULT_DAEMON_PORT, DaemonIdentityConflictError, NonceLock, type PersistedChannelContext, RIG_CHANNEL_MAP_FILENAME, type SignedNostrEvent, StandaloneLockError, type StandaloneMoneyOps, StandalonePublishError, StandalonePublisher, type StandalonePublisherOptions, type ToonClientLike, type WalletChainBalanceInfo, type WalletTokenAmountInfo, type WatermarkEntry, channelStatus, checkDaemonIdentity, defaultDaemonPort, defaultLockDir, deriveRouteDestinations, recordKey, resolveChannelPaths };
@@ -3,7 +3,7 @@ import {
3
3
  StandalonePublisher,
4
4
  deriveRouteDestinations,
5
5
  extractArweaveTxId
6
- } from "../chunk-VKEUIYQO.js";
6
+ } from "../chunk-4CAOEXGQ.js";
7
7
  import {
8
8
  ChannelMapCorruptError,
9
9
  ChannelMapStore,
@@ -19,7 +19,7 @@ import {
19
19
  recordKey,
20
20
  resolveChannelPaths
21
21
  } from "../chunk-LCYCKWAT.js";
22
- import "../chunk-35ALWUDJ.js";
22
+ import "../chunk-B5ISARMU.js";
23
23
  export {
24
24
  ChannelMapCorruptError,
25
25
  ChannelMapStore,
@@ -11,13 +11,13 @@ import {
11
11
  import {
12
12
  StandalonePublisher,
13
13
  deriveRouteDestinations
14
- } from "./chunk-VKEUIYQO.js";
14
+ } from "./chunk-4CAOEXGQ.js";
15
15
  import {
16
16
  ChannelMapStore,
17
17
  RIG_CHANNEL_MAP_FILENAME,
18
18
  standaloneForced
19
19
  } from "./chunk-LCYCKWAT.js";
20
- import "./chunk-35ALWUDJ.js";
20
+ import "./chunk-B5ISARMU.js";
21
21
  import {
22
22
  DISCOVERY_TIMEOUT_MS,
23
23
  MinaChannelUnderivableError,
@@ -728,4 +728,4 @@ export {
728
728
  createStandaloneContext,
729
729
  resolveNetworkTopology
730
730
  };
731
- //# sourceMappingURL=standalone-mode-OT63GEPM.js.map
731
+ //# sourceMappingURL=standalone-mode-X6W2RLTE.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toon-protocol/rig",
3
- "version": "2.14.0",
3
+ "version": "3.0.0",
4
4
  "description": "Git-to-TOON write path core — build git objects and NIP-34 events for the Rig control plane",
5
5
  "license": "MIT",
6
6
  "author": "Jonathan Green",
@@ -45,7 +45,7 @@
45
45
  "@toon-format/toon": "^1.0.0",
46
46
  "@toon-protocol/core": "^3.1.2",
47
47
  "nostr-tools": "^2.20.0",
48
- "@toon-protocol/client": "^0.21.2"
48
+ "@toon-protocol/client": "^0.22.0"
49
49
  },
50
50
  "optionalDependencies": {
51
51
  "@ar.io/sdk": "^4.0.3",
@@ -63,6 +63,7 @@
63
63
  },
64
64
  "scripts": {
65
65
  "build": "tsup",
66
+ "typecheck": "tsc -p tsconfig.json --noEmit",
66
67
  "test": "vitest run",
67
68
  "test:coverage": "vitest run --coverage"
68
69
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/objects.ts","../src/publisher.ts"],"sourcesContent":["/**\n * Pure git object construction and SHA-1 envelope hashing.\n *\n * Promoted from `packages/rig-web/tests/e2e/seed/lib/git-builder.ts` (#223) —\n * the proven seed pipeline builders, now the core of the Git-to-TOON write\n * path. Everything here is pure: no network, no signing, no payments.\n * Upload/publish lives with the Publisher (#226).\n *\n * Git object format: `<type> <size>\\0<content>`. The SHA-1 is computed over\n * the full envelope (header + NUL + content); the `body` (content only) is\n * what gets uploaded to Arweave.\n */\n\nimport { createHash } from 'node:crypto';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** All git object types TOON can carry. */\nexport type GitObjectType = 'blob' | 'tree' | 'commit' | 'tag';\n\nexport interface GitObject {\n /** SHA-1 hex digest computed over full git envelope */\n sha: string;\n /** Full git object (header + null + content) */\n buffer: Buffer;\n /** Body only (content after the null byte) — this is what gets uploaded */\n body: Buffer;\n}\n\n/**\n * Maximum uploadable git object body size: 95KB safety margin under the\n * 100KB free tier (R10-005). Larger objects are a hard error in v1.\n */\nexport const MAX_OBJECT_SIZE = 95 * 1024;\n\n/**\n * Git's universal empty-blob SHA-1: the object for a zero-byte file.\n *\n * It is the ONLY zero-byte object git can produce (trees, commits, and tags\n * are never empty) and it always has this exact constant value. The store\n * rejects a zero-byte kind:5094 blob upload as malformed (F00), so `rig` never\n * uploads this object — it is skipped on push and synthesized locally on\n * clone/fetch (both keyed off an ACTUAL zero-length body, never a heuristic).\n */\nexport const EMPTY_BLOB_SHA = 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391';\n\n// ---------------------------------------------------------------------------\n// Envelope hashing\n// ---------------------------------------------------------------------------\n\n/**\n * Wrap a raw object body in the git envelope (`<type> <size>\\0`) and compute\n * its SHA-1. This is exactly what `git hash-object -t <type>` does.\n */\nexport function hashGitObject(type: GitObjectType, body: Buffer): GitObject {\n const header = Buffer.from(`${type} ${body.length}\\0`);\n const fullObject = Buffer.concat([header, body]);\n const sha = createHash('sha1').update(fullObject).digest('hex');\n return { sha, buffer: fullObject, body };\n}\n\n// ---------------------------------------------------------------------------\n// Git object construction\n// ---------------------------------------------------------------------------\n\n/**\n * Construct a git blob object and compute its SHA-1.\n *\n * Format: blob <size>\\0<content>\n * SHA is over the full envelope; body is content only (for upload).\n */\nexport function createGitBlob(content: string): GitObject {\n return hashGitObject('blob', Buffer.from(content, 'utf-8'));\n}\n\n/**\n * Construct a git tree object from sorted entries.\n *\n * Format: tree <size>\\0<entries>\n * Each entry: <mode> <name>\\0<20-byte-raw-sha1>\n * Entries MUST be sorted by name (byte-wise).\n */\nexport function createGitTree(\n entries: { mode: string; name: string; sha: string }[]\n): GitObject {\n // Git sorts tree entries by raw byte order (NOT locale-aware)\n const sorted = [...entries].sort((a, b) =>\n a.name < b.name ? -1 : a.name > b.name ? 1 : 0\n );\n\n const entryBuffers: Buffer[] = [];\n for (const entry of sorted) {\n const modeAndName = Buffer.from(`${entry.mode} ${entry.name}\\0`);\n // Raw 20-byte SHA-1 (NOT hex)\n const rawSha = Buffer.from(entry.sha, 'hex');\n entryBuffers.push(Buffer.concat([modeAndName, rawSha]));\n }\n\n return hashGitObject('tree', Buffer.concat(entryBuffers));\n}\n\n/**\n * Construct a git commit object.\n *\n * Format: commit <size>\\0tree <tree-sha>\\n[parent ...]\\nauthor ...\\ncommitter ...\\n\\n<message>\n * Tree/parent SHAs are hex-encoded (40 chars) in commits, unlike tree entries.\n */\nexport function createGitCommit(opts: {\n treeSha: string;\n parentSha?: string;\n authorName: string;\n authorPubkey: string;\n message: string;\n timestamp: number;\n}): GitObject {\n const lines = [\n `tree ${opts.treeSha}`,\n ...(opts.parentSha ? [`parent ${opts.parentSha}`] : []),\n `author ${opts.authorName} <${opts.authorPubkey}@nostr> ${opts.timestamp} +0000`,\n `committer ${opts.authorName} <${opts.authorPubkey}@nostr> ${opts.timestamp} +0000`,\n '',\n opts.message,\n ];\n return hashGitObject('commit', Buffer.from(lines.join('\\n'), 'utf-8'));\n}\n\n/**\n * Construct an annotated git tag object.\n *\n * Format: tag <size>\\0object <sha>\\ntype <type>\\ntag <name>\\ntagger ...\\n\\n<message>\n * The tagged object is usually a commit, but git allows tagging any object\n * type (including another tag).\n */\nexport function createGitTag(opts: {\n /** SHA-1 of the object being tagged (hex, 40 chars) */\n objectSha: string;\n /** Type of the tagged object (usually 'commit') */\n objectType: GitObjectType;\n /** Tag name, e.g. 'v1.0.0' */\n tagName: string;\n taggerName: string;\n taggerPubkey: string;\n message: string;\n timestamp: number;\n}): GitObject {\n const lines = [\n `object ${opts.objectSha}`,\n `type ${opts.objectType}`,\n `tag ${opts.tagName}`,\n `tagger ${opts.taggerName} <${opts.taggerPubkey}@nostr> ${opts.timestamp} +0000`,\n '',\n opts.message,\n ];\n return hashGitObject('tag', Buffer.from(lines.join('\\n'), 'utf-8'));\n}\n","/**\n * Publisher — the paid-write seam between push planning (this package) and\n * the two transport implementations that follow it in epic #222:\n *\n * 1. daemon (#227): client-mcp ControlClient → toon-clientd loopback\n * /git/* routes, backed by `ClientRunner.publish`/`uploadBlob` (the\n * production paid-publish path — apex channel, signBalanceProof, flat\n * per-event fee).\n * 2. standalone (#228): an embedded ToonClient constructed from a\n * mnemonic, uploading git objects as kind:5094 store writes with\n * Git-SHA/Git-Type/Repo tags (the proven seed-pipeline shape) and\n * publishing NIP-34 events through the relay.\n *\n * The interface is deliberately minimal so both fit:\n *\n * - `uploadGitObject` takes the raw object body (content only — no git\n * envelope header; the store re-derives the SHA envelope from the\n * Git-Type/Git-SHA tags) and returns the Arweave txId plus the fee paid.\n * - `publishEvent` takes an UNSIGNED event template — signing stays with\n * the implementation (the daemon-held key never leaves the daemon; the\n * standalone impl signs with its own keypair). Relay URLs are plural\n * from day one (forward-compat for parked #84/#92; size 1 today).\n * - `getFeeRates` exposes what `planPush` needs for the pre-push estimate:\n * a per-byte upload rate (seed pipeline bids bytes × rate) and a flat\n * per-event publish fee (the daemon charges `apex.feePerEvent` regardless\n * of event size).\n *\n * All fees are bigint in the smallest asset unit (matches `@toon-protocol/client`\n * channel math); HTTP transports serialize them as strings and convert at\n * the boundary.\n */\n\nimport type { UnsignedEvent } from './nip34-events.js';\nimport type { GitObjectType } from './objects.js';\n\n/** A git object queued for upload to Arweave via the paid store path. */\nexport interface GitObjectUpload {\n /** Full 40-hex SHA-1 (over the git envelope — see `hashGitObject`). */\n sha: string;\n type: GitObjectType;\n /** Raw object body (content only, no `<type> <size>\\0` header). */\n body: Buffer;\n /** Repository identifier — becomes the `Repo` tag on the store write. */\n repoId: string;\n /**\n * Path the blob was reached by in the tree (#368), if known. Its extension\n * derives the `Content-Type` sent in the store write's `output` tag so a\n * gateway serves the blob as its real media type instead of\n * `application/octet-stream`. Absent (or a non-blob object) → octet-stream.\n */\n path?: string;\n}\n\n/**\n * A NON-git blob queued for upload to Arweave with an explicit `Content-Type`\n * (#368): the ar.io path manifest that turns a pushed repo into a permaweb\n * site. Unlike {@link GitObjectUpload} it carries no `Git-SHA`/`Git-Type`\n * tags, so the store stores the raw bytes verbatim (no git-envelope\n * re-derivation) — exactly what a manifest needs.\n */\nexport interface BlobUpload {\n /** Raw bytes to store. */\n body: Buffer;\n /** MIME type sent in the store write's `output` tag. */\n contentType: string;\n /** Optional repository identifier for provenance (`Repo` tag). */\n repoId?: string;\n}\n\n/** Receipt for one uploaded git object. */\nexport interface UploadReceipt {\n /** Arweave transaction ID the object is retrievable under. */\n txId: string;\n /** Fee paid for this upload, in the smallest asset unit. */\n feePaid: bigint;\n}\n\n/** Receipt for one published Nostr event. */\nexport interface PublishReceipt {\n /** Event ID as accepted by the relay(s). */\n eventId: string;\n /** Fee paid for this publish, in the smallest asset unit. */\n feePaid: bigint;\n}\n\n/** Fee rates used by `planPush` for the pre-push estimate. */\nexport interface FeeRates {\n /** Upload cost per body byte (smallest asset unit). */\n uploadFeePerByte: bigint;\n /**\n * Flat cost per published event (smallest asset unit). Implementations\n * already fold any per-packet route-price floor into this flat value, so\n * estimates using it match the claims actually signed.\n */\n eventFee: bigint;\n /**\n * FLAT minimum per upload claim (smallest asset unit): the store\n * destination's announced route price. The connector gates every paid\n * packet at the destination route's price — a balance-proof claim\n * advancing the channel by less is rejected (F06) — so each per-upload fee\n * is `max(bytes × uploadFeePerByte, minUploadFee)`. Absent: no floor\n * (pre-floor behavior, e.g. when the peer announces no capability prices).\n */\n minUploadFee?: bigint;\n}\n\n/**\n * Per-upload fee: `bytes × ratePerByte`, floored at `minFee` (the\n * destination's announced flat route price — see\n * {@link FeeRates.minUploadFee}). The single shared implementation keeps\n * every estimate site equal to what the publisher actually claims.\n */\nexport function flooredUploadFee(\n bytes: number,\n ratePerByte: bigint,\n minFee?: bigint\n): bigint {\n const fee = BigInt(bytes) * ratePerByte;\n const min = minFee ?? 0n;\n return fee > min ? fee : min;\n}\n\n/**\n * Paid transport for `executePush` — implemented by the daemon route\n * handlers (#227) and the standalone embedded client (#228).\n *\n * Implementations must be safe to call sequentially (uploads are issued one\n * at a time in dependency-safe order) and should throw on any failure —\n * `executePush` does not retry; a crashed push is resumed by re-planning\n * (content-addressed uploads make the retry idempotent).\n */\nexport interface Publisher {\n /** Current fee rates for estimation (may be queried before every plan). */\n getFeeRates(): Promise<FeeRates>;\n /** Upload one git object body to Arweave; paid. */\n uploadGitObject(upload: GitObjectUpload): Promise<UploadReceipt>;\n /**\n * Upload one raw blob (no git envelope) with an explicit `Content-Type`;\n * paid. Used by `rig site` (#368) for the ar.io path manifest. Optional so\n * transports that only move git objects (and pre-#368 test fakes) need not\n * implement it — `rig site` requires it and errors clearly when absent.\n */\n uploadBlob?(upload: BlobUpload): Promise<UploadReceipt>;\n /**\n * Sign (implementation-held key) and pay-to-publish one event to the\n * given relay(s).\n */\n publishEvent(\n event: UnsignedEvent,\n relayUrls: string[]\n ): Promise<PublishReceipt>;\n}\n"],"mappings":";AAaA,SAAS,kBAAkB;AAsBpB,IAAM,kBAAkB,KAAK;AAW7B,IAAM,iBAAiB;AAUvB,SAAS,cAAc,MAAqB,MAAyB;AAC1E,QAAM,SAAS,OAAO,KAAK,GAAG,IAAI,IAAI,KAAK,MAAM,IAAI;AACrD,QAAM,aAAa,OAAO,OAAO,CAAC,QAAQ,IAAI,CAAC;AAC/C,QAAM,MAAM,WAAW,MAAM,EAAE,OAAO,UAAU,EAAE,OAAO,KAAK;AAC9D,SAAO,EAAE,KAAK,QAAQ,YAAY,KAAK;AACzC;AAYO,SAAS,cAAc,SAA4B;AACxD,SAAO,cAAc,QAAQ,OAAO,KAAK,SAAS,OAAO,CAAC;AAC5D;AASO,SAAS,cACd,SACW;AAEX,QAAM,SAAS,CAAC,GAAG,OAAO,EAAE;AAAA,IAAK,CAAC,GAAG,MACnC,EAAE,OAAO,EAAE,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI;AAAA,EAC/C;AAEA,QAAM,eAAyB,CAAC;AAChC,aAAW,SAAS,QAAQ;AAC1B,UAAM,cAAc,OAAO,KAAK,GAAG,MAAM,IAAI,IAAI,MAAM,IAAI,IAAI;AAE/D,UAAM,SAAS,OAAO,KAAK,MAAM,KAAK,KAAK;AAC3C,iBAAa,KAAK,OAAO,OAAO,CAAC,aAAa,MAAM,CAAC,CAAC;AAAA,EACxD;AAEA,SAAO,cAAc,QAAQ,OAAO,OAAO,YAAY,CAAC;AAC1D;AAQO,SAAS,gBAAgB,MAOlB;AACZ,QAAM,QAAQ;AAAA,IACZ,QAAQ,KAAK,OAAO;AAAA,IACpB,GAAI,KAAK,YAAY,CAAC,UAAU,KAAK,SAAS,EAAE,IAAI,CAAC;AAAA,IACrD,UAAU,KAAK,UAAU,KAAK,KAAK,YAAY,WAAW,KAAK,SAAS;AAAA,IACxE,aAAa,KAAK,UAAU,KAAK,KAAK,YAAY,WAAW,KAAK,SAAS;AAAA,IAC3E;AAAA,IACA,KAAK;AAAA,EACP;AACA,SAAO,cAAc,UAAU,OAAO,KAAK,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;AACvE;AASO,SAAS,aAAa,MAWf;AACZ,QAAM,QAAQ;AAAA,IACZ,UAAU,KAAK,SAAS;AAAA,IACxB,QAAQ,KAAK,UAAU;AAAA,IACvB,OAAO,KAAK,OAAO;AAAA,IACnB,UAAU,KAAK,UAAU,KAAK,KAAK,YAAY,WAAW,KAAK,SAAS;AAAA,IACxE;AAAA,IACA,KAAK;AAAA,EACP;AACA,SAAO,cAAc,OAAO,OAAO,KAAK,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;AACpE;;;AC5CO,SAAS,iBACd,OACA,aACA,QACQ;AACR,QAAM,MAAM,OAAO,KAAK,IAAI;AAC5B,QAAM,MAAM,UAAU;AACtB,SAAO,MAAM,MAAM,MAAM;AAC3B;","names":[]}