@forgezero/vault 0.1.2 → 0.1.3

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/README.md CHANGED
@@ -2,10 +2,11 @@
2
2
 
3
3
  **Read your secrets at runtime instead of shipping them in a file.**
4
4
 
5
- The client discovers its own credential and, for an API key, asks a directory
6
- which node to talk to. There is no endpoint to configure. The same code runs on
7
- a laptop and in production: outside managed compute the key is a local signing
8
- seed; on managed compute there is no remote credential in the application.
5
+ The client discovers its own credential and uses one stable API origin. Node
6
+ routing and failover stay behind that edge contract; the SDK never discovers or
7
+ stores a node hostname. The same code runs on a laptop and in production:
8
+ outside managed compute the key is a local signing seed; on managed compute
9
+ there is no remote credential in the application.
9
10
 
10
11
  This one talks to a ForgeZero vault, so it needs an account. The other three
11
12
  packages do not.
@@ -56,8 +57,10 @@ An entry can declare fields the tenant never holds. Two custody modes:
56
57
  exists in plaintext only inside a signing call.
57
58
  - **supplied** — you generate it, the vault seals it.
58
59
 
59
- Either way there is no call that returns a private key. Custody operations stay
60
- on the authenticated platform surface; the application credential is read-only.
60
+ Either way there is no call that returns a private key. Derivation and signing
61
+ stay inside explicit trusted platform workflows; the general application
62
+ credential remains a read-only secret client and is not a transaction-signing
63
+ oracle.
61
64
 
62
65
  ## Subpaths
63
66
 
package/dist/index.d.ts CHANGED
@@ -156,41 +156,35 @@ export declare class ForgeZero {
156
156
  */
157
157
  getAll(): Promise<Record<string, string>>;
158
158
  /**
159
- * The PUBLIC half of a value ForgeZero derived from the realm master seed.
159
+ * Custody derivation is intentionally not a general application-key action.
160
160
  *
161
- * There is no call that returns the private half, and that is the whole
162
- * design rather than an omission. A tenant that can fetch a signing key holds
163
- * the full risk of holding one: it lands in their backups, their logs, their
164
- * heap dumps and their environment. Here they declare which chain they
165
- * activated, the platform derives from the seed, and an ADDRESS is the only
166
- * thing that crosses back.
161
+ * Kept as a typed refusal for compatibility with the early package preview,
162
+ * which exposed this method before a secured custody workflow existed. A
163
+ * compromised secret-reading process must not silently become a transaction
164
+ * signer merely because both operations happen to involve the vault.
167
165
  *
168
- * Deterministic, so losing the row loses the metadata and not the money —
169
- * re-declaring the same chain and index derives the same address.
166
+ * @deprecated Use an explicit platform custody workflow with its own policy,
167
+ * approval and audit contract.
170
168
  */
171
169
  derived(name: string, field: string): Promise<{
172
170
  address: string;
173
171
  path: string;
174
172
  }>;
175
173
  /**
176
- * Sign a digest with a derived key, without the key ever leaving.
177
- *
178
- * The tenant builds the unsigned transaction, hashes it, and sends the
179
- * digest. What comes back is a signature. A compromised tenant process can
180
- * ASK for signatures — which is bounded, logged and revocable — and cannot
181
- * take the key, which would be none of those things.
182
- *
183
- * A digest rather than a transaction on purpose: the platform is not a
184
- * transaction builder for every chain a tenant might use, and pretending
185
- * otherwise would make ForgeZero the thing that has to understand every
186
- * chain format before a tenant can support one.
174
+ * @deprecated A general application vault credential is not a signing oracle.
187
175
  */
188
176
  sign(name: string, field: string, digest: string): Promise<{
189
177
  signature: string;
190
178
  recovery?: number;
191
179
  path: string;
192
180
  }>;
193
- /** Schemas the platform holds, for a managed source. */
181
+ /**
182
+ * List schemas represented by reserved vault entries.
183
+ *
184
+ * Kept for compatibility; `managedSchemas(vault).list()` is the higher-level
185
+ * interface. It deliberately uses `list` and `get`, so both the local agent
186
+ * and signed HTTPS transports follow the same contract.
187
+ */
194
188
  schemas(): Promise<readonly {
195
189
  name: string;
196
190
  version: number;
package/dist/index.js CHANGED
@@ -254,14 +254,28 @@ class ForgeZero {
254
254
  return result.values;
255
255
  }
256
256
  async derived(name, field) {
257
- return this.request(`/v1/entries/${encodeURIComponent(name)}/derived/${encodeURIComponent(field)}${this.scope()}`);
257
+ throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Derived custody keys require an explicit platform custody workflow; an application vault credential cannot request them.");
258
258
  }
259
259
  async sign(name, field, digest) {
260
- return this.request(`/v1/entries/${encodeURIComponent(name)}/sign/${encodeURIComponent(field)}${this.scope()}`, { method: "POST", body: JSON.stringify({ digest }) });
260
+ throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Signing requires an explicit platform custody workflow with its own policy, approval and audit contract.");
261
261
  }
262
262
  async schemas() {
263
- const payload = await this.request(`/v1/schemas${this.scope()}`);
264
- return payload.schemas ?? [];
263
+ const entries = await this.list();
264
+ const names = entries.map((entry) => entry.name).filter((name) => name.startsWith("__schema__")).map((name) => name.slice("__schema__".length)).filter(Boolean);
265
+ return Promise.all(names.map(async (name) => {
266
+ let value;
267
+ try {
268
+ value = JSON.parse(await this.get(`__schema__${name}`));
269
+ } catch (cause) {
270
+ if (cause instanceof VaultError)
271
+ throw cause;
272
+ throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} is not JSON.`);
273
+ }
274
+ if (!Number.isInteger(value.version) || Number(value.version) < 1) {
275
+ throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} has no valid version.`);
276
+ }
277
+ return { name, version: Number(value.version) };
278
+ }));
265
279
  }
