@run402/sdk 4.93.2 → 4.94.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.
Files changed (195) hide show
  1. package/README.md +21 -19
  2. package/core-dist/config.d.ts +16 -2
  3. package/core-dist/config.js +52 -18
  4. package/core-dist/control-plane-session.d.ts +29 -14
  5. package/core-dist/control-plane-session.js +31 -6
  6. package/core-dist/keystore.js +7 -7
  7. package/core-dist/profiles.d.ts +3 -3
  8. package/core-dist/profiles.js +9 -7
  9. package/core-dist/{allowance-auth.d.ts → wallet-auth.d.ts} +6 -6
  10. package/core-dist/{allowance-auth.js → wallet-auth.js} +15 -15
  11. package/core-dist/wallet.d.ts +22 -0
  12. package/core-dist/{allowance.js → wallet.js} +20 -20
  13. package/core-dist/{write-auth-session.d.ts → write-approvals.d.ts} +28 -26
  14. package/core-dist/{write-auth-session.js → write-approvals.js} +19 -19
  15. package/dist/actions.d.ts +1 -1
  16. package/dist/actions.d.ts.map +1 -1
  17. package/dist/control-plane-credentials.d.ts +8 -8
  18. package/dist/control-plane-credentials.js +7 -7
  19. package/dist/credentials.d.ts +19 -19
  20. package/dist/credentials.d.ts.map +1 -1
  21. package/dist/credentials.js +1 -1
  22. package/dist/errors.d.ts +24 -26
  23. package/dist/errors.d.ts.map +1 -1
  24. package/dist/errors.js +34 -37
  25. package/dist/errors.js.map +1 -1
  26. package/dist/index.d.ts +29 -16
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +29 -16
  29. package/dist/index.js.map +1 -1
  30. package/dist/kernel.d.ts +1 -1
  31. package/dist/kernel.d.ts.map +1 -1
  32. package/dist/kernel.js +10 -9
  33. package/dist/kernel.js.map +1 -1
  34. package/dist/namespaces/admin.d.ts +51 -120
  35. package/dist/namespaces/admin.d.ts.map +1 -1
  36. package/dist/namespaces/admin.js +41 -45
  37. package/dist/namespaces/admin.js.map +1 -1
  38. package/dist/namespaces/agent.d.ts +2 -2
  39. package/dist/namespaces/agent.d.ts.map +1 -1
  40. package/dist/namespaces/agent.js +2 -2
  41. package/dist/namespaces/agent.js.map +1 -1
  42. package/dist/namespaces/ai.d.ts +1 -1
  43. package/dist/namespaces/ai.js +1 -1
  44. package/dist/namespaces/billing.d.ts +6 -3
  45. package/dist/namespaces/billing.d.ts.map +1 -1
  46. package/dist/namespaces/billing.js.map +1 -1
  47. package/dist/namespaces/buzz-notifications.types.d.ts +1 -1
  48. package/dist/namespaces/buzz.d.ts +2 -2
  49. package/dist/namespaces/buzz.d.ts.map +1 -1
  50. package/dist/namespaces/buzz.js +2 -2
  51. package/dist/namespaces/buzz.js.map +1 -1
  52. package/dist/namespaces/buzz.types.d.ts +2 -2
  53. package/dist/namespaces/buzz.types.d.ts.map +1 -1
  54. package/dist/namespaces/credentials.types.d.ts +1 -1
  55. package/dist/namespaces/deploy.d.ts +1 -1
  56. package/dist/namespaces/deploy.js +5 -5
  57. package/dist/namespaces/deploy.js.map +1 -1
  58. package/dist/namespaces/deploy.types.d.ts +4 -4
  59. package/dist/namespaces/escalations.d.ts +1 -1
  60. package/dist/namespaces/escalations.js +1 -1
  61. package/dist/namespaces/escalations.types.d.ts +2 -2
  62. package/dist/namespaces/escalations.types.d.ts.map +1 -1
  63. package/dist/namespaces/events.types.d.ts +1 -1
  64. package/dist/namespaces/functions.d.ts +1 -1
  65. package/dist/namespaces/functions.js +1 -1
  66. package/dist/namespaces/gitvault.crypto.d.ts +1 -1
  67. package/dist/namespaces/gitvault.d.ts +24 -24
  68. package/dist/namespaces/gitvault.d.ts.map +1 -1
  69. package/dist/namespaces/gitvault.js +109 -109
  70. package/dist/namespaces/gitvault.js.map +1 -1
  71. package/dist/namespaces/me.d.ts +120 -0
  72. package/dist/namespaces/me.d.ts.map +1 -0
  73. package/dist/namespaces/me.js +34 -0
  74. package/dist/namespaces/me.js.map +1 -0
  75. package/dist/namespaces/org.d.ts +108 -6
  76. package/dist/namespaces/org.d.ts.map +1 -1
  77. package/dist/namespaces/org.js +63 -7
  78. package/dist/namespaces/org.js.map +1 -1
  79. package/dist/namespaces/org.types.d.ts +29 -9
  80. package/dist/namespaces/org.types.d.ts.map +1 -1
  81. package/dist/namespaces/pay.js +3 -3
  82. package/dist/namespaces/pay.js.map +1 -1
  83. package/dist/namespaces/projects.d.ts +9 -9
  84. package/dist/namespaces/projects.js +15 -15
  85. package/dist/namespaces/projects.js.map +1 -1
  86. package/dist/namespaces/projects.types.d.ts +28 -12
  87. package/dist/namespaces/projects.types.d.ts.map +1 -1
  88. package/dist/namespaces/rooms.d.ts +7 -7
  89. package/dist/namespaces/rooms.js +17 -17
  90. package/dist/namespaces/rooms.js.map +1 -1
  91. package/dist/namespaces/rooms.types.d.ts +9 -9
  92. package/dist/namespaces/rooms.types.d.ts.map +1 -1
  93. package/dist/namespaces/service.d.ts +1 -1
  94. package/dist/namespaces/service.js +1 -1
  95. package/dist/namespaces/{operator-session.d.ts → session.d.ts} +135 -51
  96. package/dist/namespaces/session.d.ts.map +1 -0
  97. package/dist/namespaces/{operator-session.js → session.js} +118 -30
  98. package/dist/namespaces/session.js.map +1 -0
  99. package/dist/namespaces/subdomains.d.ts +5 -5
  100. package/dist/namespaces/subdomains.d.ts.map +1 -1
  101. package/dist/namespaces/subdomains.js +6 -6
  102. package/dist/namespaces/subdomains.js.map +1 -1
  103. package/dist/namespaces/tier.d.ts +43 -20
  104. package/dist/namespaces/tier.d.ts.map +1 -1
  105. package/dist/namespaces/tier.js +7 -7
  106. package/dist/namespaces/tier.js.map +1 -1
  107. package/dist/namespaces/transfers.d.ts +74 -71
  108. package/dist/namespaces/transfers.d.ts.map +1 -1
  109. package/dist/namespaces/transfers.js +31 -38
  110. package/dist/namespaces/transfers.js.map +1 -1
  111. package/dist/namespaces/vouchers.d.ts +9 -10
  112. package/dist/namespaces/vouchers.d.ts.map +1 -1
  113. package/dist/namespaces/vouchers.js +4 -5
  114. package/dist/namespaces/vouchers.js.map +1 -1
  115. package/dist/namespaces/wallets.d.ts +72 -3
  116. package/dist/namespaces/wallets.d.ts.map +1 -1
  117. package/dist/namespaces/wallets.js +141 -3
  118. package/dist/namespaces/wallets.js.map +1 -1
  119. package/dist/namespaces/write-approval.d.ts +101 -0
  120. package/dist/namespaces/write-approval.d.ts.map +1 -0
  121. package/dist/namespaces/write-approval.js +62 -0
  122. package/dist/namespaces/write-approval.js.map +1 -0
  123. package/dist/node/actions-node.d.ts +3 -3
  124. package/dist/node/actions-node.d.ts.map +1 -1
  125. package/dist/node/actions-node.js +36 -36
  126. package/dist/node/actions-node.js.map +1 -1
  127. package/dist/node/{bearer-claim-key.d.ts → bearer-redeem-key.d.ts} +12 -12
  128. package/dist/node/bearer-redeem-key.d.ts.map +1 -0
  129. package/dist/node/{bearer-claim-key.js → bearer-redeem-key.js} +21 -21
  130. package/dist/node/bearer-redeem-key.js.map +1 -0
  131. package/dist/node/ci.d.ts +1 -1
  132. package/dist/node/ci.d.ts.map +1 -1
  133. package/dist/node/ci.js +6 -6
  134. package/dist/node/ci.js.map +1 -1
  135. package/dist/node/credentials.d.ts +17 -16
  136. package/dist/node/credentials.d.ts.map +1 -1
  137. package/dist/node/credentials.js +28 -27
  138. package/dist/node/credentials.js.map +1 -1
  139. package/dist/node/funding-recovery.d.ts +1 -1
  140. package/dist/node/funding-recovery.d.ts.map +1 -1
  141. package/dist/node/funding-recovery.js +1 -1
  142. package/dist/node/funding-recovery.js.map +1 -1
  143. package/dist/node/gitvault-apply.d.ts +1 -1
  144. package/dist/node/gitvault-apply.d.ts.map +1 -1
  145. package/dist/node/gitvault-handoff.d.ts +22 -22
  146. package/dist/node/gitvault-handoff.d.ts.map +1 -1
  147. package/dist/node/gitvault-handoff.js +45 -45
  148. package/dist/node/gitvault-handoff.js.map +1 -1
  149. package/dist/node/gitvault-prewarm.js +7 -7
  150. package/dist/node/gitvault-prewarm.js.map +1 -1
  151. package/dist/node/gitvault-restore.d.ts +1 -1
  152. package/dist/node/gitvault-restore.js +1 -1
  153. package/dist/node/index.d.ts +16 -16
  154. package/dist/node/index.d.ts.map +1 -1
  155. package/dist/node/index.js +15 -15
  156. package/dist/node/index.js.map +1 -1
  157. package/dist/node/org-adopt.d.ts +49 -0
  158. package/dist/node/org-adopt.d.ts.map +1 -0
  159. package/dist/node/org-adopt.js +77 -0
  160. package/dist/node/org-adopt.js.map +1 -0
  161. package/dist/node/paid-fetch.d.ts +7 -7
  162. package/dist/node/paid-fetch.d.ts.map +1 -1
  163. package/dist/node/paid-fetch.js +54 -54
  164. package/dist/node/paid-fetch.js.map +1 -1
  165. package/dist/node/preflight.d.ts +1 -1
  166. package/dist/node/preflight.d.ts.map +1 -1
  167. package/dist/node/preflight.js +1 -1
  168. package/dist/node/preflight.js.map +1 -1
  169. package/dist/node/source-scan.d.ts +1 -1
  170. package/dist/node/source-scan.js +2 -2
  171. package/dist/node/source-scan.js.map +1 -1
  172. package/dist/scoped.d.ts +3 -3
  173. package/dist/scoped.d.ts.map +1 -1
  174. package/dist/scoped.js +2 -2
  175. package/dist/scoped.js.map +1 -1
  176. package/package.json +1 -1
  177. package/core-dist/allowance.d.ts +0 -22
  178. package/core-dist/operator-session.d.ts +0 -80
  179. package/core-dist/operator-session.js +0 -154
  180. package/dist/namespaces/allowance.d.ts +0 -79
  181. package/dist/namespaces/allowance.d.ts.map +0 -1
  182. package/dist/namespaces/allowance.js +0 -149
  183. package/dist/namespaces/allowance.js.map +0 -1
  184. package/dist/namespaces/operator-session.d.ts.map +0 -1
  185. package/dist/namespaces/operator-session.js.map +0 -1
  186. package/dist/namespaces/operator.d.ts +0 -359
  187. package/dist/namespaces/operator.d.ts.map +0 -1
  188. package/dist/namespaces/operator.js +0 -272
  189. package/dist/namespaces/operator.js.map +0 -1
  190. package/dist/node/bearer-claim-key.d.ts.map +0 -1
  191. package/dist/node/bearer-claim-key.js.map +0 -1
  192. package/dist/node/operator-claim.d.ts +0 -49
  193. package/dist/node/operator-claim.d.ts.map +0 -1
  194. package/dist/node/operator-claim.js +0 -77
  195. package/dist/node/operator-claim.js.map +0 -1
