@onesi/genesis 0.2.4 → 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 +1 -1
- package/dist/client.d.ts +12 -0
- package/dist/client.js +41 -1
- package/dist/errors.js +1 -1
- package/dist/fleets.d.ts +4 -1
- package/dist/fleets.js +10 -2
- package/dist/generated/operations.js +177 -150
- package/dist/generated/schema.d.ts +286 -137
- package/dist/genesis.d.ts +17 -7
- package/dist/genesis.js +2 -0
- package/dist/genesis.openapi.json +402 -160
- package/dist/hives-cells.d.ts +13 -3
- package/dist/hives-cells.js +24 -6
- package/dist/hives-node.d.ts +2 -0
- package/dist/hives-node.js +12 -0
- package/dist/hives-operations.d.ts +3 -3
- package/dist/hives-project.d.ts +19 -0
- package/dist/hives-project.js +62 -0
- package/dist/hives-sse.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/minds.js +2 -2
- package/dist/urls.js +36 -14
- package/package.json +1 -1
package/dist/hives-cells.d.ts
CHANGED
|
@@ -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>;
|
package/dist/hives-cells.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
66
|
-
|
|
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
|
},
|
package/dist/hives-node.d.ts
CHANGED
|
@@ -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;
|
package/dist/hives-node.js
CHANGED
|
@@ -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>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { GenesisError } from './errors.js';
|
|
2
|
+
import type { OperationMeta } from './types.js';
|
|
3
|
+
/** The one description of a Hives `project_id` (spec, CLI help and MCP schemas). */
|
|
4
|
+
export declare const HIVES_PROJECT_ID_DESCRIPTION = "Hives project id (prj_\u2026)";
|
|
5
|
+
/** Appended where an omitted project_id resolves from the selected Genesis context. */
|
|
6
|
+
export declare const HIVES_PROJECT_ID_DEFAULT = "omit it to use the Hives project bound to your selected Genesis context";
|
|
7
|
+
/** A Genesis project id (`pr_…`). A Hives project id is `prj_…`, so the two never collide. */
|
|
8
|
+
export declare const isGenesisProjectId: (value: unknown) => value is string;
|
|
9
|
+
/** Hives operations addressed by a Hives project in their path. */
|
|
10
|
+
export declare const isHivesProjectOperation: (op: OperationMeta | undefined) => boolean;
|
|
11
|
+
/** A Genesis pr_… id given where Hives wants its own prj_… id: refused before any request. */
|
|
12
|
+
export declare function hivesProjectIdRefusal(value: string, operationId?: string): GenesisError;
|
|
13
|
+
/**
|
|
14
|
+
* Map a Hives project argument to a Hives project id. A prj_… (or any non-Genesis) value is returned unchanged.
|
|
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. 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.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveHivesProjectId(value: unknown, readContext: () => Promise<unknown>, reread?: () => Promise<unknown> | undefined): Promise<string>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { GenesisError } from './errors.js';
|
|
2
|
+
/** The one description of a Hives `project_id` (spec, CLI help and MCP schemas). */
|
|
3
|
+
export const HIVES_PROJECT_ID_DESCRIPTION = 'Hives project id (prj_…)';
|
|
4
|
+
/** Appended where an omitted project_id resolves from the selected Genesis context. */
|
|
5
|
+
export const HIVES_PROJECT_ID_DEFAULT = 'omit it to use the Hives project bound to your selected Genesis context';
|
|
6
|
+
/** A Genesis project id (`pr_…`). A Hives project id is `prj_…`, so the two never collide. */
|
|
7
|
+
export const isGenesisProjectId = (value) => typeof value === 'string' && /^pr_[A-Za-z0-9]{1,124}$/.test(value);
|
|
8
|
+
const HIVES_PROJECT = /^prj_[A-Za-z0-9]{1,124}$/;
|
|
9
|
+
/** Hives operations addressed by a Hives project in their path. */
|
|
10
|
+
export const isHivesProjectOperation = (op) => op?.service === 'hives' && op.pathParams.includes('project_id');
|
|
11
|
+
const FIND = 'Find the Hives project bound to your selected Genesis context with `genesis hives context get` (SDK: genesis.hives.resolveProject()), or list Hives projects with `genesis hives projects list`.';
|
|
12
|
+
/** A Genesis pr_… id given where Hives wants its own prj_… id: refused before any request. */
|
|
13
|
+
export function hivesProjectIdRefusal(value, operationId) {
|
|
14
|
+
return new GenesisError({ status: 0, type: 'invalid_request', code: 'HIVES_PROJECT_ID_REQUIRED', operationId,
|
|
15
|
+
message: `${value} is a Genesis project id. Hives operations take a Hives project id (prj_…). ${FIND}` });
|
|
16
|
+
}
|
|
17
|
+
const notBound = (message, from) => new GenesisError({ status: from?.status ?? 0, type: 'invalid_request', code: 'HIVES_PROJECT_NOT_BOUND',
|
|
18
|
+
message, requestId: from?.requestId, operationId: 'hives_get_context_project' });
|
|
19
|
+
/**
|
|
20
|
+
* Map a Hives project argument to a Hives project id. A prj_… (or any non-Genesis) value is returned unchanged.
|
|
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. 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.
|
|
24
|
+
*/
|
|
25
|
+
export async function resolveHivesProjectId(value, readContext, reread) {
|
|
26
|
+
if (value !== undefined && value !== null && value !== '' && !isGenesisProjectId(value)) {
|
|
27
|
+
if (typeof value !== 'string')
|
|
28
|
+
throw new GenesisError({ status: 0, type: 'invalid_request', code: 'HIVES_PROJECT_ID_REQUIRED', message: `project_id must be a ${HIVES_PROJECT_ID_DESCRIPTION}.` });
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
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));
|
|
49
|
+
}
|
|
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\`.`);
|
|
52
|
+
}
|
|
53
|
+
return bound;
|
|
54
|
+
}
|
|
55
|
+
function binding(context) {
|
|
56
|
+
const row = context && typeof context === 'object' ? context : {};
|
|
57
|
+
const selected = row.selectedContext?.projectId, bound = row.binding?.hivesProjectId;
|
|
58
|
+
if (typeof bound !== 'string' || !HIVES_PROJECT.test(bound) || typeof selected !== 'string') {
|
|
59
|
+
throw new GenesisError({ status: 0, type: 'invalid_response', operationId: 'hives_get_context_project', message: 'Hives returned an invalid context binding.' });
|
|
60
|
+
}
|
|
61
|
+
return { selected, bound };
|
|
62
|
+
}
|
package/dist/hives-sse.d.ts
CHANGED
|
@@ -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
|
|
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
|
@@ -11,6 +11,7 @@ export type { paths, operations, components } from './generated/schema.js';
|
|
|
11
11
|
export { hivesUploadBody, MAX_WASM_BYTES, type HivesUploadOptions } from './hives-upload.js';
|
|
12
12
|
export { validateHivesInvocation, hivesFunctionResponseHeaders, HivesOperationError, MAX_FUNCTION_BODY_BYTES, MAX_FUNCTION_JSON_BYTES, type HivesInvokeRequest, type HivesInvokeOptions, type HivesOperationStatus } from './hives-functions.js';
|
|
13
13
|
export { hivesResponseBytes } from './hives-response.js';
|
|
14
|
+
export { HIVES_PROJECT_ID_DESCRIPTION, HIVES_PROJECT_ID_DEFAULT, isGenesisProjectId, isHivesProjectOperation, hivesProjectIdRefusal } from './hives-project.js';
|
|
14
15
|
export { runnerModule, type RunnerStartInput, type RunnerSnapshot, type RunnerCatalog, type RunnerEvent, type RunnerProviderResult, type RunnerRequestOptions } from './runner.js';
|
|
15
16
|
export type { RunnerSelfExecutionGrantInput, RunnerSelfExecutionGrant } from './runner-grant.js';
|
|
16
17
|
export { beaconsModule, BEACONS_RESOURCE_FAMILIES, BEACONS_CLIENT_PLATFORMS, type BeaconsResourceFamily } from './beacons.js';
|
|
@@ -29,7 +30,7 @@ export { scopesModule } from './scopes.js';
|
|
|
29
30
|
export { billingModule, gatewayModule, orgsModule } from './gateway.js';
|
|
30
31
|
export { boxesModule } from './boxes.js';
|
|
31
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';
|
|
32
|
-
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';
|
|
33
34
|
export { hivesSseEvents, hivesSseReader, type HivesLogStreamEvent, type HivesLogStreamQuery, type HivesLogWindow, type HivesLogWindowOptions } from './hives-platform.js';
|
|
34
35
|
export { hivesQueueBody, type HivesQueue, type HivesQueueConfig, type HivesQueueCreate, type HivesQueueSend, type HivesQueueDelivery, type HivesDeadLetter, type HivesDeadLetterStats } from './hives-queues.js';
|
|
35
36
|
export type { HivesRuntime, HivesRuntimeSelection } from './hives-runtimes.js';
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { operationTable, services } from './generated/operations.js';
|
|
|
9
9
|
export { hivesUploadBody, MAX_WASM_BYTES } from './hives-upload.js';
|
|
10
10
|
export { validateHivesInvocation, hivesFunctionResponseHeaders, HivesOperationError, MAX_FUNCTION_BODY_BYTES, MAX_FUNCTION_JSON_BYTES } from './hives-functions.js';
|
|
11
11
|
export { hivesResponseBytes } from './hives-response.js';
|
|
12
|
+
export { HIVES_PROJECT_ID_DESCRIPTION, HIVES_PROJECT_ID_DEFAULT, isGenesisProjectId, isHivesProjectOperation, hivesProjectIdRefusal } from './hives-project.js';
|
|
12
13
|
export { runnerModule } from './runner.js';
|
|
13
14
|
export { beaconsModule, BEACONS_RESOURCE_FAMILIES, BEACONS_CLIENT_PLATFORMS } from './beacons.js';
|
|
14
15
|
export { rigsModule, panesModule, shellsModule } from './instances.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/dist/urls.js
CHANGED
|
@@ -41,34 +41,54 @@ const ENCODED_USERINFO = /(%(?:25){0,2}2F%(?:25){0,2}2F)(?:(?!%(?:25){0,2}2F)[^\
|
|
|
41
41
|
const BARE_USERINFO = /(^|[\s"'(<=,;[{])[^\s/?#@@:"'<>\\]{1,64}:[^\s/?#"'<>\\]{0,128}[@@](?=[\w[])/g;
|
|
42
42
|
/** Every place a userinfo can end: `@`, fullwidth `@`, or an encoded `%40` / `%2540`. */
|
|
43
43
|
const AT_HITS = /[@@]|%(?:25){0,2}40/gi;
|
|
44
|
+
/** The scheme-less form can only end at an `@` or `@` that is followed by a word character or `[` (see BARE_USERINFO). */
|
|
45
|
+
const BARE_HITS = /[@@](?=[\w[])/g;
|
|
44
46
|
/** The longest URL-form match (slashes and userinfo, encoded) is under 640 characters; the bare form is under 200. */
|
|
45
47
|
const URL_WINDOW = 700;
|
|
46
48
|
const BARE_WINDOW = 200;
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
/** With at least one hit per DENSE characters the windows would cover the text anyway, so it is scanned whole. The regexes are linear on their own; the windows only skip stretches that cannot hold a userinfo. */
|
|
50
|
+
const DENSE = 64;
|
|
51
|
+
/** Start and end of every hit of `re` in `text`, flattened; `null` when they are dense. */
|
|
52
|
+
function hitSpans(text, re) {
|
|
53
|
+
const limit = Math.floor(text.length / DENSE);
|
|
54
|
+
const spans = [];
|
|
55
|
+
re.lastIndex = 0;
|
|
56
|
+
for (let hit = re.exec(text); hit; hit = re.exec(text)) {
|
|
57
|
+
if (spans.length >= 2 * limit)
|
|
58
|
+
return null;
|
|
59
|
+
spans.push(hit.index, hit.index + hit[0].length);
|
|
60
|
+
}
|
|
61
|
+
return spans;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Apply `fn` to the stretches of `text` within `window` characters before a hit, and copy the rest as it is.
|
|
65
|
+
* `spans` of `null` means dense: `fn` runs over the whole text. A stretch without the character `needs` cannot hold a match.
|
|
66
|
+
*/
|
|
67
|
+
function overHits(text, spans, window, fn, needs = '') {
|
|
68
|
+
if (spans === null)
|
|
69
|
+
return fn(text);
|
|
70
|
+
if (spans.length === 0)
|
|
52
71
|
return text;
|
|
53
72
|
let out = '';
|
|
54
73
|
let copied = 0;
|
|
55
|
-
let start = Math.max(0,
|
|
56
|
-
let end =
|
|
74
|
+
let start = Math.max(0, spans[0] - window);
|
|
75
|
+
let end = spans[1] + 1;
|
|
57
76
|
const flush = () => {
|
|
77
|
+
const seg = text.slice(start, end);
|
|
58
78
|
// A sentinel before a window that does not start the text keeps `^` (start of text) from matching mid-text.
|
|
59
|
-
const piece = start > 0 ? fn(`x${
|
|
79
|
+
const piece = needs && !seg.includes(needs) ? seg : start > 0 ? fn(`x${seg}`).slice(1) : fn(seg);
|
|
60
80
|
out += text.slice(copied, start) + piece;
|
|
61
81
|
copied = Math.min(end, text.length);
|
|
62
82
|
};
|
|
63
|
-
for (
|
|
64
|
-
const s = Math.max(0,
|
|
83
|
+
for (let i = 2; i < spans.length; i += 2) {
|
|
84
|
+
const s = Math.max(0, spans[i] - window);
|
|
65
85
|
if (s <= end) {
|
|
66
|
-
end =
|
|
86
|
+
end = spans[i + 1] + 1;
|
|
67
87
|
continue;
|
|
68
88
|
}
|
|
69
89
|
flush();
|
|
70
90
|
start = s;
|
|
71
|
-
end =
|
|
91
|
+
end = spans[i + 1] + 1;
|
|
72
92
|
}
|
|
73
93
|
flush();
|
|
74
94
|
return out + text.slice(copied);
|
|
@@ -83,8 +103,10 @@ export function redactUserinfo(text, mask = '***') {
|
|
|
83
103
|
// Pre-check: no `@`, `@` or `%40` means no userinfo in any form.
|
|
84
104
|
if (!/[@@]|%(?:25){0,2}40/i.test(text))
|
|
85
105
|
return text;
|
|
86
|
-
const urlForms = overHits(text, URL_WINDOW, (t) => t.replace(ENCODED_USERINFO, `$1${mask}%40`).replace(USERINFO, `$1${mask}@`));
|
|
87
|
-
|
|
106
|
+
const urlForms = overHits(text, hitSpans(text, AT_HITS), URL_WINDOW, (t) => t.replace(ENCODED_USERINFO, `$1${mask}%40`).replace(USERINFO, `$1${mask}@`));
|
|
107
|
+
if (!urlForms.includes(':'))
|
|
108
|
+
return urlForms; // the scheme-less form needs its colon
|
|
109
|
+
return overHits(urlForms, hitSpans(urlForms, BARE_HITS), BARE_WINDOW, (t) => t.replace(BARE_USERINFO, `$1${mask}@`), ':');
|
|
88
110
|
}
|
|
89
111
|
/** `url` without its userinfo (`https://u:p@host/x` becomes `https://host/x`); text that is not an absolute URL passes through redactUserinfo. */
|
|
90
112
|
export function stripUserinfo(url) {
|