@onesi/genesis 0.2.5 → 0.2.6

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
@@ -3,7 +3,7 @@
3
3
  The TypeScript SDK for OneOS. One typed client for every Genesis service, through the Genesis API at `https://os.one.ml/api`.
4
4
 
5
5
  ```sh
6
- npm install @onesi/genesis@0.2.5
6
+ npm install @onesi/genesis@0.2.6
7
7
  ```
8
8
 
9
9
  ```ts
package/dist/client.d.ts CHANGED
@@ -41,12 +41,14 @@ export declare class GenesisClient {
41
41
  constructor(opts?: GenesisOptions);
42
42
  static operations: Readonly<Record<OperationId, OperationMeta>>;
43
43
  static services: import("./types.js").ServiceMeta[];
44
- /** This client's one read of the selected context's Hives binding (cleared on failure). */
44
+ /** This client's cached read of the selected context's Hives binding: kept HIVES_BINDING_TTL_MS, cleared on failure and on every link or detach. */
45
45
  private hivesBinding?;
46
46
  /**
47
47
  * The Hives project id (prj_…) for a Hives project argument. A prj_… id is returned unchanged. Omitted, or the
48
48
  * Genesis pr_… id of the selected context's project, it resolves to the Hives project bound to that selection
49
- * (`hives_get_context_project`, read at most once per client); otherwise a GenesisError says how to find the prj_… id.
49
+ * (`hives_get_context_project`). The binding is cached for 60 s; a pr_… id that does not match a cached binding reads
50
+ * the selection again before it is refused, so each call makes at most one context read. Otherwise a GenesisError
51
+ * says how to find the prj_… id.
50
52
  */
51
53
  hivesProjectId(project_id?: string, init?: {
52
54
  signal?: AbortSignal;
package/dist/client.js CHANGED
@@ -56,6 +56,8 @@ export function scrubError(e, depth = 0) {
56
56
  fresh.stack = stack;
57
57
  return fresh;
58
58
  }
59
+ /** How long a client reuses its read of the selected context's Hives binding. */
60
+ const HIVES_BINDING_TTL_MS = 60_000;
59
61
  export class GenesisClient {
60
62
  /** The configured gateway root, kept without userinfo so it is safe to log or print. */
61
63
  get baseUrl() { return stripUserinfo(this.root); }
@@ -76,20 +78,29 @@ export class GenesisClient {
76
78
  }
77
79
  static operations = operationTable;
78
80
  static services = services;
79
- /** This client's one read of the selected context's Hives binding (cleared on failure). */
81
+ /** This client's cached read of the selected context's Hives binding: kept HIVES_BINDING_TTL_MS, cleared on failure and on every link or detach. */
80
82
  hivesBinding;
81
83
  /**
82
84
  * The Hives project id (prj_…) for a Hives project argument. A prj_… id is returned unchanged. Omitted, or the
83
85
  * Genesis pr_… id of the selected context's project, it resolves to the Hives project bound to that selection
84
- * (`hives_get_context_project`, read at most once per client); otherwise a GenesisError says how to find the prj_… id.
86
+ * (`hives_get_context_project`). The binding is cached for 60 s; a pr_… id that does not match a cached binding reads
87
+ * the selection again before it is refused, so each call makes at most one context read. Otherwise a GenesisError
88
+ * says how to find the prj_… id.
85
89
  */
86
90
  async hivesProjectId(project_id, init = {}) {
87
- return resolveHivesProjectId(project_id, () => {
88
- const read = this.hivesBinding ??= this.request('hives_get_context_project', {}, { signal: init.signal });
89
- read.catch(() => { if (this.hivesBinding === read)
91
+ let readHere = false;
92
+ const read = (fresh) => {
93
+ const cached = this.hivesBinding;
94
+ if (cached && !fresh && Date.now() - cached.at < HIVES_BINDING_TTL_MS)
95
+ return cached.read;
96
+ readHere = true;
97
+ const entry = { read: this.request('hives_get_context_project', {}, { signal: init.signal }), at: Date.now() };
98
+ this.hivesBinding = entry;
99
+ entry.read.catch(() => { if (this.hivesBinding === entry)
90
100
  this.hivesBinding = undefined; });
91
- return read;
92
- });
101
+ return entry.read;
102
+ };
103
+ return resolveHivesProjectId(project_id, () => read(false), () => readHere ? undefined : read(true));
93
104
  }
94
105
  /** Resolve the credential: explicit apiKey > token > env GENESIS_API_KEY > GENESIS_TOKEN > provider. */
95
106
  async credential() {
@@ -203,6 +214,16 @@ export class GenesisClient {
203
214
  // A Genesis pr_… id where Hives wants its own prj_… id would only be a remote 404: refuse it before any request.
204
215
  if (isGenesisProjectId(input.project_id) && isHivesProjectOperation(operationTable[operationId]))
205
216
  throw hivesProjectIdRefusal(input.project_id, operationId);
217
+ // Linking or detaching the selection changes its Hives binding: drop the cached read before and after, whatever the outcome.
218
+ if (operationId === 'hives_set_context_project' || operationId === 'hives_detach_context_project') {
219
+ this.hivesBinding = undefined;
220
+ try {
221
+ return await this.dispatch(operationId, input, init);
222
+ }
223
+ finally {
224
+ this.hivesBinding = undefined;
225
+ }
226
+ }
206
227
  if (!isIamDirectoryOperation(operationId))
207
228
  return this.dispatch(operationId, input, init);
208
229
  // The gateway binds the organization context itself. A refusal is only explained here; the client never changes a session or its context.
@@ -245,7 +266,7 @@ export class GenesisClient {
245
266
  const url = this.url(operationId, input);
246
267
  const headers = {
247
268
  accept: 'application/json',
248
- 'user-agent': this.opts.userAgent ?? '@onesi/genesis/0.2.5',
269
+ 'user-agent': this.opts.userAgent ?? '@onesi/genesis/0.2.6',
249
270
  ...this.opts.headers, ...init.headers,
250
271
  };
251
272
  if (op.service === 'blinds' && !['GET', 'HEAD', 'OPTIONS'].includes(op.method))
package/dist/errors.js CHANGED
@@ -90,7 +90,7 @@ function backendCode(body) {
90
90
  && typeof body.error !== 'string' && !authorizationCode(body) ? body.code : undefined;
91
91
  return envelope !== undefined && !(own && /^UPSTREAM_\d{3}$/.test(envelope)) ? envelope : own;
92
92
  }
93
- const statusType = (s) => s === 401 ? 'unauthorized' : s === 403 ? 'forbidden' : s === 404 ? 'not_found' : s === 429 ? 'rate_limited' : s >= 500 ? 'upstream_error' : 'error';
93
+ const statusType = (s) => s === 401 ? 'unauthorized' : s === 403 ? 'forbidden' : s === 404 ? 'not_found' : s === 410 ? 'gone' : s === 429 ? 'rate_limited' : s >= 500 ? 'upstream_error' : 'error';
94
94
  /** The gateway catalog fields of an error, for JSON output: `code`, `required_scope` and `docs_url` when the gateway sent them. */
95
95
  export function errorCatalog(e) {
96
96
  const body = e.body && typeof e.body === 'object' ? e.body.error : undefined;
@@ -26252,6 +26252,22 @@ export interface components {
26252
26252
  has_prev: boolean;
26253
26253
  };
26254
26254
  };
26255
+ /** @description The funded storage write operation receipt. A settled first write (201) carries the object acknowledgement as `result`; a same-key replay (200) returns the original receipt without `result`; a write that is not settled yet (202) names its operation_id. */
26256
+ "Hives.CloudResource_GenesisCellsStorageWriteReceipt": {
26257
+ /** @enum {string} */
26258
+ object: "storage_write_operation";
26259
+ operation_id: string;
26260
+ state: string;
26261
+ code?: string;
26262
+ funding_source?: string | null;
26263
+ reservation_id?: string | null;
26264
+ native_meter?: string;
26265
+ quantity_base?: string | null;
26266
+ upper_bound_quantity_base?: string | null;
26267
+ retry_send?: boolean;
26268
+ storage_operation_id?: string | null;
26269
+ result?: components["schemas"]["Hives.CloudResource_GenesisCellsObjectAcknowledgement"];
26270
+ };
26255
26271
  "Hives.CloudResource_GenesisCellsObjectAcknowledgement": {
26256
26272
  key: string;
26257
26273
  bucket_id: string;
@@ -39670,6 +39686,15 @@ export interface components {
39670
39686
  "application/json": components["schemas"]["Minds.MindsError"];
39671
39687
  };
39672
39688
  };
39689
+ /** @description MIND_GONE: the Mind was deleted and released; its data is archived and it cannot be resumed or used. Not retryable. (Deleting or resizing an already deleted Mind answers 409 MIND_DELETED instead.) */
39690
+ "Minds.MindsGone": {
39691
+ headers: {
39692
+ [name: string]: unknown;
39693
+ };
39694
+ content: {
39695
+ "application/json": components["schemas"]["Minds.MindsError"];
39696
+ };
39697
+ };
39673
39698
  /** @description Missing scope, not the approver, or no authority over the record */
39674
39699
  "Auto.Forbidden": {
39675
39700
  headers: {
@@ -50288,13 +50313,31 @@ export interface operations {
50288
50313
  };
50289
50314
  };
50290
50315
  responses: {
50291
- /** @description Actual provider upload metadata */
50316
+ /** @description Actual provider upload metadata (unfunded mode), or the original settled receipt without `result` for a same-key replay */
50292
50317
  200: {
50293
50318
  headers: {
50294
50319
  [name: string]: unknown;
50295
50320
  };
50296
50321
  content: {
50297
- "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsObjectAcknowledgement"];
50322
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsObjectAcknowledgement"] | components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50323
+ };
50324
+ };
50325
+ /** @description Funded write settled; the receipt carries the object acknowledgement as `result` */
50326
+ 201: {
50327
+ headers: {
50328
+ [name: string]: unknown;
50329
+ };
50330
+ content: {
50331
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50332
+ };
50333
+ };
50334
+ /** @description Funded write not settled yet; replay the same Idempotency-Key to read its outcome */
50335
+ 202: {
50336
+ headers: {
50337
+ [name: string]: unknown;
50338
+ };
50339
+ content: {
50340
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50298
50341
  };
50299
50342
  };
50300
50343
  /** @description Invalid encoded key */
@@ -50304,6 +50347,15 @@ export interface operations {
50304
50347
  };
50305
50348
  content?: never;
50306
50349
  };
50350
+ /** @description Funded write denied; the receipt's state is final */
50351
+ 402: {
50352
+ headers: {
50353
+ [name: string]: unknown;
50354
+ };
50355
+ content: {
50356
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50357
+ };
50358
+ };
50307
50359
  /** @description Owned bucket not found */
50308
50360
  404: {
50309
50361
  headers: {
@@ -50478,13 +50530,31 @@ export interface operations {
50478
50530
  };
50479
50531
  };
50480
50532
  responses: {
50481
- /** @description Object uploaded */
50533
+ /** @description Object uploaded (unfunded mode), or the original settled receipt without `result` for a same-key replay */
50482
50534
  200: {
50483
50535
  headers: {
50484
50536
  [name: string]: unknown;
50485
50537
  };
50486
50538
  content: {
50487
- "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsObjectAcknowledgement"];
50539
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsObjectAcknowledgement"] | components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50540
+ };
50541
+ };
50542
+ /** @description Funded write settled; the receipt carries the object acknowledgement as `result` */
50543
+ 201: {
50544
+ headers: {
50545
+ [name: string]: unknown;
50546
+ };
50547
+ content: {
50548
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50549
+ };
50550
+ };
50551
+ /** @description Funded write not settled yet; replay the same Idempotency-Key to read its outcome */
50552
+ 202: {
50553
+ headers: {
50554
+ [name: string]: unknown;
50555
+ };
50556
+ content: {
50557
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50488
50558
  };
50489
50559
  };
50490
50560
  /** @description Unauthorized */
@@ -50494,6 +50564,15 @@ export interface operations {
50494
50564
  };
50495
50565
  content?: never;
50496
50566
  };
50567
+ /** @description Funded write denied; the receipt's state is final */
50568
+ 402: {
50569
+ headers: {
50570
+ [name: string]: unknown;
50571
+ };
50572
+ content: {
50573
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50574
+ };
50575
+ };
50497
50576
  /** @description Bucket not found */
50498
50577
  404: {
50499
50578
  headers: {
@@ -50501,6 +50580,13 @@ export interface operations {
50501
50580
  };
50502
50581
  content?: never;
50503
50582
  };
50583
+ /** @description Idempotency-Key reused with a different body, or the write conflicted with admission */
50584
+ 409: {
50585
+ headers: {
50586
+ [name: string]: unknown;
50587
+ };
50588
+ content?: never;
50589
+ };
50504
50590
  /** @description Payload too large */
50505
50591
  413: {
50506
50592
  headers: {
@@ -50606,13 +50692,31 @@ export interface operations {
50606
50692
  };
50607
50693
  };
50608
50694
  responses: {
50609
- /** @description Object uploaded */
50695
+ /** @description Object uploaded (unfunded mode), or the original settled receipt without `result` for a same-key replay */
50610
50696
  200: {
50611
50697
  headers: {
50612
50698
  [name: string]: unknown;
50613
50699
  };
50614
50700
  content: {
50615
- "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsObjectAcknowledgement"];
50701
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsObjectAcknowledgement"] | components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50702
+ };
50703
+ };
50704
+ /** @description Funded write settled; the receipt carries the object acknowledgement as `result` */
50705
+ 201: {
50706
+ headers: {
50707
+ [name: string]: unknown;
50708
+ };
50709
+ content: {
50710
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50711
+ };
50712
+ };
50713
+ /** @description Funded write not settled yet; replay the same Idempotency-Key to read its outcome */
50714
+ 202: {
50715
+ headers: {
50716
+ [name: string]: unknown;
50717
+ };
50718
+ content: {
50719
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50616
50720
  };
50617
50721
  };
50618
50722
  /** @description Unauthorized */
@@ -50622,6 +50726,15 @@ export interface operations {
50622
50726
  };
50623
50727
  content?: never;
50624
50728
  };
50729
+ /** @description Funded write denied; the receipt's state is final */
50730
+ 402: {
50731
+ headers: {
50732
+ [name: string]: unknown;
50733
+ };
50734
+ content: {
50735
+ "application/json": components["schemas"]["Hives.CloudResource_GenesisCellsStorageWriteReceipt"];
50736
+ };
50737
+ };
50625
50738
  /** @description Bucket not found */
50626
50739
  404: {
50627
50740
  headers: {
@@ -50629,6 +50742,13 @@ export interface operations {
50629
50742
  };
50630
50743
  content?: never;
50631
50744
  };
50745
+ /** @description Idempotency-Key reused with a different body, or the write conflicted with admission */
50746
+ 409: {
50747
+ headers: {
50748
+ [name: string]: unknown;
50749
+ };
50750
+ content?: never;
50751
+ };
50632
50752
  /** @description Payload too large */
50633
50753
  413: {
50634
50754
  headers: {
@@ -70946,6 +71066,7 @@ export interface operations {
70946
71066
  };
70947
71067
  };
70948
71068
  403: components["responses"]["Minds.MindsHumanSelectionRequired"];
71069
+ 410: components["responses"]["Minds.MindsGone"];
70949
71070
  };
70950
71071
  };
70951
71072
  minds_deleteMind: {
@@ -71001,6 +71122,7 @@ export interface operations {
71001
71122
  };
71002
71123
  };
71003
71124
  403: components["responses"]["Minds.MindsHumanSelectionRequired"];
71125
+ 410: components["responses"]["Minds.MindsGone"];
71004
71126
  };
71005
71127
  };
71006
71128
  minds_getEpisodicMemory: {
@@ -71026,6 +71148,7 @@ export interface operations {
71026
71148
  };
71027
71149
  };
71028
71150
  403: components["responses"]["Minds.MindsHumanSelectionRequired"];
71151
+ 410: components["responses"]["Minds.MindsGone"];
71029
71152
  };
71030
71153
  };
71031
71154
  minds_updateEpisodicMemory: {
@@ -71062,6 +71185,7 @@ export interface operations {
71062
71185
  };
71063
71186
  };
71064
71187
  403: components["responses"]["Minds.MindsHumanSelectionRequired"];
71188
+ 410: components["responses"]["Minds.MindsGone"];
71065
71189
  };
71066
71190
  };
71067
71191
  minds_searchMemory: {
@@ -71089,6 +71213,7 @@ export interface operations {
71089
71213
  };
71090
71214
  };
71091
71215
  403: components["responses"]["Minds.MindsHumanSelectionRequired"];
71216
+ 410: components["responses"]["Minds.MindsGone"];
71092
71217
  };
71093
71218
  };
71094
71219
  minds_resumeMind: {
@@ -71118,6 +71243,7 @@ export interface operations {
71118
71243
  };
71119
71244
  };
71120
71245
  403: components["responses"]["Minds.MindsHumanSelectionRequired"];
71246
+ 410: components["responses"]["Minds.MindsGone"];
71121
71247
  };
71122
71248
  };
71123
71249
  minds_agentInsertEpisodicMemory: {
@@ -71497,6 +71623,7 @@ export interface operations {
71497
71623
  };
71498
71624
  };
71499
71625
  403: components["responses"]["Minds.MindsHumanSelectionRequired"];
71626
+ 410: components["responses"]["Minds.MindsGone"];
71500
71627
  };
71501
71628
  };
71502
71629
  minds_createWebhookDelivery: {
package/dist/genesis.d.ts CHANGED
@@ -9372,16 +9372,16 @@ export declare class Genesis extends GenesisClient {
9372
9372
  }, options?: import("./hives-resources-transport.js").HivesResourceOptions): Promise<import("./hives-cells.js").HivesObjectList>;
9373
9373
  put(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: import("./hives-resources-transport.js").HivesFundedWriteOptions & {
9374
9374
  content_type?: string;
9375
- }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement>;
9375
+ }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement | import("./hives-cells.js").HivesStorageWriteReplay>;
9376
9376
  remove: (project: string, id: string, key: string, options?: import("./hives-resources-transport.js").HivesResourceOptions) => Promise<void>;
9377
9377
  download: (project: string, id: string, key: string, options?: import("./hives-resources-transport.js").HivesResourceOptions) => Promise<Response>;
9378
9378
  putFlat(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: import("./hives-resources-transport.js").HivesFundedWriteOptions & {
9379
9379
  content_type?: string;
9380
- }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement>;
9380
+ }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement | import("./hives-cells.js").HivesStorageWriteReplay>;
9381
9381
  removeFlat: (project: string, id: string, key: string, options?: import("./hives-resources-transport.js").HivesResourceOptions) => Promise<void>;
9382
9382
  putDownload(project: string, id: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: import("./hives-resources-transport.js").HivesFundedWriteOptions & {
9383
- content_type? /** One SQL statement, run once (never replayed) and metered on success. */: string;
9384
- }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement>;
9383
+ content_type?: string;
9384
+ }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement | import("./hives-cells.js").HivesStorageWriteReplay>;
9385
9385
  removeDownload: (project: string, id: string, options?: import("./hives-resources-transport.js").HivesResourceOptions) => Promise<void>;
9386
9386
  };
9387
9387
  presign(project: string, id: string, body: import("./hives-cells.js").HivesPresign, options?: import("./hives-resources-transport.js").HivesResourceOptions): Promise<import("./hives-cells.js").HivesPresignedUrl>;
@@ -14725,11 +14725,38 @@
14725
14725
  },
14726
14726
  "responses": {
14727
14727
  "200": {
14728
- "description": "Actual provider upload metadata",
14728
+ "description": "Actual provider upload metadata (unfunded mode), or the original settled receipt without `result` for a same-key replay",
14729
14729
  "content": {
14730
14730
  "application/json": {
14731
14731
  "schema": {
14732
- "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsObjectAcknowledgement"
14732
+ "oneOf": [
14733
+ {
14734
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsObjectAcknowledgement"
14735
+ },
14736
+ {
14737
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
14738
+ }
14739
+ ]
14740
+ }
14741
+ }
14742
+ }
14743
+ },
14744
+ "201": {
14745
+ "description": "Funded write settled; the receipt carries the object acknowledgement as `result`",
14746
+ "content": {
14747
+ "application/json": {
14748
+ "schema": {
14749
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
14750
+ }
14751
+ }
14752
+ }
14753
+ },
14754
+ "202": {
14755
+ "description": "Funded write not settled yet; replay the same Idempotency-Key to read its outcome",
14756
+ "content": {
14757
+ "application/json": {
14758
+ "schema": {
14759
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
14733
14760
  }
14734
14761
  }
14735
14762
  }
@@ -14737,6 +14764,16 @@
14737
14764
  "400": {
14738
14765
  "description": "Invalid encoded key"
14739
14766
  },
14767
+ "402": {
14768
+ "description": "Funded write denied; the receipt's state is final",
14769
+ "content": {
14770
+ "application/json": {
14771
+ "schema": {
14772
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
14773
+ }
14774
+ }
14775
+ }
14776
+ },
14740
14777
  "404": {
14741
14778
  "description": "Owned bucket not found"
14742
14779
  },
@@ -14942,11 +14979,38 @@
14942
14979
  },
14943
14980
  "responses": {
14944
14981
  "200": {
14945
- "description": "Object uploaded",
14982
+ "description": "Object uploaded (unfunded mode), or the original settled receipt without `result` for a same-key replay",
14983
+ "content": {
14984
+ "application/json": {
14985
+ "schema": {
14986
+ "oneOf": [
14987
+ {
14988
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsObjectAcknowledgement"
14989
+ },
14990
+ {
14991
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
14992
+ }
14993
+ ]
14994
+ }
14995
+ }
14996
+ }
14997
+ },
14998
+ "201": {
14999
+ "description": "Funded write settled; the receipt carries the object acknowledgement as `result`",
14946
15000
  "content": {
14947
15001
  "application/json": {
14948
15002
  "schema": {
14949
- "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsObjectAcknowledgement"
15003
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
15004
+ }
15005
+ }
15006
+ }
15007
+ },
15008
+ "202": {
15009
+ "description": "Funded write not settled yet; replay the same Idempotency-Key to read its outcome",
15010
+ "content": {
15011
+ "application/json": {
15012
+ "schema": {
15013
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
14950
15014
  }
14951
15015
  }
14952
15016
  }
@@ -14954,9 +15018,22 @@
14954
15018
  "401": {
14955
15019
  "description": "Unauthorized"
14956
15020
  },
15021
+ "402": {
15022
+ "description": "Funded write denied; the receipt's state is final",
15023
+ "content": {
15024
+ "application/json": {
15025
+ "schema": {
15026
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
15027
+ }
15028
+ }
15029
+ }
15030
+ },
14957
15031
  "404": {
14958
15032
  "description": "Bucket not found"
14959
15033
  },
15034
+ "409": {
15035
+ "description": "Idempotency-Key reused with a different body, or the write conflicted with admission"
15036
+ },
14960
15037
  "413": {
14961
15038
  "description": "Payload too large"
14962
15039
  },
@@ -15093,11 +15170,38 @@
15093
15170
  },
15094
15171
  "responses": {
15095
15172
  "200": {
15096
- "description": "Object uploaded",
15173
+ "description": "Object uploaded (unfunded mode), or the original settled receipt without `result` for a same-key replay",
15174
+ "content": {
15175
+ "application/json": {
15176
+ "schema": {
15177
+ "oneOf": [
15178
+ {
15179
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsObjectAcknowledgement"
15180
+ },
15181
+ {
15182
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
15183
+ }
15184
+ ]
15185
+ }
15186
+ }
15187
+ }
15188
+ },
15189
+ "201": {
15190
+ "description": "Funded write settled; the receipt carries the object acknowledgement as `result`",
15191
+ "content": {
15192
+ "application/json": {
15193
+ "schema": {
15194
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
15195
+ }
15196
+ }
15197
+ }
15198
+ },
15199
+ "202": {
15200
+ "description": "Funded write not settled yet; replay the same Idempotency-Key to read its outcome",
15097
15201
  "content": {
15098
15202
  "application/json": {
15099
15203
  "schema": {
15100
- "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsObjectAcknowledgement"
15204
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
15101
15205
  }
15102
15206
  }
15103
15207
  }
@@ -15105,9 +15209,22 @@
15105
15209
  "401": {
15106
15210
  "description": "Unauthorized"
15107
15211
  },
15212
+ "402": {
15213
+ "description": "Funded write denied; the receipt's state is final",
15214
+ "content": {
15215
+ "application/json": {
15216
+ "schema": {
15217
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsStorageWriteReceipt"
15218
+ }
15219
+ }
15220
+ }
15221
+ },
15108
15222
  "404": {
15109
15223
  "description": "Bucket not found"
15110
15224
  },
15225
+ "409": {
15226
+ "description": "Idempotency-Key reused with a different body, or the write conflicted with admission"
15227
+ },
15111
15228
  "413": {
15112
15229
  "description": "Payload too large"
15113
15230
  },
@@ -44567,6 +44684,9 @@
44567
44684
  },
44568
44685
  "403": {
44569
44686
  "$ref": "#/components/responses/Minds.MindsHumanSelectionRequired"
44687
+ },
44688
+ "410": {
44689
+ "$ref": "#/components/responses/Minds.MindsGone"
44570
44690
  }
44571
44691
  },
44572
44692
  "x-required-scope": "minds:read",
@@ -44678,6 +44798,9 @@
44678
44798
  },
44679
44799
  "403": {
44680
44800
  "$ref": "#/components/responses/Minds.MindsHumanSelectionRequired"
44801
+ },
44802
+ "410": {
44803
+ "$ref": "#/components/responses/Minds.MindsGone"
44681
44804
  }
44682
44805
  },
44683
44806
  "requestBody": {
@@ -44784,6 +44907,9 @@
44784
44907
  },
44785
44908
  "403": {
44786
44909
  "$ref": "#/components/responses/Minds.MindsHumanSelectionRequired"
44910
+ },
44911
+ "410": {
44912
+ "$ref": "#/components/responses/Minds.MindsGone"
44787
44913
  }
44788
44914
  },
44789
44915
  "x-required-scope": "minds:write",
@@ -44838,6 +44964,9 @@
44838
44964
  },
44839
44965
  "403": {
44840
44966
  "$ref": "#/components/responses/Minds.MindsHumanSelectionRequired"
44967
+ },
44968
+ "410": {
44969
+ "$ref": "#/components/responses/Minds.MindsGone"
44841
44970
  }
44842
44971
  },
44843
44972
  "x-required-scope": "minds:read",
@@ -44887,6 +45016,9 @@
44887
45016
  },
44888
45017
  "403": {
44889
45018
  "$ref": "#/components/responses/Minds.MindsHumanSelectionRequired"
45019
+ },
45020
+ "410": {
45021
+ "$ref": "#/components/responses/Minds.MindsGone"
44890
45022
  }
44891
45023
  },
44892
45024
  "requestBody": {
@@ -44963,6 +45095,9 @@
44963
45095
  },
44964
45096
  "403": {
44965
45097
  "$ref": "#/components/responses/Minds.MindsHumanSelectionRequired"
45098
+ },
45099
+ "410": {
45100
+ "$ref": "#/components/responses/Minds.MindsGone"
44966
45101
  }
44967
45102
  },
44968
45103
  "x-required-scope": "minds:write",
@@ -45800,6 +45935,9 @@
45800
45935
  },
45801
45936
  "403": {
45802
45937
  "$ref": "#/components/responses/Minds.MindsHumanSelectionRequired"
45938
+ },
45939
+ "410": {
45940
+ "$ref": "#/components/responses/Minds.MindsGone"
45803
45941
  }
45804
45942
  },
45805
45943
  "x-required-scope": "minds:write",
@@ -104302,6 +104440,72 @@
104302
104440
  }
104303
104441
  }
104304
104442
  },
104443
+ "Hives.CloudResource_GenesisCellsStorageWriteReceipt": {
104444
+ "type": "object",
104445
+ "description": "The funded storage write operation receipt. A settled first write (201) carries the object acknowledgement as `result`; a same-key replay (200) returns the original receipt without `result`; a write that is not settled yet (202) names its operation_id.",
104446
+ "required": [
104447
+ "object",
104448
+ "operation_id",
104449
+ "state"
104450
+ ],
104451
+ "properties": {
104452
+ "object": {
104453
+ "type": "string",
104454
+ "enum": [
104455
+ "storage_write_operation"
104456
+ ]
104457
+ },
104458
+ "operation_id": {
104459
+ "type": "string",
104460
+ "pattern": "^fop_[0-9a-f]{32}$"
104461
+ },
104462
+ "state": {
104463
+ "type": "string"
104464
+ },
104465
+ "code": {
104466
+ "type": "string"
104467
+ },
104468
+ "funding_source": {
104469
+ "type": [
104470
+ "string",
104471
+ "null"
104472
+ ]
104473
+ },
104474
+ "reservation_id": {
104475
+ "type": [
104476
+ "string",
104477
+ "null"
104478
+ ]
104479
+ },
104480
+ "native_meter": {
104481
+ "type": "string"
104482
+ },
104483
+ "quantity_base": {
104484
+ "type": [
104485
+ "string",
104486
+ "null"
104487
+ ]
104488
+ },
104489
+ "upper_bound_quantity_base": {
104490
+ "type": [
104491
+ "string",
104492
+ "null"
104493
+ ]
104494
+ },
104495
+ "retry_send": {
104496
+ "type": "boolean"
104497
+ },
104498
+ "storage_operation_id": {
104499
+ "type": [
104500
+ "string",
104501
+ "null"
104502
+ ]
104503
+ },
104504
+ "result": {
104505
+ "$ref": "#/components/schemas/Hives.CloudResource_GenesisCellsObjectAcknowledgement"
104506
+ }
104507
+ }
104508
+ },
104305
104509
  "Hives.CloudResource_GenesisCellsObjectAcknowledgement": {
104306
104510
  "type": "object",
104307
104511
  "required": [
@@ -150007,6 +150211,16 @@
150007
150211
  }
150008
150212
  }
150009
150213
  },
150214
+ "Minds.MindsGone": {
150215
+ "description": "MIND_GONE: the Mind was deleted and released; its data is archived and it cannot be resumed or used. Not retryable. (Deleting or resizing an already deleted Mind answers 409 MIND_DELETED instead.)",
150216
+ "content": {
150217
+ "application/json": {
150218
+ "schema": {
150219
+ "$ref": "#/components/schemas/Minds.MindsError"
150220
+ }
150221
+ }
150222
+ }
150223
+ },
150010
150224
  "Auto.Forbidden": {
150011
150225
  "description": "Missing scope, not the approver, or no authority over the record",
150012
150226
  "content": {
@@ -84,6 +84,16 @@ export interface HivesPresignedUrl {
84
84
  required_headers?: Record<string, string>;
85
85
  }
86
86
  export declare function hivesObjectKey(key: string): string;
87
+ /** A replay of the same Idempotency-Key: Hives answers with the original settled receipt and no result. */
88
+ export interface HivesStorageWriteReplay {
89
+ replayed: true;
90
+ key: string;
91
+ bucket_id: string;
92
+ operation_id: string;
93
+ state: 'settled';
94
+ storage_operation_id: string | null;
95
+ funding_source: string | null;
96
+ }
87
97
  export declare function hivesCells(client: GenesisClient): {
88
98
  list(project: string, query?: {
89
99
  page?: number;
@@ -114,18 +124,18 @@ export declare function hivesCells(client: GenesisClient): {
114
124
  }, options?: HivesResourceOptions): Promise<HivesObjectList>;
115
125
  put(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: HivesFundedWriteOptions & {
116
126
  content_type?: string;
117
- }): Promise<HivesObjectAcknowledgement>;
127
+ }): Promise<HivesObjectAcknowledgement | HivesStorageWriteReplay>;
118
128
  remove: (project: string, id: string, key: string, options?: HivesResourceOptions) => Promise<void>;
119
129
  download: (project: string, id: string, key: string, options?: HivesResourceOptions) => Promise<Response>;
120
130
  /** Existing flat-key path compatibility; nested keys use canonical collection methods above. */
121
131
  putFlat(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: HivesFundedWriteOptions & {
122
132
  content_type?: string;
123
- }): Promise<HivesObjectAcknowledgement>;
133
+ }): Promise<HivesObjectAcknowledgement | HivesStorageWriteReplay>;
124
134
  removeFlat: (project: string, id: string, key: string, options?: HivesResourceOptions) => Promise<void>;
125
135
  /** The flat key "download" on its own static route, which shadows /objects/{key} for that key. */
126
136
  putDownload(project: string, id: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: HivesFundedWriteOptions & {
127
137
  content_type?: string;
128
- }): Promise<HivesObjectAcknowledgement>;
138
+ }): Promise<HivesObjectAcknowledgement | HivesStorageWriteReplay>;
129
139
  removeDownload: (project: string, id: string, options?: HivesResourceOptions) => Promise<void>;
130
140
  };
131
141
  presign(project: string, id: string, body: HivesPresign, options?: HivesResourceOptions): Promise<HivesPresignedUrl>;
@@ -1,3 +1,4 @@
1
+ import { GenesisError } from './errors.js';
1
2
  import { HIVES_OBJECT_BYTES, hivesFundedWriteHeaders, hivesResourceCall, hivesResourceId, hivesObjectBody, hivesContentType, resourceError } from './hives-resources-transport.js';
2
3
  export function hivesObjectKey(key) {
3
4
  const bytes = new TextEncoder().encode(key);
@@ -59,11 +60,28 @@ function object(value, id) {
59
60
  hivesObjectKey(value.key);
60
61
  return Object.fromEntries(['key', 'bucket_id', 'size_bytes', 'etag', 'last_modified', 'generation', 'content_type', 'metadata', 'metadata_scope'].map(k => [k, value[k]]));
61
62
  }
62
- function acknowledgement(answer, key, id, size) {
63
+ const OPERATION_ID = /^fop_[0-9a-f]{32}$/, STATE = /^[a-z][a-z_]{0,31}$/;
64
+ function acknowledgement(answer, key, id, size, operation) {
63
65
  // A funded write answers with its settled storage operation receipt; the acknowledgement is its result.
64
66
  const receipt = answer;
65
- if (receipt && receipt.object !== undefined && (receipt.object !== 'storage_write_operation' || receipt.state !== 'settled'))
66
- throw resourceError(0);
67
+ if (receipt && receipt.object !== undefined) {
68
+ if (receipt.object !== 'storage_write_operation')
69
+ throw resourceError(0);
70
+ const operation_id = typeof receipt.operation_id === 'string' && OPERATION_ID.test(receipt.operation_id) ? receipt.operation_id : undefined;
71
+ if (receipt.state !== 'settled') {
72
+ const state = typeof receipt.state === 'string' && STATE.test(receipt.state) ? receipt.state : 'unknown';
73
+ throw new GenesisError({ status: 0, type: 'invalid_request', code: 'HIVES_STORAGE_WRITE_NOT_SETTLED', operationId: operation, body: { operation_id: operation_id ?? null, state },
74
+ message: ['denied', 'released'].includes(state)
75
+ ? `Hives did not perform this storage write (state ${state}${operation_id ? `, operation_id ${operation_id}` : ''}). This outcome is final: a replay of the same Idempotency-Key returns it again. No automatic retry was made.`
76
+ : `Hives has not settled this storage write (state ${state}${operation_id ? `, operation_id ${operation_id}` : ''}). Replay the same Idempotency-Key to read its outcome; no automatic retry was made.` });
77
+ }
78
+ if (receipt.result === undefined) {
79
+ if (!operation_id)
80
+ throw resourceError(0);
81
+ const text = (v) => typeof v === 'string' && v.length <= 256 ? v : null;
82
+ return { replayed: true, key, bucket_id: id, operation_id, state: 'settled', storage_operation_id: text(receipt.storage_operation_id), funding_source: text(receipt.funding_source) };
83
+ }
84
+ }
67
85
  const value = (receipt?.object === undefined ? answer : receipt.result);
68
86
  if (!value || value.bucket_id !== id || value.key !== key || value.size_bytes !== size || !Number.isSafeInteger(value.size_bytes) || value.size_bytes < 0 || typeof value.etag !== 'string' || typeof value.generation !== 'string' || value.content_type !== null && typeof value.content_type !== 'string')
69
87
  throw resourceError(0);
@@ -120,7 +138,7 @@ export function hivesCells(client) {
120
138
  async put(project, id, key, bytes, options = {}) {
121
139
  const body = await hivesObjectBody(bytes);
122
140
  const content_type = hivesContentType(options.content_type);
123
- return acknowledgement(await write('hives_upload_object_by_key', { ...ids(project, id), key_base64url: hivesObjectKey(key), body, content_type }, options), key, id, body.byteLength);
141
+ return acknowledgement(await write('hives_upload_object_by_key', { ...ids(project, id), key_base64url: hivesObjectKey(key), body, content_type }, options), key, id, body.byteLength, 'hives_upload_object_by_key');
124
142
  },
125
143
  remove: (project, id, key, options) => call('hives_delete_object_by_key', { ...ids(project, id), key_base64url: hivesObjectKey(key) }, options, 'empty'),
126
144
  download: (project, id, key, options) => call('hives_download_object_by_key', { ...ids(project, id), key_base64url: hivesObjectKey(key) }, options, 'binary', HIVES_OBJECT_BYTES),
@@ -130,14 +148,14 @@ export function hivesCells(client) {
130
148
  if (!/^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*$/.test(key))
131
149
  throw resourceError(0);
132
150
  const body = await hivesObjectBody(bytes);
133
- return acknowledgement(await write('hives_upload_object', { ...ids(project, id), key, body, content_type: hivesContentType(options.content_type) }, options), key, id, body.byteLength);
151
+ return acknowledgement(await write('hives_upload_object', { ...ids(project, id), key, body, content_type: hivesContentType(options.content_type) }, options), key, id, body.byteLength, 'hives_upload_object');
134
152
  },
135
153
  removeFlat: (project, id, key, options) => { hivesObjectKey(key); if (!/^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*$/.test(key))
136
154
  throw resourceError(0); return call('hives_delete_object', { ...ids(project, id), key }, options, 'empty'); },
137
155
  /** The flat key "download" on its own static route, which shadows /objects/{key} for that key. */
138
156
  async putDownload(project, id, bytes, options = {}) {
139
157
  const body = await hivesObjectBody(bytes);
140
- return acknowledgement(await write('hives_upload_object_named_download', { ...ids(project, id), body, content_type: hivesContentType(options.content_type) }, options), 'download', id, body.byteLength);
158
+ return acknowledgement(await write('hives_upload_object_named_download', { ...ids(project, id), body, content_type: hivesContentType(options.content_type) }, options), 'download', id, body.byteLength, 'hives_upload_object_named_download');
141
159
  },
142
160
  removeDownload: (project, id, options) => call('hives_delete_object_named_download', ids(project, id), options, 'empty'),
143
161
  },
@@ -2,6 +2,8 @@ import { Genesis } from './genesis.js';
2
2
  import type { GenesisOptions } from './client.js';
3
3
  export declare function closeHivesNodeTransport(): Promise<void>;
4
4
  export declare function hivesOperationBudget(id: string): number;
5
+ /** Live log streams must start within 45 s (15 s heartbeat + 15 s window + margin). The 330 s budget runs from the start of the request, so the body gets at least 285 s. */
6
+ export declare function hivesHeaderBudget(id: string): number | undefined;
5
7
  /** Hives leaf transport. Caller fetch overrides stay authoritative; only native
6
8
  * global fetch gets our Agent. Every operation retains an overall body deadline. */
7
9
  export declare function createHivesNodeTransport(opts?: GenesisOptions, callerSignal?: AbortSignal): typeof fetch;
@@ -25,6 +25,10 @@ export function hivesOperationBudget(id) {
25
25
  return 100_000;
26
26
  return 20_000;
27
27
  }
28
+ /** Live log streams must start within 45 s (15 s heartbeat + 15 s window + margin). The 330 s budget runs from the start of the request, so the body gets at least 285 s. */
29
+ export function hivesHeaderBudget(id) {
30
+ return id === 'hives_stream_logs' || id === 'hives_stream_deployment_logs' ? 45_000 : undefined;
31
+ }
28
32
  const escape = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
29
33
  const templatePattern = (value) => new RegExp('^' + value.split(/(\{[^}]+\})/).map((part) => part.startsWith('{') ? '[^/]+' : escape(part)).join('') + '$');
30
34
  /** Hives leaf transport. Caller fetch overrides stay authoritative; only native
@@ -79,6 +83,12 @@ export function createHivesNodeTransport(opts = {}, callerSignal) {
79
83
  controller.abort();
80
84
  }, hivesOperationBudget(route.id));
81
85
  timer.unref();
86
+ const headerBudget = hivesHeaderBudget(route.id);
87
+ const headerTimer = headerBudget === undefined ? undefined : setTimeout(() => {
88
+ message = 'Hives stream did not start within 45 s. Retry the stream.';
89
+ controller.abort();
90
+ }, headerBudget);
91
+ headerTimer?.unref();
82
92
  let abortReject = () => { };
83
93
  let reader;
84
94
  let bodyController;
@@ -93,6 +103,7 @@ export function createHivesNodeTransport(opts = {}, callerSignal) {
93
103
  void abortPromise.catch(() => { });
94
104
  const cleanup = () => {
95
105
  clearTimeout(timer);
106
+ clearTimeout(headerTimer);
96
107
  for (const signal of signals)
97
108
  signal.removeEventListener('abort', canceled);
98
109
  controller.signal.removeEventListener('abort', aborted);
@@ -113,6 +124,7 @@ export function createHivesNodeTransport(opts = {}, callerSignal) {
113
124
  void pending.then((response) => { if (controller.signal.aborted)
114
125
  void response.body?.cancel().catch(() => { }); }, () => { });
115
126
  const response = await Promise.race([pending, abortPromise]);
127
+ clearTimeout(headerTimer);
116
128
  if (controller.signal.aborted)
117
129
  throw safeError();
118
130
  if (!response.body) {
@@ -31,16 +31,16 @@ export declare function hivesOperations(client: GenesisClient): {
31
31
  }, options?: import("./hives-resources-transport.js").HivesResourceOptions): Promise<import("./hives-cells.js").HivesObjectList>;
32
32
  put(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: import("./hives-resources-transport.js").HivesFundedWriteOptions & {
33
33
  content_type?: string;
34
- }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement>;
34
+ }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement | import("./hives-cells.js").HivesStorageWriteReplay>;
35
35
  remove: (project: string, id: string, key: string, options?: import("./hives-resources-transport.js").HivesResourceOptions) => Promise<void>;
36
36
  download: (project: string, id: string, key: string, options?: import("./hives-resources-transport.js").HivesResourceOptions) => Promise<Response>;
37
37
  putFlat(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: import("./hives-resources-transport.js").HivesFundedWriteOptions & {
38
38
  content_type?: string;
39
- }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement>;
39
+ }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement | import("./hives-cells.js").HivesStorageWriteReplay>;
40
40
  removeFlat: (project: string, id: string, key: string, options?: import("./hives-resources-transport.js").HivesResourceOptions) => Promise<void>;
41
41
  putDownload(project: string, id: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: import("./hives-resources-transport.js").HivesFundedWriteOptions & {
42
42
  content_type?: string;
43
- }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement>;
43
+ }): Promise<import("./hives-cells.js").HivesObjectAcknowledgement | import("./hives-cells.js").HivesStorageWriteReplay>;
44
44
  removeDownload: (project: string, id: string, options?: import("./hives-resources-transport.js").HivesResourceOptions) => Promise<void>;
45
45
  };
46
46
  presign(project: string, id: string, body: import("./hives-cells.js").HivesPresign, options?: import("./hives-resources-transport.js").HivesResourceOptions): Promise<import("./hives-cells.js").HivesPresignedUrl>;
@@ -13,6 +13,7 @@ export declare function hivesProjectIdRefusal(value: string, operationId?: strin
13
13
  /**
14
14
  * Map a Hives project argument to a Hives project id. A prj_… (or any non-Genesis) value is returned unchanged.
15
15
  * Omitted, or a Genesis pr_… id that is the selected context's project, resolves to that selection's Hives binding
16
- * read from `hives_get_context_project`; anything else is refused with how to find the prj_… id.
16
+ * read from `hives_get_context_project`; anything else is refused with how to find the prj_… id. When the binding
17
+ * came from a cache and a pr_… id does not match it, `reread` (if given) reads the selection once more before refusing.
17
18
  */
18
- export declare function resolveHivesProjectId(value: unknown, readContext: () => Promise<unknown>): Promise<string>;
19
+ export declare function resolveHivesProjectId(value: unknown, readContext: () => Promise<unknown>, reread?: () => Promise<unknown> | undefined): Promise<string>;
@@ -19,33 +19,44 @@ const notBound = (message, from) => new GenesisError({ status: from?.status ?? 0
19
19
  /**
20
20
  * Map a Hives project argument to a Hives project id. A prj_… (or any non-Genesis) value is returned unchanged.
21
21
  * Omitted, or a Genesis pr_… id that is the selected context's project, resolves to that selection's Hives binding
22
- * read from `hives_get_context_project`; anything else is refused with how to find the prj_… id.
22
+ * read from `hives_get_context_project`; anything else is refused with how to find the prj_… id. When the binding
23
+ * came from a cache and a pr_… id does not match it, `reread` (if given) reads the selection once more before refusing.
23
24
  */
24
- export async function resolveHivesProjectId(value, readContext) {
25
+ export async function resolveHivesProjectId(value, readContext, reread) {
25
26
  if (value !== undefined && value !== null && value !== '' && !isGenesisProjectId(value)) {
26
27
  if (typeof value !== 'string')
27
28
  throw new GenesisError({ status: 0, type: 'invalid_request', code: 'HIVES_PROJECT_ID_REQUIRED', message: `project_id must be a ${HIVES_PROJECT_ID_DESCRIPTION}.` });
28
29
  return value;
29
30
  }
30
- let context;
31
- try {
32
- context = await readContext();
31
+ const load = async (read) => {
32
+ try {
33
+ return binding(await read());
34
+ }
35
+ catch (e) {
36
+ if (!(e instanceof GenesisError) || ![404, 409].includes(e.status))
37
+ throw e;
38
+ const named = isGenesisProjectId(value) ? `${value} is a Genesis project id and ` : '';
39
+ throw notBound(e.status === 404
40
+ ? `${named}No Hives project is bound to your selected Genesis context. Bind one with \`genesis hives context create <name>\` or \`genesis hives context link <prj_…>\`, or pass a Hives project id (prj_…) from \`genesis hives projects list\`.`
41
+ : `${named}No Genesis project is selected. Select an organization, workspace and project with \`genesis context select\`, or pass a Hives project id (prj_…) from \`genesis hives projects list\`.`, e);
42
+ }
43
+ };
44
+ let { selected, bound } = await load(readContext);
45
+ if (isGenesisProjectId(value) && value !== selected && reread) {
46
+ const fresh = reread();
47
+ if (fresh)
48
+ ({ selected, bound } = await load(() => fresh));
33
49
  }