package/README.md CHANGED
@@ -14,7 +14,7 @@ Deployment summaries share the SDK workflow view. CLI writes redacted detail und
14
14
 
15
15
  | Import | Use when |
16
16
  |---|---|
17
- | `@run402/sdk/node` | Running in Node 22 with the local profile state, project-key credential cache, and allowance. Auto-loads the configured API base, profile `credentials/project-keys.v1.json`, and signs x402 payments from the selected allowance or opaque signer. Includes `r.actions.run(...)`, `r.up(...)`, `r.sites.deployDir(dir)`, `fileSetFromDir(dir)`, `loadDeployManifest(path)`, `normalizeDeployManifest(input)`, and `resolveRun402TargetProfile()`. |
17
+ | `@run402/sdk/node` | Running in Node 22 with the local profile state, project-key credential cache, and wallet. Auto-loads the configured API base, profile `credentials/project-keys.v1.json`, and signs x402 payments from the selected wallet or opaque signer. Includes `r.actions.run(...)`, `r.up(...)`, `r.sites.deployDir(dir)`, `fileSetFromDir(dir)`, `loadDeployManifest(path)`, `normalizeDeployManifest(input)`, and `resolveRun402TargetProfile()`. |
18
18
  | `@run402/sdk` | Isomorphic — works in Node, Deno, Bun, V8 isolates. No filesystem access. Bring your own `CredentialsProvider` (a session-token shim, a remote vault, anything that resolves project keys + auth headers). |
19
19
 
20
20
  The Node entry sends bounded client-version metadata on gateway requests using the unprefixed `Run402-Client` header, for example `surface="sdk", version="3.7.14", sdk="3.7.14"`. The CLI passes `surface: "cli"`, so gateway compatibility hints can distinguish CLI-created SDK traffic from direct SDK callers. Metadata never includes local paths, package manager details, wallet/org/project ids, secrets, or install confidence. The isomorphic entry does not send this header by default; pass `clientMetadata` explicitly only in runtimes where custom headers are expected.
@@ -78,14 +78,14 @@ provider controls API authentication; the x402 payer is resolved exactly once
78
78
  in this order:
79
79
 
80
80
  1. `paymentSigner` — an explicit async EVM signer provider (KMS/HSM friendly).
81
- 2. `allowancePath` — an explicit local allowance file.
82
- 3. `credentials.readAllowance()` — when a supplied provider implements it.
83
- 4. The Node default provider's active-profile allowance — only when the caller
81
+ 2. `walletPath` — an explicit local wallet file.
82
+ 3. `credentials.readWallet()` — when a supplied provider implements it.
83
+ 4. The Node default provider's active-profile wallet — only when the caller
84
84
  did not supply a custom credentials provider.
