@onesi/genesis 0.0.1-stage → 0.1.13
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 +29 -0
- package/dist/beacons.d.ts +103 -0
- package/dist/beacons.js +77 -0
- package/dist/blinds-owner-enrollment.d.ts +171 -0
- package/dist/blinds-owner-enrollment.js +150 -0
- package/dist/client.d.ts +19996 -0
- package/dist/client.js +277 -0
- package/dist/context.d.ts +50 -0
- package/dist/context.js +153 -0
- package/dist/dials.d.ts +299 -0
- package/dist/dials.js +100 -0
- package/dist/errors.d.ts +35 -0
- package/dist/errors.js +66 -0
- package/dist/flares.d.ts +170 -0
- package/dist/flares.js +56 -0
- package/dist/fleets.d.ts +186 -0
- package/dist/fleets.js +136 -0
- package/dist/flocks.d.ts +155 -0
- package/dist/flocks.js +39 -0
- package/dist/foundry-billing.d.ts +97 -0
- package/dist/foundry-billing.js +107 -0
- package/dist/gears.d.ts +107 -0
- package/dist/gears.js +20 -0
- package/dist/generated/operations.d.ts +19949 -0
- package/dist/generated/operations.js +23846 -0
- package/dist/generated/schema.d.ts +35413 -0
- package/dist/generated/schema.js +1 -0
- package/dist/genesis.d.ts +2926 -0
- package/dist/genesis.js +206 -0
- package/dist/genesis.openapi.json +49321 -0
- package/dist/henry.d.ts +168 -0
- package/dist/henry.js +45 -0
- package/dist/hives-cells.d.ts +127 -0
- package/dist/hives-cells.js +151 -0
- package/dist/hives-environment.d.ts +28 -0
- package/dist/hives-environment.js +58 -0
- package/dist/hives-functions.d.ts +36 -0
- package/dist/hives-functions.js +185 -0
- package/dist/hives-marketplace.d.ts +128 -0
- package/dist/hives-marketplace.js +187 -0
- package/dist/hives-node.d.ts +9 -0
- package/dist/hives-node.js +152 -0
- package/dist/hives-operations.d.ts +337 -0
- package/dist/hives-operations.js +41 -0
- package/dist/hives-queue-consumer.d.ts +56 -0
- package/dist/hives-queue-consumer.js +95 -0
- package/dist/hives-queue-funding.d.ts +28 -0
- package/dist/hives-queue-funding.js +81 -0
- package/dist/hives-queues.d.ts +137 -0
- package/dist/hives-queues.js +143 -0
- package/dist/hives-resources-transport.d.ts +23 -0
- package/dist/hives-resources-transport.js +204 -0
- package/dist/hives-response.d.ts +2 -0
- package/dist/hives-response.js +32 -0
- package/dist/hives-runtimes.d.ts +34 -0
- package/dist/hives-runtimes.js +32 -0
- package/dist/hives-topics.d.ts +51 -0
- package/dist/hives-topics.js +79 -0
- package/dist/hives-upload.d.ts +9 -0
- package/dist/hives-upload.js +23 -0
- package/dist/hives-volumes.d.ts +64 -0
- package/dist/hives-volumes.js +117 -0
- package/dist/idempotency.d.ts +4 -0
- package/dist/idempotency.js +17 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +25 -0
- package/dist/instances.d.ts +25 -0
- package/dist/instances.js +11 -0
- package/dist/lanes.d.ts +267 -0
- package/dist/lanes.js +41 -0
- package/dist/minds-agent.d.ts +60 -0
- package/dist/minds-agent.js +190 -0
- package/dist/minds-owner.d.ts +110 -0
- package/dist/minds-owner.js +226 -0
- package/dist/minds.d.ts +269 -0
- package/dist/minds.js +193 -0
- package/dist/relays-enrollment.d.ts +33 -0
- package/dist/relays-enrollment.js +115 -0
- package/dist/runner-grant.d.ts +10 -0
- package/dist/runner-grant.js +133 -0
- package/dist/runner.d.ts +68 -0
- package/dist/runner.js +116 -0
- package/dist/types.d.ts +87 -0
- package/dist/types.js +1 -0
- package/dist/urls.d.ts +6 -0
- package/dist/urls.js +31 -0
- package/package.json +49 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { type HivesQueueOperation, type HivesQueueSendOptions } from './hives-queue-funding.js';
|
|
2
|
+
import type { GenesisClient } from './client.js';
|
|
3
|
+
import { type HivesResourceOptions } from './hives-resources-transport.js';
|
|
4
|
+
export interface HivesQueueConfig {
|
|
5
|
+
retentionPeriod: number;
|
|
6
|
+
visibilityTimeout: number;
|
|
7
|
+
maxReceiveCount: number;
|
|
8
|
+
deadLetterQueueId?: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface HivesQueue extends HivesQueueConfig {
|
|
11
|
+
id: string;
|
|
12
|
+
projectId: string;
|
|
13
|
+
name: string;
|
|
14
|
+
type: 'standard' | 'dead_letter' | 'fifo';
|
|
15
|
+
status: 'active' | 'paused';
|
|
16
|
+
deliveryAvailable: boolean;
|
|
17
|
+
maxMessageSize: number;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
messageCount: number;
|
|
21
|
+
messagesProcessing: number;
|
|
22
|
+
delayedMessages: number;
|
|
23
|
+
retainedMessages: number;
|
|
24
|
+
retainedPayloadBytes: number;
|
|
25
|
+
consumerCount: null;
|
|
26
|
+
throughputPerSecond: null;
|
|
27
|
+
avgProcessingTimeMs: null;
|
|
28
|
+
}
|
|
29
|
+
export interface HivesQueueCreate {
|
|
30
|
+
name: string;
|
|
31
|
+
type?: 'standard' | 'dead_letter' | 'fifo';
|
|
32
|
+
retentionPeriod?: number;
|
|
33
|
+
visibilityTimeout?: number;
|
|
34
|
+
maxReceiveCount?: number;
|
|
35
|
+
deadLetterQueueId?: string | null;
|
|
36
|
+
}
|
|
37
|
+
export interface HivesQueueSend {
|
|
38
|
+
body?: unknown;
|
|
39
|
+
body_base64?: string;
|
|
40
|
+
attributes?: Record<string, string>;
|
|
41
|
+
message_group_id?: string;
|
|
42
|
+
deduplication_id?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface HivesQueueDelivery {
|
|
45
|
+
id: string;
|
|
46
|
+
body_base64: string;
|
|
47
|
+
attributes: Record<string, string>;
|
|
48
|
+
receive_count: number;
|
|
49
|
+
receipt_handle: string;
|
|
50
|
+
lease_expires_at: string;
|
|
51
|
+
created_at: string;
|
|
52
|
+
message_group_id?: string;
|
|
53
|
+
sequence_number?: number;
|
|
54
|
+
}
|
|
55
|
+
export interface HivesDeadLetter {
|
|
56
|
+
id: string;
|
|
57
|
+
queue_id: string;
|
|
58
|
+
original_queue_id: string | null;
|
|
59
|
+
original_message_id: string | null;
|
|
60
|
+
body_base64: string;
|
|
61
|
+
attributes: Record<string, string>;
|
|
62
|
+
receive_count: number;
|
|
63
|
+
reason: string | null;
|
|
64
|
+
moved_at: string | null;
|
|
65
|
+
}
|
|
66
|
+
export interface HivesDeadLetterStats {
|
|
67
|
+
total_messages: number;
|
|
68
|
+
oldest_message_at: string | null;
|
|
69
|
+
newest_message_at: string | null;
|
|
70
|
+
average_receive_count: number | null;
|
|
71
|
+
retained_payload_bytes: number;
|
|
72
|
+
}
|
|
73
|
+
export declare function hivesQueueBody(encoded: string): Uint8Array;
|
|
74
|
+
export declare function hivesQueues(client: GenesisClient): {
|
|
75
|
+
consumer: {
|
|
76
|
+
get(project: string, queue: string, options?: HivesResourceOptions): Promise<import("./hives-queue-consumer.js").HivesQueueConsumerStatus>;
|
|
77
|
+
configure(project: string, queue: string, input: import("./hives-queue-consumer.js").HivesQueueConsumerConfig, options?: HivesResourceOptions): Promise<import("./hives-queue-consumer.js").HivesQueueConsumerBinding>;
|
|
78
|
+
remove(project: string, queue: string, options?: HivesResourceOptions): Promise<{
|
|
79
|
+
success: true;
|
|
80
|
+
queueId: string;
|
|
81
|
+
}>;
|
|
82
|
+
};
|
|
83
|
+
list(project: string, options?: HivesResourceOptions): Promise<{
|
|
84
|
+
data: HivesQueue[];
|
|
85
|
+
engine_available: true;
|
|
86
|
+
}>;
|
|
87
|
+
get(project: string, id: string, options?: HivesResourceOptions): Promise<HivesQueue>;
|
|
88
|
+
create(project: string, body: HivesQueueCreate, options?: HivesResourceOptions): Promise<HivesQueue>;
|
|
89
|
+
configure(project: string, id: string, body: HivesQueueConfig, options?: HivesResourceOptions): Promise<HivesQueue>;
|
|
90
|
+
remove(project: string, id: string, options?: HivesResourceOptions): Promise<{
|
|
91
|
+
deleted: true;
|
|
92
|
+
}>;
|
|
93
|
+
stats(project: string, id: string, options?: HivesResourceOptions): Promise<HivesQueue>;
|
|
94
|
+
consumers: (project: string, id: string, options?: HivesResourceOptions) => Promise<never>;
|
|
95
|
+
pause(project: string, id: string, options?: HivesResourceOptions): Promise<HivesQueue>;
|
|
96
|
+
resume(project: string, id: string, options?: HivesResourceOptions): Promise<HivesQueue>;
|
|
97
|
+
purge(project: string, id: string, options?: HivesResourceOptions): Promise<{
|
|
98
|
+
purged: number;
|
|
99
|
+
}>;
|
|
100
|
+
send(project: string, id: string, body: HivesQueueSend, options?: HivesQueueSendOptions): Promise<HivesQueueOperation | {
|
|
101
|
+
message_id: string;
|
|
102
|
+
}>;
|
|
103
|
+
operations: {
|
|
104
|
+
get(project: string, id: string, operationId: string, options?: HivesResourceOptions): Promise<HivesQueueOperation>;
|
|
105
|
+
};
|
|
106
|
+
receive(project: string, id: string, body?: {
|
|
107
|
+
maxMessages?: number;
|
|
108
|
+
waitSeconds?: number;
|
|
109
|
+
}, options?: HivesResourceOptions): Promise<{
|
|
110
|
+
messages: HivesQueueDelivery[];
|
|
111
|
+
}>;
|
|
112
|
+
ack: (project: string, id: string, message: string, receipt: string, options?: HivesResourceOptions) => Promise<{
|
|
113
|
+
acknowledged: boolean;
|
|
114
|
+
released: boolean;
|
|
115
|
+
}>;
|
|
116
|
+
nack: (project: string, id: string, message: string, receipt: string, options?: HivesResourceOptions) => Promise<{
|
|
117
|
+
acknowledged: boolean;
|
|
118
|
+
released: boolean;
|
|
119
|
+
}>;
|
|
120
|
+
deadLetters: (project: string, id: string, query?: {
|
|
121
|
+
limit?: number;
|
|
122
|
+
offset?: number;
|
|
123
|
+
}, options?: HivesResourceOptions) => Promise<{
|
|
124
|
+
messages: HivesDeadLetter[];
|
|
125
|
+
}>;
|
|
126
|
+
deadLetterStats: (project: string, id: string, options?: HivesResourceOptions) => Promise<HivesDeadLetterStats>;
|
|
127
|
+
replay(project: string, id: string, message: string, options?: HivesResourceOptions): Promise<{
|
|
128
|
+
message_id: string;
|
|
129
|
+
replayed: 1;
|
|
130
|
+
}>;
|
|
131
|
+
deleteDeadLetter(project: string, id: string, message: string, options?: HivesResourceOptions): Promise<{
|
|
132
|
+
deleted: true;
|
|
133
|
+
}>;
|
|
134
|
+
purgeDeadLetters(project: string, id: string, options?: HivesResourceOptions): Promise<{
|
|
135
|
+
purged: number;
|
|
136
|
+
}>;
|
|
137
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { hivesQueueOperation, hivesQueueOperationId, hivesQueueSendHeaders } from './hives-queue-funding.js';
|
|
2
|
+
import { hivesQueueConsumer } from './hives-queue-consumer.js';
|
|
3
|
+
import { HIVES_QUEUE_BYTES, hivesResourceCall, hivesResourceId, resourceError } from './hives-resources-transport.js';
|
|
4
|
+
export function hivesQueueBody(encoded) {
|
|
5
|
+
if (typeof encoded !== 'string' || encoded.length > Math.ceil(HIVES_QUEUE_BYTES / 3) * 4 || encoded.length % 4 || !/^[A-Za-z0-9+/]*={0,2}$/.test(encoded))
|
|
6
|
+
throw resourceError(0);
|
|
7
|
+
try {
|
|
8
|
+
const bytes = atob(encoded);
|
|
9
|
+
if (btoa(bytes) !== encoded || bytes.length > HIVES_QUEUE_BYTES)
|
|
10
|
+
throw resourceError(0);
|
|
11
|
+
return Uint8Array.from(bytes, c => c.charCodeAt(0));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw resourceError(0);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function config(body, required = false) {
|
|
18
|
+
const ranges = [{ key: 'retentionPeriod', min: 3600, max: 336 * 3600, divisor: 3600 }, { key: 'visibilityTimeout', min: 1, max: 43200 }, { key: 'maxReceiveCount', min: 1, max: 1000 }];
|
|
19
|
+
for (const r of ranges) {
|
|
20
|
+
const value = body[r.key];
|
|
21
|
+
if (value === undefined && !required)
|
|
22
|
+
continue;
|
|
23
|
+
if (typeof value !== 'number' || !Number.isInteger(value) || value < r.min || value > r.max || r.divisor && value % r.divisor)
|
|
24
|
+
throw resourceError(0);
|
|
25
|
+
}
|
|
26
|
+
if (body.deadLetterQueueId != null)
|
|
27
|
+
hivesResourceId(body.deadLetterQueueId);
|
|
28
|
+
}
|
|
29
|
+
function queue(value, project, id) {
|
|
30
|
+
if (!value || value.projectId !== project || typeof value.id !== 'string' || id !== undefined && value.id !== id || !['standard', 'dead_letter', 'fifo'].includes(value.type) || !['active', 'paused'].includes(value.status) || typeof value.deliveryAvailable !== 'boolean')
|
|
31
|
+
throw resourceError(0);
|
|
32
|
+
const counts = [value.messageCount, value.messagesProcessing, value.delayedMessages, value.retainedMessages, value.retainedPayloadBytes];
|
|
33
|
+
if (counts.some(v => !Number.isSafeInteger(v) || v < 0) || value.consumerCount !== null || value.throughputPerSecond !== null || value.avgProcessingTimeMs !== null)
|
|
34
|
+
throw resourceError(0);
|
|
35
|
+
return Object.fromEntries(['id', 'projectId', 'name', 'type', 'status', 'deliveryAvailable', 'retentionPeriod', 'visibilityTimeout', 'maxReceiveCount', 'deadLetterQueueId', 'maxMessageSize', 'createdAt', 'updatedAt', 'messageCount', 'messagesProcessing', 'delayedMessages', 'retainedMessages', 'retainedPayloadBytes', 'consumerCount', 'throughputPerSecond', 'avgProcessingTimeMs'].map(k => [k, value[k]]));
|
|
36
|
+
}
|
|
37
|
+
function fifoIdentity(value) { return typeof value === 'string' && /^[!-~]{1,128}$/.test(value); }
|
|
38
|
+
function send(body) {
|
|
39
|
+
if (!body || typeof body !== 'object' || Object.keys(body).some(k => !['body', 'body_base64', 'attributes', 'message_group_id', 'deduplication_id'].includes(k)) || (body.body != null) === (body.body_base64 != null))
|
|
40
|
+
throw resourceError(0);
|
|
41
|
+
if (body.message_group_id !== undefined || body.deduplication_id !== undefined) {
|
|
42
|
+
if (!fifoIdentity(body.message_group_id) || !fifoIdentity(body.deduplication_id))
|
|
43
|
+
throw resourceError(0);
|
|
44
|
+
}
|
|
45
|
+
if (body.body_base64 != null)
|
|
46
|
+
hivesQueueBody(body.body_base64);
|
|
47
|
+
else {
|
|
48
|
+
let value;
|
|
49
|
+
try {
|
|
50
|
+
value = typeof body.body === 'string' ? body.body : JSON.stringify(body.body);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw resourceError(0);
|
|
54
|
+
}
|
|
55
|
+
if (value === undefined || new TextEncoder().encode(value).length > HIVES_QUEUE_BYTES)
|
|
56
|
+
throw resourceError(0);
|
|
57
|
+
}
|
|
58
|
+
if (body.attributes !== undefined) {
|
|
59
|
+
if (!body.attributes || typeof body.attributes !== 'object' || Array.isArray(body.attributes) || Object.keys(body.attributes).length > 64 || Object.entries(body.attributes).some(([k, v]) => !k || new TextEncoder().encode(k).length > 128 || k.startsWith('buzz.') || typeof v !== 'string') || new TextEncoder().encode(JSON.stringify(body.attributes)).length > 8192)
|
|
60
|
+
throw resourceError(0);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function hivesQueues(client) {
|
|
64
|
+
const ids = (project_id, queue_id) => ({ project_id: hivesResourceId(project_id), ...(queue_id === undefined ? {} : { queue_id: hivesResourceId(queue_id) }) });
|
|
65
|
+
const call = (operation, input, options, limit = 2 * 1024 * 1024) => hivesResourceCall(client, operation, input, options, 'json', limit, 20_000);
|
|
66
|
+
const ack = async (project, id, message, receipt, release, options) => {
|
|
67
|
+
if (typeof receipt !== 'string' || !/^rh_[a-f0-9]{32}$/.test(receipt))
|
|
68
|
+
throw resourceError(0);
|
|
69
|
+
const result = await call(release ? 'hives_nack_native_queue' : 'hives_ack_native_queue', { ...ids(project, id), message_id: hivesResourceId(message), body: { receiptHandle: receipt } }, options);
|
|
70
|
+
if (!result || result.acknowledged !== !release || result.released !== release)
|
|
71
|
+
throw resourceError(0);
|
|
72
|
+
return result;
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
consumer: hivesQueueConsumer(client),
|
|
76
|
+
async list(project, options) { const result = await call('hives_list_native_queue', ids(project), options); if (!result || !Array.isArray(result.data) || result.engine_available !== true)
|
|
77
|
+
throw resourceError(0); return { ...result, data: result.data.map(row => queue(row, project)) }; },
|
|
78
|
+
async get(project, id, options) { return queue(await call('hives_inspect_native_queue', ids(project, id), options), project, id); },
|
|
79
|
+
async create(project, body, options) { if (!body || !/^[A-Za-z0-9_-]{1,128}$/.test(body.name) || body.type !== undefined && !['standard', 'dead_letter', 'fifo'].includes(body.type) || Object.keys(body).some(k => !['name', 'type', 'retentionPeriod', 'visibilityTimeout', 'maxReceiveCount', 'deadLetterQueueId'].includes(k)))
|
|
80
|
+
throw resourceError(0); config(body); return queue(await call('hives_create_native_queue', { ...ids(project), body }, options), project); },
|
|
81
|
+
async configure(project, id, body, options) { if (!body || Object.keys(body).some(k => !['retentionPeriod', 'visibilityTimeout', 'maxReceiveCount', 'deadLetterQueueId'].includes(k)))
|
|
82
|
+
throw resourceError(0); config(body, true); return queue(await call('hives_configure_native_queue', { ...ids(project, id), body }, options), project, id); },
|
|
83
|
+
async remove(project, id, options) { const result = await call('hives_delete_native_queue', ids(project, id), options); if (result?.deleted !== true)
|
|
84
|
+
throw resourceError(0); return result; },
|
|
85
|
+
async stats(project, id, options) { return queue(await call('hives_stats_native_queue', ids(project, id), options), project, id); },
|
|
86
|
+
consumers: (project, id, options) => call('hives_consumers_native_queue', ids(project, id), options),
|
|
87
|
+
async pause(project, id, options) { return queue(await call('hives_pause_native_queue', ids(project, id), options), project, id); },
|
|
88
|
+
async resume(project, id, options) { return queue(await call('hives_resume_native_queue', ids(project, id), options), project, id); },
|
|
89
|
+
async purge(project, id, options) { const result = await call('hives_purge_native_queue', ids(project, id), options); if (!Number.isSafeInteger(result?.purged) || result.purged < 0)
|
|
90
|
+
throw resourceError(0); return result; },
|
|
91
|
+
async send(project, id, body, options = {}) {
|
|
92
|
+
send(body);
|
|
93
|
+
const headers = hivesQueueSendHeaders(options);
|
|
94
|
+
if (options.idempotencyKey !== undefined && (body.message_group_id !== undefined || body.deduplication_id !== undefined))
|
|
95
|
+
throw resourceError(0);
|
|
96
|
+
let operation;
|
|
97
|
+
const result = await hivesResourceCall(client, 'hives_send_native_queue', { ...ids(project, id), body }, options, 'json', 4096, 20_000, undefined, { headers, onResponse: r => {
|
|
98
|
+
const value = r.headers.get('x-hives-operation-id');
|
|
99
|
+
if (value !== null)
|
|
100
|
+
operation = hivesQueueOperationId(value);
|
|
101
|
+
if (options.idempotencyKey !== undefined && !operation)
|
|
102
|
+
throw resourceError(0);
|
|
103
|
+
} });
|
|
104
|
+
if (operation)
|
|
105
|
+
return hivesQueueOperation(result, operation);
|
|
106
|
+
hivesResourceId(result?.message_id);
|
|
107
|
+
return result;
|
|
108
|
+
},
|
|
109
|
+
operations: { async get(project, id, operationId, options) {
|
|
110
|
+
hivesQueueOperationId(operationId);
|
|
111
|
+
const result = await hivesResourceCall(client, 'hives_get_operation_native_queue', { ...ids(project, id), operation_id: operationId }, options, 'json', 4096, 20_000, undefined, { onResponse: r => {
|
|
112
|
+
if (r.headers.get('x-hives-operation-id') !== operationId)
|
|
113
|
+
throw resourceError(0);
|
|
114
|
+
} });
|
|
115
|
+
return hivesQueueOperation(result, operationId);
|
|
116
|
+
} },
|
|
117
|
+
async receive(project, id, body = {}, options) { if (Object.keys(body).some(k => !['maxMessages', 'waitSeconds'].includes(k)) || body.maxMessages !== undefined && (!Number.isInteger(body.maxMessages) || body.maxMessages < 1 || body.maxMessages > 10) || body.waitSeconds !== undefined && (!Number.isInteger(body.waitSeconds) || body.waitSeconds < 0 || body.waitSeconds > 10))
|
|
118
|
+
throw resourceError(0); const result = await call('hives_receive_native_queue', { ...ids(project, id), body }, options, 4 * 1024 * 1024); if (!result || !Array.isArray(result.messages) || result.messages.length > (body.maxMessages ?? 1))
|
|
119
|
+
throw resourceError(0); for (const row of result.messages) {
|
|
120
|
+
hivesResourceId(row.id);
|
|
121
|
+
hivesQueueBody(row.body_base64);
|
|
122
|
+
if (!/^rh_[a-f0-9]{32}$/.test(row.receipt_handle))
|
|
123
|
+
throw resourceError(0);
|
|
124
|
+
if (row.message_group_id !== undefined || row.sequence_number !== undefined) {
|
|
125
|
+
if (!fifoIdentity(row.message_group_id) || !Number.isSafeInteger(row.sequence_number) || (row.sequence_number ?? 0) < 1)
|
|
126
|
+
throw resourceError(0);
|
|
127
|
+
}
|
|
128
|
+
} return result; },
|
|
129
|
+
ack: (project, id, message, receipt, options) => ack(project, id, message, receipt, false, options),
|
|
130
|
+
nack: (project, id, message, receipt, options) => ack(project, id, message, receipt, true, options),
|
|
131
|
+
deadLetters: async (project, id, query = {}, options) => { if (query.limit !== undefined && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 10) || query.offset !== undefined && (!Number.isInteger(query.offset) || query.offset < 0 || query.offset > 8192))
|
|
132
|
+
throw resourceError(0); const result = await call('hives_dead_letters_native_queue', { ...query, ...ids(project, id) }, options, 4 * 1024 * 1024); if (!result || !Array.isArray(result.messages) || result.messages.length > (query.limit ?? 10))
|
|
133
|
+
throw resourceError(0); for (const row of result.messages)
|
|
134
|
+
hivesQueueBody(row.body_base64); return result; },
|
|
135
|
+
deadLetterStats: (project, id, options) => call('hives_dlq_stats_native_queue', ids(project, id), options),
|
|
136
|
+
async replay(project, id, message, options) { const result = await call('hives_replay_native_queue', { ...ids(project, id), body: { message_id: hivesResourceId(message) } }, options); if (result?.replayed !== 1)
|
|
137
|
+
throw resourceError(0); hivesResourceId(result.message_id); return result; },
|
|
138
|
+
async deleteDeadLetter(project, id, message, options) { const result = await call('hives_delete_dlq_native_queue', { ...ids(project, id), message_id: hivesResourceId(message) }, options); if (result?.deleted !== true)
|
|
139
|
+
throw resourceError(0); return result; },
|
|
140
|
+
async purgeDeadLetters(project, id, options) { const result = await call('hives_purge_dlq_native_queue', ids(project, id), options); if (!Number.isSafeInteger(result?.purged) || result.purged < 0)
|
|
141
|
+
throw resourceError(0); return result; },
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { GenesisClient } from './client.js';
|
|
2
|
+
import { GenesisError } from './errors.js';
|
|
3
|
+
export declare const HIVES_OBJECT_BYTES: number;
|
|
4
|
+
export declare const HIVES_QUEUE_BYTES: number;
|
|
5
|
+
export declare const HIVES_RESOURCE_JSON_BYTES: number;
|
|
6
|
+
export interface HivesResourceOptions {
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
}
|
|
9
|
+
export declare function hivesResourceId(value: string): string;
|
|
10
|
+
export declare function resourceError(status: number, id?: string): GenesisError;
|
|
11
|
+
/** A non-2xx Hives resource reply as a GenesisError with the gateway's code, request id and required scope (bounded read, body discarded). */
|
|
12
|
+
export declare function resourceErrorFromResponse(response: Response, id?: string): Promise<GenesisError>;
|
|
13
|
+
export declare const isHivesResourceOperation: (id: string) => boolean;
|
|
14
|
+
export declare const isHivesObjectUpload: (id: string) => id is "hives_upload_object_by_key" | "hives_upload_object";
|
|
15
|
+
/** Shared-client hook proposal: snapshot only the two real raw Cells upload operations. */
|
|
16
|
+
export declare function hivesObjectBody(value: unknown): Promise<ArrayBuffer>;
|
|
17
|
+
export declare function hivesContentType(value?: string): string;
|
|
18
|
+
export declare function hivesResourceBytes(response: Response, limit: number, signal?: AbortSignal): Promise<Uint8Array>;
|
|
19
|
+
/** Whole operation budget includes credential/fetch and incremental body read. No retries or redirects. */
|
|
20
|
+
export declare function hivesResourceCall<T>(client: GenesisClient, id: string, input: Record<string, unknown>, options?: HivesResourceOptions, mode?: 'json' | 'empty' | 'binary', limit?: number, budget?: number, expectedStatus?: number, request?: {
|
|
21
|
+
headers?: Record<string, string>;
|
|
22
|
+
onResponse?: (response: Response) => void;
|
|
23
|
+
}): Promise<T>;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { GenesisError } from './errors.js';
|
|
2
|
+
export const HIVES_OBJECT_BYTES = 10 * 1024 * 1024;
|
|
3
|
+
export const HIVES_QUEUE_BYTES = 256 * 1024;
|
|
4
|
+
export const HIVES_RESOURCE_JSON_BYTES = 2 * 1024 * 1024;
|
|
5
|
+
export function hivesResourceId(value) {
|
|
6
|
+
if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/.test(value))
|
|
7
|
+
throw resourceError(0);
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
export function resourceError(status, id) {
|
|
11
|
+
return new GenesisError({ status, type: status ? `http_${status}` : 'invalid_request', operationId: id,
|
|
12
|
+
message: status === 404 ? 'Hives resource not found in the authenticated organization and project.'
|
|
13
|
+
: status === 409 ? 'Hives resource state conflicted. Read persisted state before another mutation.'
|
|
14
|
+
: status === 503 ? 'Hives outcome is unavailable. Read persisted state or reconcile before another mutation.'
|
|
15
|
+
: 'Hives resource request failed. Check the request and persisted state; no automatic retry was made.' });
|
|
16
|
+
}
|
|
17
|
+
// Gateway catalog codes are upper case; Hives' own codes are lower case (queue_state_conflict, selected_context_required…).
|
|
18
|
+
const CODE = /^(?:[A-Z][A-Z0-9_]{1,63}|[a-z][a-z0-9_]{2,63})$/, REQUEST_ID = /^[A-Za-z0-9._:-]{1,128}$/, SCOPE = /^[a-z][a-z0-9_.:-]{0,127}$/;
|
|
19
|
+
function catalogFields(body, header) {
|
|
20
|
+
const top = body && typeof body === 'object' ? body : {};
|
|
21
|
+
const nested = top.error && typeof top.error === 'object' ? top.error : {};
|
|
22
|
+
const pick = (re, ...values) => values.find((v) => typeof v === 'string' && re.test(v));
|
|
23
|
+
return {
|
|
24
|
+
code: pick(CODE, nested.code, top.code),
|
|
25
|
+
requestId: pick(REQUEST_ID, header, nested.request_id, top.request_id),
|
|
26
|
+
requiredScope: pick(SCOPE, nested.required_scope, top.required_scope),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** A non-2xx Hives resource reply as a GenesisError with the gateway's code, request id and required scope (bounded read, body discarded). */
|
|
30
|
+
export async function resourceErrorFromResponse(response, id) {
|
|
31
|
+
let body;
|
|
32
|
+
try {
|
|
33
|
+
body = JSON.parse(new TextDecoder().decode(await hivesResourceBytes(response, 16 * 1024)));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
await response.body?.cancel().catch(() => { });
|
|
37
|
+
}
|
|
38
|
+
const fields = catalogFields(body, response.headers.get('x-request-id'));
|
|
39
|
+
const base = resourceError(response.status, id);
|
|
40
|
+
// Codes whose fix is not 're-read state': fixed SDK guidance, never the server's text.
|
|
41
|
+
const guidance = {
|
|
42
|
+
selected_context_required: 'Select an authorized Genesis organization, workspace and project (genesis context select), then retry.',
|
|
43
|
+
queue_persistence_unavailable: 'Hives queue storage is unavailable and nothing was confirmed. Check the queue, or retry with the same idempotency key, before sending again.',
|
|
44
|
+
};
|
|
45
|
+
const known = fields.code?.toLowerCase(); // the gateway envelope upper-cases upstream codes
|
|
46
|
+
const lead = (known && Object.hasOwn(guidance, known) ? guidance[known] : undefined) ?? base.message;
|
|
47
|
+
const detail = [fields.code, fields.requiredScope && `required scope ${fields.requiredScope}`].filter(Boolean).join('; ');
|
|
48
|
+
return new GenesisError({ status: base.status, type: base.type, operationId: id,
|
|
49
|
+
message: detail ? `${lead} (${detail})` : lead,
|
|
50
|
+
code: fields.code, requestId: fields.requestId,
|
|
51
|
+
body: fields.code || fields.requiredScope ? { error: { code: fields.code, request_id: fields.requestId, required_scope: fields.requiredScope } } : undefined });
|
|
52
|
+
}
|
|
53
|
+
export const isHivesResourceOperation = (id) => /^(?:hives_marketplace_(?:categories|featured|installed|get_installation|uninstall|reconcile|list_packages|publish|get_package|install|update|list_versions)|hives_(?:get|configure|remove)_native_queue_consumer|hives_.*_native_queue|hives_.*_native_topic|hives_(?:(?:list_volumes|create_volume|get_volume|delete_volume|mount_volume|unmount_volume)|list_buckets|create_bucket|get_bucket|delete_bucket|list_objects|upload_object(?:_by_key)?|delete_object(?:_by_key)?|download_object_by_key|get_cors_config|set_cors_config|generate_presigned_url|reconcile|list_runtimes|get_runtime|select_runtime|list_project_runtimes))$/.test(id);
|
|
54
|
+
export const isHivesObjectUpload = (id) => id === 'hives_upload_object_by_key' || id === 'hives_upload_object';
|
|
55
|
+
/** Shared-client hook proposal: snapshot only the two real raw Cells upload operations. */
|
|
56
|
+
export async function hivesObjectBody(value) {
|
|
57
|
+
let bytes;
|
|
58
|
+
if (value instanceof Blob) {
|
|
59
|
+
if (value.size > HIVES_OBJECT_BYTES)
|
|
60
|
+
throw resourceError(0);
|
|
61
|
+
bytes = new Uint8Array(await value.arrayBuffer());
|
|
62
|
+
}
|
|
63
|
+
else if (value instanceof ArrayBuffer)
|
|
64
|
+
bytes = new Uint8Array(value);
|
|
65
|
+
else if (ArrayBuffer.isView(value))
|
|
66
|
+
bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
67
|
+
else
|
|
68
|
+
throw resourceError(0);
|
|
69
|
+
if (bytes.byteLength > HIVES_OBJECT_BYTES)
|
|
70
|
+
throw resourceError(0);
|
|
71
|
+
return Uint8Array.from(bytes).buffer;
|
|
72
|
+
}
|
|
73
|
+
export function hivesContentType(value = 'application/octet-stream') {
|
|
74
|
+
if (typeof value !== 'string' || !value.length || new TextEncoder().encode(value).length > 512 || /[\u0000-\u001f\u007f]/.test(value))
|
|
75
|
+
throw resourceError(0);
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
export async function hivesResourceBytes(response, limit, signal) {
|
|
79
|
+
const chunks = [];
|
|
80
|
+
let length = 0;
|
|
81
|
+
const reader = response.body?.getReader();
|
|
82
|
+
if (!reader)
|
|
83
|
+
return new Uint8Array();
|
|
84
|
+
const cancel = () => { void reader.cancel().catch(() => { }); };
|
|
85
|
+
signal?.addEventListener('abort', cancel, { once: true });
|
|
86
|
+
if (signal?.aborted)
|
|
87
|
+
cancel();
|
|
88
|
+
try {
|
|
89
|
+
for (;;) {
|
|
90
|
+
const next = await reader.read();
|
|
91
|
+
if (signal?.aborted)
|
|
92
|
+
throw resourceError(0);
|
|
93
|
+
if (next.done)
|
|
94
|
+
break;
|
|
95
|
+
length += next.value.byteLength;
|
|
96
|
+
if (length > limit) {
|
|
97
|
+
await reader.cancel();
|
|
98
|
+
throw resourceError(0);
|
|
99
|
+
}
|
|
100
|
+
chunks.push(next.value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
signal?.removeEventListener('abort', cancel);
|
|
105
|
+
reader.releaseLock();
|
|
106
|
+
}
|
|
107
|
+
const bytes = new Uint8Array(length);
|
|
108
|
+
let offset = 0;
|
|
109
|
+
for (const part of chunks) {
|
|
110
|
+
bytes.set(part, offset);
|
|
111
|
+
offset += part.byteLength;
|
|
112
|
+
}
|
|
113
|
+
return bytes;
|
|
114
|
+
}
|
|
115
|
+
/** Whole operation budget includes credential/fetch and incremental body read. No retries or redirects. */
|
|
116
|
+
export async function hivesResourceCall(client, id, input, options = {}, mode = 'json', limit = HIVES_RESOURCE_JSON_BYTES, budget = 20_000, expectedStatus, request) {
|
|
117
|
+
let snapshot;
|
|
118
|
+
try {
|
|
119
|
+
if (input.body instanceof ArrayBuffer)
|
|
120
|
+
snapshot = { ...input, body: input.body.slice(0) };
|
|
121
|
+
else {
|
|
122
|
+
const value = JSON.stringify(input);
|
|
123
|
+
if (new TextEncoder().encode(value).length > 512 * 1024)
|
|
124
|
+
throw resourceError(0);
|
|
125
|
+
snapshot = JSON.parse(value);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
throw resourceError(0, id);
|
|
130
|
+
}
|
|
131
|
+
const controller = new AbortController();
|
|
132
|
+
const abort = () => controller.abort();
|
|
133
|
+
let rejectAbort = () => { };
|
|
134
|
+
const failure = new Promise((_, reject) => { rejectAbort = reject; });
|
|
135
|
+
void failure.catch(() => { });
|
|
136
|
+
const aborted = () => rejectAbort(resourceError(0, id));
|
|
137
|
+
controller.signal.addEventListener('abort', aborted, { once: true });
|
|
138
|
+
options.signal?.addEventListener('abort', abort, { once: true });
|
|
139
|
+
const timer = setTimeout(abort, budget);
|
|
140
|
+
if (typeof timer === 'object' && 'unref' in timer)
|
|
141
|
+
timer.unref();
|
|
142
|
+
let response;
|
|
143
|
+
let completed = false;
|
|
144
|
+
const operation = (async () => {
|
|
145
|
+
if (options.signal?.aborted)
|
|
146
|
+
abort();
|
|
147
|
+
if (controller.signal.aborted)
|
|
148
|
+
throw resourceError(0, id);
|
|
149
|
+
response = await client.raw(id, snapshot, { signal: controller.signal, headers: request?.headers });
|
|
150
|
+
if (controller.signal.aborted) {
|
|
151
|
+
await response.body?.cancel();
|
|
152
|
+
throw resourceError(0, id);
|
|
153
|
+
}
|
|
154
|
+
request?.onResponse?.(response);
|
|
155
|
+
if (response.status < 200 || response.status >= 300)
|
|
156
|
+
throw await resourceErrorFromResponse(response, id);
|
|
157
|
+
if (expectedStatus !== undefined && response.status !== expectedStatus)
|
|
158
|
+
throw resourceError(0, id);
|
|
159
|
+
if (mode === 'empty' && ![200, 204].includes(response.status))
|
|
160
|
+
throw resourceError(0, id);
|
|
161
|
+
const bytes = await hivesResourceBytes(response, mode === 'empty' ? 0 : limit, controller.signal);
|
|
162
|
+
if (controller.signal.aborted)
|
|
163
|
+
throw resourceError(0, id);
|
|
164
|
+
if (mode === 'empty')
|
|
165
|
+
return undefined;
|
|
166
|
+
if (mode === 'binary') {
|
|
167
|
+
if (response.status !== 200)
|
|
168
|
+
throw resourceError(0, id);
|
|
169
|
+
const headers = new Headers({ 'content-type': hivesContentType(response.headers.get('content-type') ?? undefined), 'cache-control': 'no-store', 'content-disposition': 'attachment' });
|
|
170
|
+
return new Response(Uint8Array.from(bytes).buffer, { status: 200, headers });
|
|
171
|
+
}
|
|
172
|
+
if (!response.headers.get('content-type')?.toLowerCase().includes('application/json'))
|
|
173
|
+
throw resourceError(0, id);
|
|
174
|
+
try {
|
|
175
|
+
return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
throw resourceError(0, id);
|
|
179
|
+
}
|
|
180
|
+
})();
|
|
181
|
+
void operation.then(() => { if (controller.signal.aborted)
|
|
182
|
+
void response?.body?.cancel().catch(() => { }); }, () => { });
|
|
183
|
+
try {
|
|
184
|
+
const result = await Promise.race([operation, failure]);
|
|
185
|
+
completed = true;
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (error instanceof GenesisError && (error.type === 'hives_queue_operation' || isHivesResourceOperation(id) && (error.code !== undefined || error.requestId !== undefined)))
|
|
190
|
+
throw error; // already sanitized: catalog fields only
|
|
191
|
+
if (error instanceof GenesisError)
|
|
192
|
+
throw resourceError(error.status, id);
|
|
193
|
+
throw resourceError(0, id);
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
clearTimeout(timer);
|
|
197
|
+
options.signal?.removeEventListener('abort', abort);
|
|
198
|
+
controller.signal.removeEventListener('abort', aborted);
|
|
199
|
+
if (!completed) {
|
|
200
|
+
controller.abort();
|
|
201
|
+
void response?.body?.cancel().catch(() => { });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { MAX_FUNCTION_BODY_BYTES } from './hives-functions.js';
|
|
2
|
+
/** Bound completed response bytes without losing binary data or treating HTTP errors as JSON wrappers. */
|
|
3
|
+
export async function hivesResponseBytes(response) {
|
|
4
|
+
if (!response.body)
|
|
5
|
+
return new Uint8Array();
|
|
6
|
+
const reader = response.body.getReader();
|
|
7
|
+
const chunks = [];
|
|
8
|
+
let size = 0;
|
|
9
|
+
try {
|
|
10
|
+
for (;;) {
|
|
11
|
+
const { value, done } = await reader.read();
|
|
12
|
+
if (done)
|
|
13
|
+
break;
|
|
14
|
+
size += value.byteLength;
|
|
15
|
+
if (size > MAX_FUNCTION_BODY_BYTES) {
|
|
16
|
+
await reader.cancel();
|
|
17
|
+
throw new Error('Hives guest response exceeds 10 MiB.');
|
|
18
|
+
}
|
|
19
|
+
chunks.push(value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
reader.releaseLock();
|
|
24
|
+
}
|
|
25
|
+
const bytes = new Uint8Array(size);
|
|
26
|
+
let offset = 0;
|
|
27
|
+
for (const chunk of chunks) {
|
|
28
|
+
bytes.set(chunk, offset);
|
|
29
|
+
offset += chunk.length;
|
|
30
|
+
}
|
|
31
|
+
return bytes;
|
|
32
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { GenesisClient } from './client.js';
|
|
2
|
+
import { type HivesResourceOptions } from './hives-resources-transport.js';
|
|
3
|
+
export interface HivesRuntime {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
wasiVersions: string[];
|
|
7
|
+
runners: string[];
|
|
8
|
+
artifactKinds: string[];
|
|
9
|
+
compiledFeatures: string[];
|
|
10
|
+
capabilityScope: 'compiled_serving_implementation';
|
|
11
|
+
features: string[];
|
|
12
|
+
useCases: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface HivesRuntimeSelection {
|
|
15
|
+
selected: string;
|
|
16
|
+
reason: string;
|
|
17
|
+
wasi: string;
|
|
18
|
+
runner: string;
|
|
19
|
+
artifact: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function hivesRuntimes(client: GenesisClient): {
|
|
22
|
+
list: (options?: HivesResourceOptions) => Promise<{
|
|
23
|
+
runtimes: HivesRuntime[];
|
|
24
|
+
}>;
|
|
25
|
+
project: (project_id: string, options?: HivesResourceOptions) => Promise<{
|
|
26
|
+
runtimes: HivesRuntime[];
|
|
27
|
+
}>;
|
|
28
|
+
get: (name: string, options?: HivesResourceOptions) => Promise<HivesRuntime>;
|
|
29
|
+
select: (input: {
|
|
30
|
+
wasi: string;
|
|
31
|
+
runner: string;
|
|
32
|
+
artifact: string;
|
|
33
|
+
}, options?: HivesResourceOptions) => Promise<HivesRuntimeSelection>;
|
|
34
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { hivesResourceCall, hivesResourceId, resourceError } from './hives-resources-transport.js';
|
|
2
|
+
function runtime(value) {
|
|
3
|
+
if (!value || typeof value !== 'object')
|
|
4
|
+
throw resourceError(0);
|
|
5
|
+
const row = value;
|
|
6
|
+
if (typeof row.name !== 'string' || typeof row.version !== 'string' || row.capabilityScope !== 'compiled_serving_implementation'
|
|
7
|
+
|| ['wasiVersions', 'runners', 'artifactKinds', 'compiledFeatures', 'features', 'useCases'].some(k => !Array.isArray(row[k]) || !row[k].every(v => typeof v === 'string'))
|
|
8
|
+
|| !row.wasiVersions.length || !row.runners.length || !row.artifactKinds.length)
|
|
9
|
+
throw resourceError(0);
|
|
10
|
+
return { name: row.name, version: row.version, wasiVersions: [...row.wasiVersions], runners: [...row.runners], artifactKinds: [...row.artifactKinds], compiledFeatures: [...row.compiledFeatures], capabilityScope: row.capabilityScope, features: [...row.features], useCases: [...row.useCases] };
|
|
11
|
+
}
|
|
12
|
+
export function hivesRuntimes(client) {
|
|
13
|
+
const list = async (id, input, options) => {
|
|
14
|
+
const result = await hivesResourceCall(client, id, input, options);
|
|
15
|
+
if (!result || !Array.isArray(result.runtimes))
|
|
16
|
+
throw resourceError(0);
|
|
17
|
+
return { runtimes: result.runtimes.map(runtime) };
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
list: (options) => list('hives_list_runtimes', {}, options),
|
|
21
|
+
project: (project_id, options) => list('hives_list_project_runtimes', { project_id: hivesResourceId(project_id) }, options),
|
|
22
|
+
get: async (name, options) => runtime(await hivesResourceCall(client, 'hives_get_runtime', { name: hivesResourceId(name) }, options)),
|
|
23
|
+
select: async (input, options) => {
|
|
24
|
+
if (Object.keys(input).some(k => !['wasi', 'runner', 'artifact'].includes(k)) || Object.values(input).some(v => typeof v !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/.test(v)))
|
|
25
|
+
throw resourceError(0);
|
|
26
|
+
const result = await hivesResourceCall(client, 'hives_select_runtime', { ...input }, options);
|
|
27
|
+
if (!result || typeof result.selected !== 'string' || typeof result.reason !== 'string' || result.wasi !== input.wasi || result.runner !== input.runner || result.artifact !== input.artifact)
|
|
28
|
+
throw resourceError(0);
|
|
29
|
+
return result;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|