34
- catch (e) {
35
- if (!(e instanceof GenesisError) || ![404, 409].includes(e.status))
36
- throw e;
37
- const named = isGenesisProjectId(value) ? `${value} is a Genesis project id and ` : '';
38
- throw notBound(e.status === 404
39
- ? `${named}No Hives project is bound to your selected Genesis context. Bind one with \`genesis hives context create <name>\` or \`genesis hives context link <prj_…>\`, or pass a Hives project id (prj_…) from \`genesis hives projects list\`.`
40
- : `${named}No Genesis project is selected. Select an organization, workspace and project with \`genesis context select\`, or pass a Hives project id (prj_…) from \`genesis hives projects list\`.`, e);
50
+ if (isGenesisProjectId(value) && value !== selected) {
51
+ throw notBound(`${value} is a Genesis project id, and it is not your selected Genesis project (${selected}, bound to Hives project ${bound}). Select it with \`genesis context select\`, or pass its Hives project id (prj_…) from \`genesis hives projects list\`.`);
41
52
  }
53
+ return bound;
54
+ }
55
+ function binding(context) {
42
56
  const row = context && typeof context === 'object' ? context : {};
43
57
  const selected = row.selectedContext?.projectId, bound = row.binding?.hivesProjectId;
44
58
  if (typeof bound !== 'string' || !HIVES_PROJECT.test(bound) || typeof selected !== 'string') {
45
59
  throw new GenesisError({ status: 0, type: 'invalid_response', operationId: 'hives_get_context_project', message: 'Hives returned an invalid context binding.' });
46
60
  }
47
- if (isGenesisProjectId(value) && value !== selected) {
48
- throw notBound(`${value} is a Genesis project id, and it is not your selected Genesis project (${selected}, bound to Hives project ${bound}). Select it with \`genesis context select\`, or pass its Hives project id (prj_…) from \`genesis hives projects list\`.`);
49
- }
50
- return bound;
61
+ return { selected, bound };
51
62
  }