85
85
 
86
86
  Once a source is selected, the SDK never falls back to the ambient/global
87
- wallet. `paymentSigner` and `allowancePath` together throw
88
- `PAYMENT_SOURCE_CONFLICT`. Passing both `credentials` and `allowancePath` is
87
+ wallet. `paymentSigner` and `walletPath` together throw
88
+ `PAYMENT_SOURCE_CONFLICT`. Passing both `credentials` and `walletPath` is
89
89
  valid: auth uses `credentials`, while payment intentionally uses that file.
90
90
  `fetch` still takes precedence over built-in paid fetch, and
91
91
  `disablePaidFetch: true` disables automatic payment entirely.
@@ -123,7 +123,7 @@ const payer = await r.paymentPayer();
123
123
 
124
124
  The provider may return `null` for an unsupported Base network. Paid-fetch
125
125
  initialization is lazy and retries after missing/recoverable local state, so a
126
- long-lived client can start paying after its selected allowance/provider
126
+ long-lived client can start paying after its selected wallet/provider
127
127
  becomes available without being reconstructed. `r.paymentPayer()` initializes
128
128
  the selected source if necessary and returns only its source, rail, public
129
129
  address(es), and network(s); it never returns a key, signed authorization, or
@@ -211,7 +211,7 @@ await r.actions.run({
211
211
  });
212
212
  ```
213
213
 
214
- Action identifiers are exported constants plus a string-literal union, so inputs narrow by `type`. `up` validates `run402.deploy.json` / `app.json` before any mutation, resolves the project as explicit `projectId` → `.run402/project.json` → manifest `project_id` → approved creation from `name`; global active state never selects a deployment target, then delegates to `r.project(id).apply(...)`. `name` is only project creation/link metadata; it is not a manifest field and never renames an existing project. If allowance/tier/project/link are already configured, `r.up()` can run the requested deploy with the default approval policy; pass `{ approval: "yes" }` only when you want recursive prerequisites/local writes to proceed unattended.
214
+ Action identifiers are exported constants plus a string-literal union, so inputs narrow by `type`. `up` validates `run402.deploy.json` / `app.json` before any mutation, resolves the project as explicit `projectId` → `.run402/project.json` → manifest `project_id` → approved creation from `name`; global active state never selects a deployment target, then delegates to `r.project(id).apply(...)`. `name` is only project creation/link metadata; it is not a manifest field and never renames an existing project. If wallet/tier/project/link are already configured, `r.up()` can run the requested deploy with the default approval policy; pass `{ approval: "yes" }` only when you want recursive prerequisites/local writes to proceed unattended.
215
215
 
216
216
  Before any gateway call, in every mode, `up` verifies every local file the manifest references (migration `sql_path`/`sql_file`, function `source`/`files`, site `{ path }` entries and `dir()` targets, `assets.put[].source`) and throws `MANIFEST_FILE_MISSING` (`details.missing[]` of `{ field_path, path, kind }`, one `create_file` next action per file); `manifest` pointing at a missing path is `MANIFEST_NOT_FOUND`, and with no manifest in the directory `UP_MANIFEST_REQUIRED` lists `details.nearby_manifests[]` one level down with a read-only `run_in_directory` action for a single candidate, or one unranked `select_application` action for multiple apps. The same check is exported standalone from `@run402/sdk/node`: `collectLocalFileReferences(spec)`, `findMissingLocalFileReferences(spec)`, `assertLocalFileReferencesExist(spec, { manifestPath? })`, plus the `manifestFileMissingError` / `manifestNotFoundError` builders.
217
217
 
@@ -303,14 +303,14 @@ const r = new Run402({
303
303
  });
304
304
  ```
305
305
 
306
- The `CredentialsProvider` interface has two required methods (`getAuth`, `getProject`) plus optional ones (`saveProject`, `removeProject`, `setActiveProject`, `readAllowance`, `saveAllowance`, …) for hosts that want full sticky-default behavior.
306
+ The `CredentialsProvider` interface has two required methods (`getAuth`, `getProject`) plus optional ones (`saveProject`, `removeProject`, `setActiveProject`, `readWallet`, `saveWallet`, …) for hosts that want full sticky-default behavior.
307
307
 
308
308
  ## Namespaces
309
309
 
310
310
  | Namespace | Highlights |
311
311
  |---|---|
312
312
  | `actions` | Node entry only (`@run402/sdk/node`). Generic recursive action runner: `actions.run({ type: Run402Action.Up | ProjectsProvision | TierSet, ... })`; `r.up(input, opts)` is the convenience for repo-level manifest deploys. Recursive mutations are approval-gated; `mode: "check" | "printSpec" | "printManifest" | "plan" | { kind: "applyReviewed" }` distinguishes local validation, gateway review, and exact reviewed apply. Child gateway mutations derive idempotency keys from the root action. |
313
- | `pay` | `fetch(url, init?, { maxUsdMicros?, idempotencyKey?, requireReceipt? })` — bounded arbitrary-URL x402 buyer; Node uses the selected allowance/signer and returns the response plus settlement and independently verified merchant evidence. |
313
+ | `pay` | `fetch(url, init?, { maxUsdMicros?, idempotencyKey?, requireReceipt? })` — bounded arbitrary-URL x402 buyer; Node uses the selected wallet/signer and returns the response plus settlement and independently verified merchant evidence. |
314
314
  | `projects` | `provision`, `delete`, `list`, `get`, `use`, `active`, `sql`, `rest`, `validateExpose`, `applyExpose`, `getExpose`, `getUsage`, `getSchema`, `info`, `keys`, `pin`, `getQuote`. `list`/`get`/`use` are server-authoritative; local key reads are moving to `credentials.projectKeys`. |
315
315
  | `snapshots` | Internal project restore points: `create`, `list`, `get`, `restorePlan`, `restore`, `delete`. Restore is a two-step plan/confirm handshake. |
316
316
  | `branches` | Contained project data branches: `create`, `list`, `renew`, `delete`. Branches default to expiring, noindex, sandboxed-email copies. |