266
280
  async list() {
267
281
  const result = await this.request(`/v1/vault/${this.scope()}/list`);
package/dist/providers.js CHANGED
@@ -254,14 +254,28 @@ class ForgeZero {
254
254
  return result.values;
255
255
  }
256
256
  async derived(name, field) {
257
- return this.request(`/v1/entries/${encodeURIComponent(name)}/derived/${encodeURIComponent(field)}${this.scope()}`);
257
+ throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Derived custody keys require an explicit platform custody workflow; an application vault credential cannot request them.");
258
258
  }
259
259
  async sign(name, field, digest) {
260
- return this.request(`/v1/entries/${encodeURIComponent(name)}/sign/${encodeURIComponent(field)}${this.scope()}`, { method: "POST", body: JSON.stringify({ digest }) });
260
+ throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Signing requires an explicit platform custody workflow with its own policy, approval and audit contract.");
261
261
  }
262
262
  async schemas() {
263
- const payload = await this.request(`/v1/schemas${this.scope()}`);
264
- return payload.schemas ?? [];
263
+ const entries = await this.list();
264
+ const names = entries.map((entry) => entry.name).filter((name) => name.startsWith("__schema__")).map((name) => name.slice("__schema__".length)).filter(Boolean);
265
+ return Promise.all(names.map(async (name) => {
266
+ let value;
267
+ try {
268
+ value = JSON.parse(await this.get(`__schema__${name}`));
269
+ } catch (cause) {
270
+ if (cause instanceof VaultError)
271
+ throw cause;
272
+ throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} is not JSON.`);
273
+ }
274
+ if (!Number.isInteger(value.version) || Number(value.version) < 1) {
275
+ throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} has no valid version.`);
276
+ }
277
+ return { name, version: Number(value.version) };
278
+ }));
265
279
  }
266
280
  async list() {
267
281
  const result = await this.request(`/v1/vault/${this.scope()}/list`);
package/dist/schema.d.ts CHANGED
@@ -49,9 +49,7 @@ export interface SchemaSource {
49
49
  * platform being up. `refresh` exists so a long-lived process can pick up a
50
50
  * change without restarting.
51
51
  */
52
- export declare function managedSchemas(vault: Pick<ForgeZero, 'get'> & {
53
- schemas?: () => Promise<readonly SchemaRef[]>;
54
- }, options?: {
52
+ export declare function managedSchemas(vault: Pick<ForgeZero, 'get' | 'list'>, options?: {
55
53
  ttlMs?: number;
56
54
  now?: () => number;
57
55
  }): SchemaSource & {
package/dist/schema.js CHANGED
@@ -254,14 +254,28 @@ class ForgeZero {
254
254
  return result.values;
255
255
  }
256
256
  async derived(name, field) {
257
- return this.request(`/v1/entries/${encodeURIComponent(name)}/derived/${encodeURIComponent(field)}${this.scope()}`);
257
+ throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Derived custody keys require an explicit platform custody workflow; an application vault credential cannot request them.");
258
258
  }
259
259
  async sign(name, field, digest) {
260
- return this.request(`/v1/entries/${encodeURIComponent(name)}/sign/${encodeURIComponent(field)}${this.scope()}`, { method: "POST", body: JSON.stringify({ digest }) });
260
+ throw new VaultError("CUSTODY_WORKFLOW_REQUIRED", "Signing requires an explicit platform custody workflow with its own policy, approval and audit contract.");
261
261
  }
262
262
  async schemas() {
263
- const payload = await this.request(`/v1/schemas${this.scope()}`);
264
- return payload.schemas ?? [];
263
+ const entries = await this.list();
264
+ const names = entries.map((entry) => entry.name).filter((name) => name.startsWith("__schema__")).map((name) => name.slice("__schema__".length)).filter(Boolean);
265
+ return Promise.all(names.map(async (name) => {
266
+ let value;
267
+ try {
268
+ value = JSON.parse(await this.get(`__schema__${name}`));
269
+ } catch (cause) {
270
+ if (cause instanceof VaultError)
271
+ throw cause;
272
+ throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} is not JSON.`);
273
+ }
274
+ if (!Number.isInteger(value.version) || Number(value.version) < 1) {
275
+ throw new VaultError("SCHEMA_MALFORMED", `The schema for ${name} has no valid version.`);
276
+ }
277
+ return { name, version: Number(value.version) };
278
+ }));
265
279
  }
266
280
  async list() {
267
281
  const result = await this.request(`/v1/vault/${this.scope()}/list`);
@@ -362,7 +376,12 @@ function managedSchemas(vault, options = {}) {
362
376
  return value;
363
377
  },
364
378
  async list() {
365
- return await vault.schemas?.() ?? [];
379
+ const entries = await vault.list();
380
+ const names = entries.map((entry) => entry.name).filter((name) => name.startsWith("__schema__")).map((name) => name.slice("__schema__".length)).filter(Boolean);
381
+ return Promise.all(names.map(async (name) => {
382
+ const resolved = await this.get(name);
383
+ return { name, version: resolved.version };
384
+ }));
366
385
  }
367
386
  };
368
387
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "Publishing happens from an operator's machine, not CI \u2014 CLAUDE.md records that the absence of CI is deliberate. npm's `provenance` attests a tarball was built by a recognised CI provider from a named commit, so it cannot be produced here: it was set, and the first publish failed with `Automatic provenance generation not supported for provider: null`. A setting that can never be satisfied is worse than none, because it reads as a guarantee nobody is getting. Restore it the day this publishes from CI, and not before.",
3
3
  "name": "@forgezero/vault",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public"