@@ -7,7 +7,7 @@ export interface HivesSseEvent {
7
7
  export interface HivesSseWindowOptions {
8
8
  /** Stop after this many events (1-1000, default 100). */
9
9
  maxEvents?: number;
10
- /** Stop after this many seconds (1-15, default 10). The CLI and MCP Hives node transport allows a body 20 s, so a window stays below it. */
10
+ /** Stop after this many seconds (1-15, default 10). The CLI and MCP Hives node transport waits at most 45 s for a log stream to start, within a 330 s budget from the start of the request (at least 285 s of body), so a window always fits. */
11
11
  seconds?: number;
12
12
  signal?: AbortSignal;
13
13
  }
package/dist/index.d.ts CHANGED
@@ -30,7 +30,7 @@ export { scopesModule } from './scopes.js';
30
30
  export { billingModule, gatewayModule, orgsModule } from './gateway.js';
31
31
  export { boxesModule } from './boxes.js';
32
32
  export { dialsModule, dialsEmergencyAddressFeedback, type DialsEmergencyAddressFeedback, type DialsScope, type DialsOutboundCall, type DialsCallControl, type DialsEmergencyAddress, type DialsCallListItem, type DialsCallDispatchState, type DialsMessage, type DialsMessageTemplate, type DialsMessagingBrand, type DialsMessagingCampaign, type DialsWorkflowDocument, type DialsRoutingAction, type DialsRoutingRule, type DialsRoutingRuleReceipt, type DialsOutboundCallReceipt, type DialsRecoveredOutboundCallReceipt } from './dials.js';
33
- export { hivesObjectKey, type HivesBucket, type HivesObject, type HivesObjectAcknowledgement, type HivesObjectList, type HivesCorsRule, type HivesCreateBucket, type HivesPresign, type HivesPresignedUrl } from './hives-cells.js';
33
+ export { hivesObjectKey, type HivesBucket, type HivesObject, type HivesObjectAcknowledgement, type HivesStorageWriteReplay, type HivesObjectList, type HivesCorsRule, type HivesCreateBucket, type HivesPresign, type HivesPresignedUrl } from './hives-cells.js';
34
34
  export { hivesSseEvents, hivesSseReader, type HivesLogStreamEvent, type HivesLogStreamQuery, type HivesLogWindow, type HivesLogWindowOptions } from './hives-platform.js';
35
35
  export { hivesQueueBody, type HivesQueue, type HivesQueueConfig, type HivesQueueCreate, type HivesQueueSend, type HivesQueueDelivery, type HivesDeadLetter, type HivesDeadLetterStats } from './hives-queues.js';
36
36
  export type { HivesRuntime, HivesRuntimeSelection } from './hives-runtimes.js';
package/dist/minds.js CHANGED
@@ -35,7 +35,7 @@ export async function mindsTransport(options) {
35
35
  const id = options.operationId, input = options.input, write = writes.has(id);
36
36
  let dispatchAttempted = false;
37
37
  const error = (status, type, code, unknownOutcome = false) => new GenesisError({ status, type, code, operationId: id,
38
- message: status === 403 ? code === 'HUMAN_SANDBOX_SELECTION_REQUIRED'
38
+ message: status === 410 ? 'This Mind was deleted; its data is archived. It cannot be resumed or used.' : status === 403 ? code === 'HUMAN_SANDBOX_SELECTION_REQUIRED'
39
39
  ? 'HUMAN_SANDBOX_SELECTION_REQUIRED: Minds accepts an original human One account session with a Console Sandbox selection, or organization API keys with a selected (bound) context; M2M tokens are refused.'
40
40
  : code === 'SCOPE_MISSING' ? 'SCOPE_MISSING: this organization API key lacks the Minds scope the operation needs (minds:read, minds:write or minds:manage; minds:manage does not imply read).'
41
41
  : 'Minds requires an admitted original human One account session with a Console Sandbox selection, or an organization API key with the operation\'s Minds scope.'
@@ -182,7 +182,7 @@ export async function mindsTransport(options) {
182
182
  const code = detail && Object.hasOwn(detail, 'code') && typeof detail.code === 'string' ? detail.code : undefined;
183
183
  const unknownOutcome = lifecycle.includes(id) && response.status === 401 && code === 'SELECTION_EXPIRED'
184
184
  && detail !== undefined && Object.hasOwn(detail, 'outcome') && detail.outcome === 'unknown';
185
- throw error(response.status, 'minds_error', code, unknownOutcome || id === 'minds_createWebhookDelivery' && detail?.outcome === 'unknown');
185
+ throw error(response.status, response.status === 410 ? 'gone' : 'minds_error', code, unknownOutcome || id === 'minds_createWebhookDelivery' && detail?.outcome === 'unknown');
186
186
  }
187
187
  if (['minds_createMind', ...lifecycle, 'minds_createWebhookDelivery'].includes(id) && response.status !== 202)
188
188
  throw error(response.status, 'invalid_response');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onesi/genesis",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/l1felabs/genesis-api.git",