@@ -323,23 +323,25 @@ The `CredentialsProvider` interface has two required methods (`getAuth`, `getPro
323
323
  | `functions` | `deploy`, `invoke`, `logs` (`{ tail?, since?, requestId?, origin? }`; every entry carries `origin: "app" \| "platform"`, computed by the exported `classifyFunctionLogLine`, and `origin` filters client-side with `hidden: { platform, app }` counts), `logsByRequestId(projectId, requestId, { tail?, since?, origin?, functionName? })` (project-wide search for a `req_`/`fnrun_`/`fnatt_` id, the `x-run402-request-id` response header: reads every function, merges oldest-first, tags each entry with its `function`; also `r.project(id).functions.logsByRequestId`), `update`, `list`, `delete`, `rebuild`, `rebuildAll`, `runs.*` durable function requests |
324
324
  | `jobs` | `submit`, `get`, `logs`, `cancel`, `purge` for platform-managed jobs |
325
325
  | `secrets` | `set`, `list`, `delete` |
326
- | `subdomains` | `claim`, `list`, `delete` (most agents declare subdomains in `r.project(id).apply({ subdomains: { set: [...] } })` instead) |
326
+ | `subdomains` | `add`, `list`, `delete` (most agents declare subdomains in `r.project(id).apply({ subdomains: { set: [...] } })` instead) |
327
327
  | `domains` | The ProjectDomain lifecycle — the one surface for custom domains (web + email): `ensure` (connect / update desired state), `get`, `list`, `check` (refresh observations), `apply` (records Run402 has authority over), `repair`, `wait`, `testReceive`, `activate`, `disconnect`. `desired` carries `web`, `email`, and an optional `authority` — `"hosted_dns_zone"` is the root-domain path (one nameserver change at the registrar; Run402 applies every in-zone record and issues TLS). Every response carries `next_actions[]`. |
328
328
  | `email` | `createMailbox`, `listMailboxes`, `setMailboxDefaults`, `updateMailbox`, `getMailbox`, `deleteMailbox`, `send`, `list`, `get`, `getRaw`, `webhooks.*` |
329
329
  | `auth` | `requestMagicLink` (link/code/both), `verifyMagicLink`, `verifyEmailCode`, `createUser`, `inviteUser`, `setUserPassword`, `settings`, passkey registration/login/list/delete helpers, typed `providers`, `promote`, `demote` |
330
330
  | `apps` | `browse`, `getApp`, `fork`, `publish`, `listVersions`, `updateVersion`, `deleteVersion` |
331
331
  | `tier` | `set`, `status` (tier pricing lives on `r.projects.getQuote()`) |
332
332
  | `billing` | `createEmailOrganization`, `linkWallet`, `createCheckout`, `setAutoRecharge`, `checkBalance`, `getOrganization`, `lookupOrganization`, `getHistory`, `balance`, `history` |
333
- | `vouchers` | `redeem` (promo code → prepaid credit; safe to retry) |
333
+ | `vouchers` | `redeem` (promo code → the organization's allowance; safe to retry) |
334
334
  | `contracts` | `provisionSigner`, `getSigner`, `listSigners`, `setRecovery`, `setLowBalanceAlert`, `call`, `read`, `callStatus`, `drain`, `deleteSigner` |
335
335
  | `ai` | `translate`, `moderate`, `usage`, `generateImage` |
336
- | `allowance` | `status`, `create`, `export`, `faucet` |
337
336
  | `service` | `status`, `health` (no auth, no setup — works on a fresh install) |
338
- | `admin` | Operator/admin endpoints: messages/contact, per-project finance (`getProjectFinance`) |
339
- | `operator` | **The human / email principal** — distinct from the agent's per-wallet SIWX identity (and from platform-`admin`). Read session: `deviceStart`, `devicePoll`, `overview({ token })`, `revoke({ token })` — browser-delegated device-authorization (RFC 8628, the `aws sso login` model); `overview` returns the email-union across every wallet that verified the email. Write session (v1.78): `buildCliAuthorizeUrl`/`exchangeCliToken` (loopback-PKCE CLI login) + the hosted `operator.session.*` surface (email magic-link / passkey / OAuth login, `whoami`/`refresh`/`revoke`, step-up, authenticators, recovery) — carry a minted session SDK-wide with `controlPlaneSessionCredentials({ token })`. Drives `run402 operator login[/--loopback]/overview/whoami/logout`. No MCP tool by design — MCP authenticates as the agent, not the human. |
337
+ | `admin` | Admin endpoints: messages/contact, notifications, staff-only per-project finance (`getProjectFinance`) |
338
+ | `session` | **A person's sign-in session** — distinct from the agent's per-wallet SIWX identity. One session class, graded by provenance (`grade`: `browser`, `loopback`, `device` — read-only). CLI seams: `buildCliAuthorizeUrl`/`exchangeCliToken` (loopback PKCE, `run402 login`) and `deviceStart`/`devicePoll` (RFC 8628, `run402 login --device`). Browser surface: email magic link / passkey / OAuth sign-in, `whoami`/`refresh`/`revoke`, step-up, authenticators, recovery. Carry a minted session SDK-wide with `controlPlaneSessionCredentials({ token })`. No MCP tool by design. |
339
+ | `writeApproval` | `requestChallenge`, `exchangeClaimCode` — the passkey-signed, `(action, target)`-scoped write approval a person without a wallet needs to provision, deploy, or write secrets (`run402 approve`); a gated write without one throws `WriteApprovalRequiredError`. |
340
+ | `me` | `overview()` (`GET /agent/v1/me/overview`, joined into `run402 org list`), `status()` (`GET /agent/v1/me/status`, read by `run402 doctor` and MCP `whoami`) |
340
341
  | `identityLinks` | Public human/agent external identity attribution with a discriminated proof protocol. Agent `nostr.begin`/`complete` uses EOA + kind 1; human creation/revocation is browser-canonical. `list`, `getProof`, and `revoke` preserve multiple active and revoked records. Never accepts a Nostr secret and never grants authority. |
341
342
  | `buzz` | Capability-detecting Buzz control plane. `offerAdoption` plus `humanAdoptionOffers` creates/reads/cancels durable HTTPS handoffs and creates human-bound attempts; direct `humanAdoptions` is advanced compatibility. `install/enroll` and typed community/enrollment methods preserve separate principals, bounded named-project grants, drift, and scoped revocation. `notifications` routes project events into a Buzz channel (`createRoute`/`list`/`get`/`update`/`pause`/`resume`/`rotate`/`revoke`/`test`/`deliveries`/`testAndWait` — configure → authorize → test → live; the signing secret never leaves the gateway). Buzz signing stays outside the SDK. |
342
- | `wallet(address)` | `getLabel()`, `setLabel(label)` — the signed server-side wallet label (gateway `/wallets/v1/:address/label`) surfaced in the operator console; pushed on `wallets use` unless `RUN402_WALLET_LABEL_SYNC=0`. Use the `r.wallet(address)` handle; `r.wallets.getLabel(address)` remains a bare read |
343
+ | `wallets` | The local wallet: `status`, `create`, `export`, `faucet`; plus `getLabel(address)` |
344
+ | `wallet(address)` | `getLabel()`, `setLabel(label)` — the signed server-side wallet label (gateway `/wallets/v1/:address/label`) surfaced in the console; pushed on `wallets use` unless `RUN402_WALLET_LABEL_SYNC=0`. Use the `r.wallet(address)` handle; `r.wallets.getLabel(address)` remains a bare read |
343
345
  | `orgs` | **Org-owned control plane** (first-class orgs). `create`, `list`, `whoami` (the gateway-resolved control-plane identity) on the collection; the scoped `r.org(id)` sub-client (org analog of `r.project(id)`) adds `get`, `rename`, `setPayoutWallet`, `members.*` (`list`/`add`/`setRole`/`revoke`), `invites.*` (`list`/`create`/`revoke`), `audit`. Org create/read/rename summaries include `tier`, `lease_started_at`, and `lease_expires_at`. |
344
346
  | `grants` | `create`, `revoke` — per-project capability grants (e.g. `"deploy"`, `"functions:write"`) for agent/CI principals; owner-gated, also reachable project-scoped as `r.project(id).grants` |
345
347
  | `events` | `list`, `listForOrg` — the cursored project events feed ("what happened since I last looked"): deploy activations, suspensions, transfers, lifecycle cliffs, each with platform-suggested `next_actions`, plus app-emitted business facts (`source: "app"`) alongside the platform's own (`source: "platform"`) — filter with `{ source?, eventType? }`. Opaque store-and-echo cursor; `reset: true` + `earliest_cursor` instead of errors on expiry. Also reachable project-scoped as `r.project(id).events` |
@@ -823,12 +825,12 @@ const minted = await r.gitvault.handoff({
823
825
  });
824
826
  console.log(minted.handoff_key); // kgh1_… — print it ALONE, this is the only copy
825
827
 
826
- // on another machine, with no shared keystore or allowance:
828
+ // on another machine, with no shared keystore or wallet:
827
829
  const resumed = await r.gitvault.resume({ key: "kgh1_…" });
828
830
  console.log(resumed.restored.dir); // the fresh checkout, dirty state reapplied
829
831
  ```
830
832
 
831
- **Invite / join — a second agent into the SAME work, dirty tree included (kygit-invite).** The second claim kind beside handoff/resume, sharing the same crypto/keystore/restore machinery, kind-parameterized: a Handoff passes the work on and the sender stops; an Invite grows the team while the sender keeps working. `r.gitvault.invite({ project_id, note, roomKey?, role?, ttlSeconds?, includeSensitive?, program?, model?, sessionKey? })` captures the checkpoint exactly like `handoff` — the inviter's own worktree, index, branch, refs, and access are all untouched — registers the inviter's OWN presence in the invite's room (the project's default room, or `roomKey` for a named org room) BEFORE minting, mints a single-use bearer `kgi1_<base64url(invite_id[16] ‖ master_secret[32])>` key (returned in `invite_key`, the ONLY copy), and posts ONE room message naming the checkpoint and invite id (never the key) — a presence or fact-post failure is reported in `inviter_presence`/`room_fact` and never voids the mint. `r.gitvault.join({ key, to?, program?, model?, sessionKey? })` claims it (a same-principal replay dedups safely), clones a fresh checkout, reapplies the checkpoint with `git stash apply --index`, pins the invite's OWN room locally (`r402.room`), registers this session's presence, posts ONE arrival message, and returns the inviter (name, labels, liveness), `live_presences`, the catch-up `cursor`, and the last few `recent_messages` — the joiner's first message needs no lookup. `r.gitvault.listInvites`/`revokeInvite` manage outstanding keys. A `kgh1_…` key handed to `join()`, or a `kgi1_…` key handed to `resume()`, is refused BY NAME (`INVITE_KEY_WRONG_KIND`/`HANDOFF_KEY_WRONG_KIND`) before any network call.
833
+ **Invite / join — a second agent into the SAME work, dirty tree included (kygit-invite).** The second claim kind beside handoff/resume, sharing the same crypto/keystore/restore machinery, kind-parameterized: a Handoff passes the work on and the sender stops; an Invite grows the team while the sender keeps working. `r.gitvault.invite({ project_id, note, roomKey?, role?, ttlSeconds?, includeSensitive?, program?, model?, sessionKey? })` captures the checkpoint exactly like `handoff` — the inviter's own worktree, index, branch, refs, and access are all untouched — registers the inviter's OWN presence in the invite's room (the project's default room, or `roomKey` for a named org room) BEFORE minting, mints a single-use bearer `kgi1_<base64url(invite_id[16] ‖ master_secret[32])>` key (returned in `invite_key`, the ONLY copy), and posts ONE room message naming the checkpoint and invite id (never the key) — a presence or fact-post failure is reported in `inviter_presence`/`room_message` and never voids the mint. `r.gitvault.join({ key, to?, program?, model?, sessionKey? })` claims it (a same-principal replay dedups safely), clones a fresh checkout, reapplies the checkpoint with `git stash apply --index`, pins the invite's OWN room locally (`r402.room`), registers this session's presence, posts ONE arrival message, and returns the inviter (name, labels, liveness), `live_presences`, the catch-up `cursor`, and the last few `recent_messages` — the joiner's first message needs no lookup. `r.gitvault.listInvites`/`revokeInvite` manage outstanding keys. A `kgh1_…` key handed to `join()`, or a `kgi1_…` key handed to `resume()`, is refused BY NAME (`INVITE_KEY_WRONG_KIND`/`HANDOFF_KEY_WRONG_KIND`) before any network call.
832
834
 
833
835
  ```ts
834
836
  const minted = await r.gitvault.invite({
@@ -837,7 +839,7 @@ const minted = await r.gitvault.invite({
837
839
  });
838
840
  console.log(minted.invite_key); // kgi1_… — print it ALONE, this is the only copy
839
841
 
840
- // on another machine, with no shared keystore or allowance:
842
+ // on another machine, with no shared keystore or wallet:
841
843
  const joined = await r.gitvault.join({ key: "kgi1_…" });
842
844
  console.log(joined.restored.dir); // the fresh checkout, dirty state reapplied
843
845
  console.log(joined.inviter?.name); // who invited you, and whether they're still live
@@ -39,7 +39,7 @@ export declare function getProfilesDir(): string;
39
39
  * The effective config directory for the *active* wallet. The `default` wallet
40
40
  * resolves to the base dir (zero migration for existing single-wallet
41
41
  * installs); any named wallet resolves to `{base}/profiles/<name>`. Because
42
- * keystore, allowance, and meta paths all derive from this, switching the
42
+ * keystore, wallet, and meta paths all derive from this, switching the
43
43
  * profile env var moves the whole wallet bundle atomically — and the SDK/MCP
44
44
  * inherit profile selection for free.
45
45
  */
@@ -57,5 +57,19 @@ export declare function configureApiBase(apiBase: string, options?: Omit<ApiTarg
57
57
  export declare function getConfiguredApiBase(): string | null;
58
58
  export declare function getApiTargetKind(): ApiTargetKind;
59
59
  export declare function isCoreApiTarget(): boolean;
60
- export declare function getAllowancePath(): string;
60
+ /**
61
+ * The file that holds a wallet's key, in the base config dir (the `default`
62
+ * wallet) and in each `profiles/<name>/` directory.
63
+ */
64
+ export declare const WALLET_FILE_NAME = "wallet.json";
65
+ /**
66
+ * One-time local move of the wallet key file to its current name: in the base
67
+ * config dir and every `profiles/<name>/` directory, `allowance.json` is
68
+ * renamed to `wallet.json` (an atomic same-directory rename) when
69
+ * `wallet.json` is absent, then tightened to 0600. A directory that already
70
+ * holds `wallet.json` is left untouched. Runs once per base dir per process;
71
+ * nothing reads the previous name afterwards.
72
+ */
73
+ export declare function moveWalletFiles(): void;
74
+ export declare function getWalletPath(): string;
61
75
  //# sourceMappingURL=config.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { homedir } from "node:os";
2
2
  import { dirname, join } from "node:path";
3
- import { existsSync, renameSync, mkdirSync, chmodSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { existsSync, renameSync, mkdirSync, chmodSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
4
4
  import { randomBytes } from "node:crypto";
5
5
  import { describeRejectedValue } from "./redact.js";
6
6
  export const DEFAULT_API_BASE = "https://api.run402.com";
@@ -118,7 +118,7 @@ export function getProfilesDir() {
118
118
  * The effective config directory for the *active* wallet. The `default` wallet
119
119
  * resolves to the base dir (zero migration for existing single-wallet
120
120
  * installs); any named wallet resolves to `{base}/profiles/<name>`. Because
121
- * keystore, allowance, and meta paths all derive from this, switching the
121
+ * keystore, wallet, and meta paths all derive from this, switching the
122
122
  * profile env var moves the whole wallet bundle atomically — and the SDK/MCP
123
123
  * inherit profile selection for free.
124
124
  */
@@ -232,27 +232,61 @@ export function isCoreApiTarget() {
232
232
  return true;
233
233
  return false;
234
234
  }
235
- export function getAllowancePath() {
236
- if (process.env.RUN402_ALLOWANCE_PATH)
237
- return process.env.RUN402_ALLOWANCE_PATH;
238
- const dir = getConfigDir();
239
- const newPath = join(dir, "allowance.json");
240
- const oldPath = join(dir, "wallet.json");
241
- // Auto-migrate from wallet.json → allowance.json. renameSync preserves the
242
- // source file's mode, so a legacy world-readable wallet.json (mode 0644)
243
- // would otherwise carry that mode forward and leave the private key
244
- // world-readable on a shared machine. Tighten to 0600 after the rename.
245
- if (!existsSync(newPath) && existsSync(oldPath)) {
246
- mkdirSync(dir, { recursive: true });
247
- renameSync(oldPath, newPath);
235
+ /**
236
+ * The file that holds a wallet's key, in the base config dir (the `default`
237
+ * wallet) and in each `profiles/<name>/` directory.
238
+ */
239
+ export const WALLET_FILE_NAME = "wallet.json";
240
+ /** The name the wallet key file had before it was `wallet.json`. */
241
+ const PREVIOUS_WALLET_FILE_NAME = "allowance.json";
242
+ const walletFilesMovedFor = new Set();
243
+ /**
244
+ * One-time local move of the wallet key file to its current name: in the base
245
+ * config dir and every `profiles/<name>/` directory, `allowance.json` is
246
+ * renamed to `wallet.json` (an atomic same-directory rename) when
247
+ * `wallet.json` is absent, then tightened to 0600. A directory that already
248
+ * holds `wallet.json` is left untouched. Runs once per base dir per process;
249
+ * nothing reads the previous name afterwards.
250
+ */
251
+ export function moveWalletFiles() {
252
+ const base = getConfigBaseDir();
253
+ if (walletFilesMovedFor.has(base))
254
+ return;
255
+ walletFilesMovedFor.add(base);
256
+ const dirs = [base];
257
+ try {
258
+ for (const entry of readdirSync(join(base, "profiles"), { withFileTypes: true })) {
259
+ if (entry.isDirectory())
260
+ dirs.push(join(base, "profiles", entry.name));
261
+ }
262
+ }
263
+ catch {
264
+ // No profiles directory yet.
265
+ }
266
+ for (const dir of dirs) {
267
+ const from = join(dir, PREVIOUS_WALLET_FILE_NAME);
268
+ const to = join(dir, WALLET_FILE_NAME);
269
+ if (existsSync(to) || !existsSync(from))
270
+ continue;
271
+ try {
272
+ renameSync(from, to);
273
+ }
274
+ catch {
275
+ continue;
276
+ }
248
277
  try {
249
- chmodSync(newPath, 0o600);
278
+ chmodSync(to, 0o600);
250
279
  }
251
280
  catch {
252
281
  // Best-effort (e.g. Windows / exotic filesystems). Read-time self-heal
253
- // in readAllowance() is the backstop.
282
+ // in readWallet() is the backstop.
254
283
  }
255
284
  }
256
- return newPath;
285
+ }
286
+ export function getWalletPath() {
287
+ if (process.env.RUN402_WALLET_PATH)
288
+ return process.env.RUN402_WALLET_PATH;
289
+ moveWalletFiles();
290
+ return join(getConfigDir(), WALLET_FILE_NAME);
257
291
  }
258
292
  //# sourceMappingURL=config.js.map
@@ -1,33 +1,40 @@
1
1
  /**
2
- * A cached **control-plane session** — the human principal's bearer, minted by
3
- * the loopback-PKCE flow (`run402 operator login --loopback`). Distinct from the
4
- * device-flow {@link OperatorSession} (read-only): this one carries `provenance`
5
- * (`loopback_pkce`) and `amr`. It authorizes most control-plane operations, but
6
- * since gateway v1.85/v1.87 it is NOT sufficient on its own for the high-stakes
7
- * writes `provision` / `deploy` / secrets — those additionally require a
8
- * passkey-fresh **operator approval** (`X-Run402-Write-Auth`, minted by
9
- * `run402 operator approve`; see {@link WriteAuthApproval}). Cached at the BASE
10
- * config dir (email/principal-scoped, shared across local named wallets), mode
11
- * 0600 — the token is as sensitive as the allowance key.
2
+ * The cached **sign-in session** — a person's one Run402 session, bound to
3
+ * their principal and graded by how it was minted: `loopback` (`run402 login`,
4
+ * the loopback-PKCE browser ceremony; full, step-up-able) or `device`
5
+ * (`run402 login --device`, RFC 8628; read-only — the gateway refuses every
6
+ * mutation with `SESSION_READ_ONLY`). The wire token class is
7
+ * `control_plane_session`. The session authorizes most control-plane writes,
8
+ * but provisioning, deploying, and writing secrets additionally need a
9
+ * passkey-signed **write approval** (`X-Run402-Write-Approval`, minted by
10
+ * `run402 approve`; see `write-approvals.ts`). Cached at the BASE config dir
11
+ * (principal-scoped, shared across local named wallets), mode 0600 — the token
12
+ * is as sensitive as the wallet key.
12
13
  *
13
14
  * Stored shape vs the gateway payload: the gateway returns a relative
14
15
  * `expires_in` (seconds); we persist the absolute `expires_at` (epoch ms) so a
15
16
  * cached session can be expiry-checked without knowing when it was written.
16
17
  */
18
+ /** How a sign-in session was minted, as the gateway reports it. */
19
+ export type SessionGrade = "browser" | "loopback" | "device";
17
20
  export interface ControlPlaneSessionCache {
18
21
  control_plane_session_token: string;
19
22
  token_type: string;
20
- provenance: string;
23
+ grade: SessionGrade;
21
24
  principal_id: string;
22
25
  amr: string[];
23
26
  /** Epoch ms when the session expires (issued_at + expires_in). */
24
27
  expires_at: number;
25
28
  }
26
- /** The token payload returned by `POST /agent/v1/control-plane/cli/token`. */
29
+ /**
30
+ * The token payload returned by `POST /agent/v1/control-plane/cli/token`
31
+ * (grade `loopback`) and `POST /agent/v1/control-plane/cli/device/token`
32
+ * (grade `device`).
33
+ */
27
34
  export interface ControlPlaneSessionTokenResponse {
28
35
  control_plane_session_token: string;
29
36
  token_type?: string;
30
- provenance?: string;
37
+ grade?: string;
31
38
  principal_id?: string;
32
39
  amr?: string[];
33
40
  expires_in?: number;
@@ -45,7 +52,7 @@ export declare function getControlPlaneSessionPath(): string;
45
52
  export declare function readControlPlaneSession(path?: string): ControlPlaneSessionCache | null;
46
53
  /** Persist a control-plane session atomically (temp-file + rename), mode 0600. */
47
54
  export declare function saveControlPlaneSession(data: ControlPlaneSessionCache, path?: string): void;
48
- /** Delete the cached control-plane session — local half of `operator logout`. Idempotent. */
55
+ /** Delete the cached sign-in session — local half of `run402 logout`. Idempotent. */
49
56
  export declare function clearControlPlaneSession(path?: string): void;
50
57
  /** Whether a cached session is past its usable life (with a small skew buffer). */
51
58
  export declare function isControlPlaneSessionExpired(session: ControlPlaneSessionCache, nowMs?: number, skewMs?: number): boolean;
@@ -53,4 +60,12 @@ export declare function isControlPlaneSessionExpired(session: ControlPlaneSessio
53
60
  export declare function loadLiveControlPlaneSession(path?: string, nowMs?: number): ControlPlaneSessionCache | null;
54
61
  /** Map a gateway token payload (relative `expires_in`) into the cached shape (absolute `expires_at`). */
55
62
  export declare function controlPlaneSessionFromTokenResponse(resp: ControlPlaneSessionTokenResponse, nowMs?: number): ControlPlaneSessionCache;
63
+ /**
64
+ * Delete the session caches of the retired email-scoped session
65
+ * (`{base}/operator-session.json`) and the retired approval cache file
66
+ * (`{base}/write-auth-session.json`). Neither is read any more; `run402 login`
67
+ * and `run402 logout` call this so a stale token does not linger on disk.
68
+ * Best-effort and idempotent.
69
+ */
70
+ export declare function clearRetiredSessionCaches(): void;
56
71
  //# sourceMappingURL=control-plane-session.d.ts.map
@@ -10,6 +10,14 @@ export function getControlPlaneSessionPath() {
10
10
  return (process.env.RUN402_CONTROL_PLANE_SESSION_PATH ||
11
11
  join(getConfigBaseDir(), "control-plane-session.json"));
12
12
  }
13
+ /**
14
+ * Read a wire grade. An unknown or absent value is treated as `device` (the
15
+ * read-only grade) so a cache the client cannot classify never claims more
16
+ * authority than the gateway will grant.
17
+ */
18
+ function toGrade(raw) {
19
+ return raw === "browser" || raw === "loopback" || raw === "device" ? raw : "device";
20
+ }
13
21
  /** Tighten 0600 if group/other-readable, warning once. Best-effort, POSIX-only. */
14
22
  function selfHealPermissions(p) {
15
23
  if (process.platform === "win32")
@@ -50,20 +58,20 @@ export function readControlPlaneSession(path) {
50
58
  return null;
51
59
  }
52
60
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
53
- throw new Error("control-plane-session.json must contain a JSON object. Delete it and run 'run402 operator login --loopback' to recreate it.");
61
+ throw new Error("control-plane-session.json must contain a JSON object. Delete it and run 'run402 login' to recreate it.");
54
62
  }
55
63
  const data = parsed;
56
64
  if (typeof data.control_plane_session_token !== "string" ||
57
65
  data.control_plane_session_token.length === 0) {
58
- throw new Error("control-plane-session.json missing valid 'control_plane_session_token'. Run 'run402 operator login --loopback' to refresh it.");
66
+ throw new Error("control-plane-session.json missing valid 'control_plane_session_token'. Run 'run402 login' to refresh it.");
59
67
  }
60
68
  if (typeof data.expires_at !== "number" || !Number.isFinite(data.expires_at)) {
61
- throw new Error("control-plane-session.json missing valid 'expires_at'. Run 'run402 operator login --loopback' to refresh it.");
69
+ throw new Error("control-plane-session.json missing valid 'expires_at'. Run 'run402 login' to refresh it.");
62
70
  }
63
71
  return {
64
72
  control_plane_session_token: data.control_plane_session_token,
65
73
  token_type: typeof data.token_type === "string" ? data.token_type : "Bearer",
66
- provenance: typeof data.provenance === "string" ? data.provenance : "loopback_pkce",
74
+ grade: toGrade(data.grade),
67
75
  principal_id: typeof data.principal_id === "string" ? data.principal_id : "",
68
76
  amr: Array.isArray(data.amr) ? data.amr.filter((a) => typeof a === "string") : [],
69
77
  expires_at: data.expires_at,
@@ -79,7 +87,7 @@ export function saveControlPlaneSession(data, path) {
79
87
  renameSync(tmp, p);
80
88
  chmodSync(p, 0o600);
81
89
  }
82
- /** Delete the cached control-plane session — local half of `operator logout`. Idempotent. */
90
+ /** Delete the cached sign-in session — local half of `run402 logout`. Idempotent. */
83
91
  export function clearControlPlaneSession(path) {
84
92
  const p = path ?? getControlPlaneSessionPath();
85
93
  try {
@@ -105,10 +113,27 @@ export function controlPlaneSessionFromTokenResponse(resp, nowMs = Date.now()) {
105
113
  return {
106
114
  control_plane_session_token: resp.control_plane_session_token,
107
115
  token_type: resp.token_type ?? "Bearer",
108
- provenance: resp.provenance ?? "loopback_pkce",
116
+ grade: toGrade(resp.grade),
109
117
  principal_id: resp.principal_id ?? "",
110
118
  amr: Array.isArray(resp.amr) ? resp.amr.filter((a) => typeof a === "string") : [],
111
119
  expires_at: nowMs + (typeof resp.expires_in === "number" ? resp.expires_in : 0) * 1000,
112
120
  };
113
121
  }
122
+ /**
123
+ * Delete the session caches of the retired email-scoped session
124
+ * (`{base}/operator-session.json`) and the retired approval cache file
125
+ * (`{base}/write-auth-session.json`). Neither is read any more; `run402 login`
126
+ * and `run402 logout` call this so a stale token does not linger on disk.
127
+ * Best-effort and idempotent.
128
+ */
129
+ export function clearRetiredSessionCaches() {
130
+ for (const name of ["operator-session.json", "write-auth-session.json"]) {
131
+ try {
132
+ rmSync(join(getConfigBaseDir(), name), { force: true });
133
+ }
134
+ catch {
135
+ // Best-effort: a failed unlink never blocks login or logout.
136
+ }
137
+ }
138
+ }
114
139
  //# sourceMappingURL=control-plane-session.js.map
@@ -3,7 +3,7 @@ import { dirname, join } from "node:path";
3
3
  import { randomBytes } from "node:crypto";
4
4
  import { getLegacyProjectsPath, getProjectCredentialsPath } from "./config.js";
5
5
  import { clearActiveProjectId as clearProfileActiveProjectId, getActiveProjectId as getProfileActiveProjectId, recordMigration, setActiveProjectId as setProfileActiveProjectId, } from "./profile-state.js";
6
- import { readAllowance } from "./allowance.js";
6
+ import { readWallet } from "./wallet.js";
7
7
  function withFileLock(path, fn, { retries = 200, delayMs = 20 } = {}) {
8
8
  const lockDir = path + ".lock";
9
9
  mkdirSync(dirname(path), { recursive: true });
@@ -99,7 +99,7 @@ function migrateLegacyProjectsJson(targetPath) {
99
99
  // Scoped the same way every other write in this module now is (see
100
100
  // `currentPrincipal`'s doc comment) — an unscoped write here is exactly
101
101
  // what poisons the "unknown"-principal bucket for good on a machine that
102
- // migrates before its wallet allowance exists yet.
102
+ // migrates before its wallet exists yet.
103
103
  setProfileActiveProjectId(legacy.active_project_id, undefined, { principal: currentPrincipal() });
104
104
  }
105
105
  recordMigration("projects_json_import", {
@@ -174,7 +174,7 @@ export function removeProject(projectId, path) {
174
174
  }
175
175
  /**
176
176
  * The active-project scope's `principal`, derived from the CURRENT wallet's
177
- * allowance — matching exactly what `NodeCredentialsProvider.setActiveProject`
177
+ * wallet — matching exactly what `NodeCredentialsProvider.setActiveProject`
178
178
  * (sdk/src/node/credentials.ts) writes after `projects.provision` /
179
179
  * `projects.use`. Without this, every reader here used the profile-state
180
180
  * module's own default (empty) scope, which resolves to a FIXED
@@ -185,7 +185,7 @@ export function removeProject(projectId, path) {
185
185
  * `profile-state.ts#getActiveProjectId` happens to agree), but once the
186
186
  * "unknown" bucket is EVER populated by any principal-less write — the
187
187
  * one-time legacy `projects.json` migration below, or any provision/`use`
188
- * call made before this machine had a wallet allowance — it never gets
188
+ * call made before this machine had a wallet — it never gets
189
189
  * updated again (real wallet operations write to the principal-keyed
190
190
  * bucket, not "unknown") and PERMANENTLY shadows every later wallet-scoped
191
191
  * activation for every caller that reads through this module: `resolveProjectId`
@@ -197,13 +197,13 @@ export function removeProject(projectId, path) {
197
197
  * stale "unknown"-bucket entry first and never falls through to the
198
198
  * freshly-updated flat value.
199
199
  *
200
- * Best-effort: an unreadable/malformed allowance degrades to `null` (the
200
+ * Best-effort: an unreadable/malformed wallet degrades to `null` (the
201
201
  * "unknown" bucket callers tolerate), never a
202
- * throw — this is a read-scoping concern, not an allowance-validity one.
202
+ * throw — this is a read-scoping concern, not a wallet-validity one.
203
203
  */
204
204
  function currentPrincipal() {
205
205
  try {
206
- return readAllowance()?.address ?? null;
206
+ return readWallet()?.address ?? null;
207
207
  }
208
208
  catch {
209
209
  return null;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * A "wallet" is a whole config directory. The reserved `default` wallet lives
5
5
  * at the base config dir (zero migration for existing installs); every named
6
- * wallet lives under `{base}/profiles/<name>/` with its own `allowance.json`,
6
+ * wallet lives under `{base}/profiles/<name>/` with its own `wallet.json`,
7
7
  * `projects.json`, and this module's non-secret `meta.json`.
8
8
  *
9
9
  * Two levels of active state, mirroring the wallet → project model:
@@ -40,10 +40,10 @@ export declare function profileDir(name: string): string;
40
40
  export declare function ensureProfileDir(name: string): string;
41
41
  export declare function readMeta(name: string): ProfileMeta | null;
42
42
  export declare function writeMeta(name: string, meta: ProfileMeta): void;
43
- /** True when a wallet's `allowance.json` exists on disk. */
43
+ /** True when a wallet's `wallet.json` exists on disk. */
44
44
  export declare function profileExists(name: string): boolean;
45
45
  /**
46
- * All wallet names on disk: `default` (only if a root allowance.json exists)
46
+ * All wallet names on disk: `default` (only if a root wallet.json exists)
47
47
  * plus every valid directory under `profiles/`.
48
48
  */
49
49
  export declare function listProfileNames(): string[];
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * A "wallet" is a whole config directory. The reserved `default` wallet lives
5
5
  * at the base config dir (zero migration for existing installs); every named
6
- * wallet lives under `{base}/profiles/<name>/` with its own `allowance.json`,
6
+ * wallet lives under `{base}/profiles/<name>/` with its own `wallet.json`,
7
7
  * `projects.json`, and this module's non-secret `meta.json`.
8
8
  *
9
9
  * Two levels of active state, mirroring the wallet → project model:
@@ -17,7 +17,7 @@
17
17
  import { readFileSync, writeFileSync, mkdirSync, renameSync, chmodSync, existsSync, readdirSync, rmSync, } from "node:fs";
18
18
  import { dirname, join } from "node:path";
19
19
  import { randomBytes } from "node:crypto";
20
- import { getConfigBaseDir, getProfilesDir, DEFAULT_PROFILE, isValidProfileName, } from "./config.js";
20
+ import { getConfigBaseDir, getProfilesDir, DEFAULT_PROFILE, isValidProfileName, moveWalletFiles, WALLET_FILE_NAME, } from "./config.js";
21
21
  import { describeRejectedValue } from "./redact.js";
22
22
  function atomicWrite(p, content, mode) {
23
23
  const dir = dirname(p);
@@ -114,17 +114,19 @@ export function writeMeta(name, meta) {
114
114
  atomicWrite(metaPath(name), JSON.stringify(meta, null, 2), 0o600);
115
115
  }
116
116
  // --- enumeration + lifecycle ---
117
- /** True when a wallet's `allowance.json` exists on disk. */
117
+ /** True when a wallet's `wallet.json` exists on disk. */
118
118
  export function profileExists(name) {
119
- return existsSync(join(profileDir(name), "allowance.json"));
119
+ moveWalletFiles();
120
+ return existsSync(join(profileDir(name), WALLET_FILE_NAME));
120
121
  }
121
122
  /**
122
- * All wallet names on disk: `default` (only if a root allowance.json exists)
123
+ * All wallet names on disk: `default` (only if a root wallet.json exists)
123
124
  * plus every valid directory under `profiles/`.
124
125
  */
125
126
  export function listProfileNames() {
127
+ moveWalletFiles();
126
128
  const names = [];
127
- if (existsSync(join(getConfigBaseDir(), "allowance.json"))) {
129
+ if (existsSync(join(getConfigBaseDir(), WALLET_FILE_NAME))) {
128
130
  names.push(DEFAULT_PROFILE);
129
131
  }
130
132
  try {
@@ -184,7 +186,7 @@ export function renameProfile(oldName, newName) {
184
186
  /* best-effort */
185
187
  }
186
188
  const base = getConfigBaseDir();
187
- for (const f of ["allowance.json", "projects.json", "meta.json"]) {
189
+ for (const f of [WALLET_FILE_NAME, "projects.json", "meta.json"]) {
188
190
  const src = join(base, f);
189
191
  if (existsSync(src))
190
192
  renameSync(src, join(dest, f));
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Allowance auth helper — generates SIWX (Sign-In With X / EIP-4361) headers for Run402 API.
2
+ * SIWX auth helper — generates SIWX (Sign-In With X / EIP-4361) headers for Run402 API.
3
3
  * Uses @noble/curves (lighter than viem) for signing.
4
4
  */
5
- import type { AllowanceData } from "./allowance.js";
5
+ import type { WalletData } from "./wallet.js";
6
6
  export interface SIWxAuthHeaders {
7
7
  "SIGN-IN-WITH-X": string;
8
8
  }
@@ -22,7 +22,7 @@ interface SIWEMessageOpts {
22
22
  resources?: string[];
23
23
  }
24
24
  export interface SIWxAuthOptions extends SIWEMessageOpts {
25
- allowance: Pick<AllowanceData, "address" | "privateKey">;
25
+ wallet: Pick<WalletData, "address" | "privateKey">;
26
26
  type?: "eip191";
27
27
  }
28
28
  /**
@@ -33,10 +33,10 @@ export declare function formatSIWEMessage(opts: SIWEMessageOpts, address: string
33
33
  export declare function buildSIWxAuthHeaders(opts: SIWxAuthOptions): SIWxAuthHeaders;
34
34
  /**
35
35
  * Get SIWX auth headers for the Run402 API.
36
- * Returns null if no allowance is configured.
36
+ * Returns null if no local wallet is configured.
37
37
  *
38
38
  * @param path - API path (e.g. "/projects/v1") used to build the SIWE uri field.
39
39
  */
40
- export declare function getAllowanceAuthHeaders(path: string, allowancePath?: string): SIWxAuthHeaders | null;
40
+ export declare function getWalletAuthHeaders(path: string, walletPath?: string): SIWxAuthHeaders | null;
41
41
  export {};
42
- //# sourceMappingURL=allowance-auth.d.ts.map
42
+ //# sourceMappingURL=wallet-auth.d.ts.map