@onesi/genesis 0.0.1-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +29 -0
  2. package/dist/auto.d.ts +1010 -0
  3. package/dist/auto.js +125 -0
  4. package/dist/beacons.d.ts +145 -0
  5. package/dist/beacons.js +148 -0
  6. package/dist/blinds-owner-enrollment.d.ts +280 -0
  7. package/dist/blinds-owner-enrollment.js +169 -0
  8. package/dist/client.d.ts +52 -0
  9. package/dist/client.js +384 -0
  10. package/dist/context.d.ts +50 -0
  11. package/dist/context.js +153 -0
  12. package/dist/dials.d.ts +299 -0
  13. package/dist/dials.js +100 -0
  14. package/dist/errors.d.ts +35 -0
  15. package/dist/errors.js +66 -0
  16. package/dist/flares.d.ts +202 -0
  17. package/dist/flares.js +61 -0
  18. package/dist/fleets.d.ts +218 -0
  19. package/dist/fleets.js +189 -0
  20. package/dist/flocks.d.ts +439 -0
  21. package/dist/flocks.js +98 -0
  22. package/dist/foundry-billing.d.ts +97 -0
  23. package/dist/foundry-billing.js +107 -0
  24. package/dist/foundry.d.ts +424 -0
  25. package/dist/foundry.js +133 -0
  26. package/dist/garden.d.ts +754 -0
  27. package/dist/garden.js +76 -0
  28. package/dist/gateway.d.ts +365 -0
  29. package/dist/gateway.js +82 -0
  30. package/dist/gears.d.ts +226 -0
  31. package/dist/gears.js +42 -0
  32. package/dist/generated/operations.d.ts +4 -0
  33. package/dist/generated/operations.js +65134 -0
  34. package/dist/generated/schema.d.ts +87658 -0
  35. package/dist/generated/schema.js +1 -0
  36. package/dist/genesis.d.ts +9574 -0
  37. package/dist/genesis.js +271 -0
  38. package/dist/genesis.openapi.json +128522 -0
  39. package/dist/henry.d.ts +369 -0
  40. package/dist/henry.js +268 -0
  41. package/dist/hives-cells.d.ts +127 -0
  42. package/dist/hives-cells.js +151 -0
  43. package/dist/hives-environment.d.ts +37 -0
  44. package/dist/hives-environment.js +80 -0
  45. package/dist/hives-functions.d.ts +36 -0
  46. package/dist/hives-functions.js +185 -0
  47. package/dist/hives-marketplace.d.ts +128 -0
  48. package/dist/hives-marketplace.js +187 -0
  49. package/dist/hives-node.d.ts +9 -0
  50. package/dist/hives-node.js +155 -0
  51. package/dist/hives-operations.d.ts +451 -0
  52. package/dist/hives-operations.js +43 -0
  53. package/dist/hives-platform.d.ts +149 -0
  54. package/dist/hives-platform.js +183 -0
  55. package/dist/hives-queue-consumer.d.ts +56 -0
  56. package/dist/hives-queue-consumer.js +95 -0
  57. package/dist/hives-queue-funding.d.ts +28 -0
  58. package/dist/hives-queue-funding.js +81 -0
  59. package/dist/hives-queues.d.ts +137 -0
  60. package/dist/hives-queues.js +143 -0
  61. package/dist/hives-resources-transport.d.ts +23 -0
  62. package/dist/hives-resources-transport.js +204 -0
  63. package/dist/hives-response.d.ts +2 -0
  64. package/dist/hives-response.js +32 -0
  65. package/dist/hives-runtimes.d.ts +34 -0
  66. package/dist/hives-runtimes.js +32 -0
  67. package/dist/hives-sse.d.ts +24 -0
  68. package/dist/hives-sse.js +111 -0
  69. package/dist/hives-topics.d.ts +51 -0
  70. package/dist/hives-topics.js +79 -0
  71. package/dist/hives-upload.d.ts +9 -0
  72. package/dist/hives-upload.js +23 -0
  73. package/dist/hives-volumes.d.ts +64 -0
  74. package/dist/hives-volumes.js +117 -0
  75. package/dist/iam-directory.d.ts +8 -0
  76. package/dist/iam-directory.js +23 -0
  77. package/dist/iam.d.ts +391 -0
  78. package/dist/iam.js +92 -0
  79. package/dist/idempotency.d.ts +7 -0
  80. package/dist/idempotency.js +39 -0
  81. package/dist/index.d.ts +47 -0
  82. package/dist/index.js +37 -0
  83. package/dist/instances.d.ts +200 -0
  84. package/dist/instances.js +43 -0
  85. package/dist/lanes.d.ts +267 -0
  86. package/dist/lanes.js +41 -0
  87. package/dist/minds-agent.d.ts +88 -0
  88. package/dist/minds-agent.js +233 -0
  89. package/dist/minds-engine.d.ts +394 -0
  90. package/dist/minds-engine.js +555 -0
  91. package/dist/minds-owner.d.ts +110 -0
  92. package/dist/minds-owner.js +226 -0
  93. package/dist/minds.d.ts +377 -0
  94. package/dist/minds.js +228 -0
  95. package/dist/orgs.d.ts +405 -0
  96. package/dist/orgs.js +63 -0
  97. package/dist/relays-enrollment.d.ts +33 -0
  98. package/dist/relays-enrollment.js +115 -0
  99. package/dist/runner-grant.d.ts +10 -0
  100. package/dist/runner-grant.js +133 -0
  101. package/dist/runner.d.ts +72 -0
  102. package/dist/runner.js +117 -0
  103. package/dist/scopes.d.ts +310 -0
  104. package/dist/scopes.js +40 -0
  105. package/dist/taps.d.ts +118 -0
  106. package/dist/taps.js +45 -0
  107. package/dist/traces.d.ts +574 -0
  108. package/dist/traces.js +97 -0
  109. package/dist/types.d.ts +98 -0
  110. package/dist/types.js +1 -0
  111. package/dist/urls.d.ts +6 -0
  112. package/dist/urls.js +31 -0
  113. package/package.json +49 -1
@@ -0,0 +1,183 @@
1
+ import { GenesisError } from './errors.js';
2
+ const bounded = (value, fallback, max, name) => {
3
+ if (value === undefined)
4
+ return fallback;
5
+ if (!Number.isInteger(value) || value < 1 || value > max) {
6
+ throw new GenesisError({ status: 0, type: 'invalid_request', operationId: 'hives_stream_logs', message: `${name} must be an integer from 1 to ${max}.` });
7
+ }
8
+ return value;
9
+ };
10
+ function parseEvent(lines) {
11
+ let event = 'message';
12
+ let id;
13
+ const data = [];
14
+ for (const line of lines) {
15
+ if (!line || line.startsWith(':'))
16
+ continue; // SSE comments carry keepalives only.
17
+ const colon = line.indexOf(':');
18
+ const field = colon < 0 ? line : line.slice(0, colon);
19
+ let value = colon < 0 ? '' : line.slice(colon + 1);
20
+ if (value.startsWith(' '))
21
+ value = value.slice(1);
22
+ if (field === 'event')
23
+ event = value;
24
+ else if (field === 'id')
25
+ id = value;
26
+ else if (field === 'data')
27
+ data.push(value);
28
+ }
29
+ if (!data.length)
30
+ return undefined;
31
+ const text = data.join('\n');
32
+ let parsed = text;
33
+ try {
34
+ parsed = JSON.parse(text);
35
+ }
36
+ catch { /* non-JSON data such as heartbeat "ping" stays text */ }
37
+ return { event, ...(id === undefined ? {} : { id }), data: parsed };
38
+ }
39
+ /** Pull-based SSE reader. `cancel()` closes the connection even while a read is pending. */
40
+ export function hivesSseReader(response) {
41
+ const reader = response.body?.getReader();
42
+ const decoder = new TextDecoder();
43
+ let buffer = '';
44
+ let lines = [];
45
+ let finished = !reader;
46
+ const take = () => {
47
+ let index;
48
+ while ((index = buffer.search(/\r\n|\r|\n/)) >= 0) {
49
+ const line = buffer.slice(0, index);
50
+ buffer = buffer.slice(index + (buffer.startsWith('\r\n', index) ? 2 : 1));
51
+ if (line !== '') {
52
+ lines.push(line);
53
+ continue;
54
+ }
55
+ const event = parseEvent(lines);
56
+ lines = [];
57
+ if (event)
58
+ return event;
59
+ }
60
+ return undefined;
61
+ };
62
+ return {
63
+ async next() {
64
+ for (;;) {
65
+ const ready = take();
66
+ if (ready)
67
+ return ready;
68
+ if (finished) {
69
+ const tail = parseEvent(buffer ? [...lines, buffer] : lines);
70
+ buffer = '';
71
+ lines = [];
72
+ return tail;
73
+ }
74
+ const { done, value } = await reader.read();
75
+ if (done)
76
+ finished = true;
77
+ else
78
+ buffer += decoder.decode(value, { stream: true });
79
+ }
80
+ },
81
+ async cancel() { finished = true; await reader?.cancel().catch(() => { }); },
82
+ };
83
+ }
84
+ /** Yield SSE events until the caller stops iterating, the signal aborts or the server closes the stream. */
85
+ export async function* hivesSseEvents(response) {
86
+ const sse = hivesSseReader(response);
87
+ try {
88
+ for (let event = await sse.next(); event; event = await sse.next())
89
+ yield event;
90
+ }
91
+ finally {
92
+ await sse.cancel();
93
+ }
94
+ }
95
+ /**
96
+ * Hives platform reads and actions the gateway already routes: project logs (query and live SSE), custom domains,
97
+ * the Hives identity, Hives fleets and remote sessions/SFTP.
98
+ */
99
+ export function hivesPlatform(client) {
100
+ const open = async (project_id, q = {}, init = {}) => {
101
+ const res = await client.raw('hives_stream_logs', { ...q, project_id }, { signal: init.signal, headers: { accept: 'text/event-stream' } });
102
+ if (!(res.headers.get('content-type') ?? '').toLowerCase().startsWith('text/event-stream')) {
103
+ void res.body?.cancel().catch(() => { });
104
+ throw new GenesisError({ status: res.status, type: 'invalid_response', operationId: 'hives_stream_logs', message: 'Hives did not return a Server-Sent Events stream.',
105
+ requestId: res.headers.get('x-request-id') ?? undefined });
106
+ }
107
+ return res;
108
+ };
109
+ return {
110
+ logs: {
111
+ query: (project_id, q = {}) => client.request('hives_query_logs', { ...q, project_id }),
112
+ /** Live SSE events. Iterate and `break` (or abort the signal) to close the connection; it never ends on its own. */
113
+ stream: async function* (project_id, q = {}, init = {}) {
114
+ yield* hivesSseEvents(await open(project_id, q, init));
115
+ },
116
+ /** A bounded window of the live stream: the first `maxEvents` events or `seconds` of stream, whichever comes first. */
117
+ window: async (project_id, q = {}, options = {}) => {
118
+ const maxEvents = bounded(options.maxEvents, 100, 10_000, 'maxEvents');
119
+ const seconds = bounded(options.seconds, 10, 300, 'seconds');
120
+ const events = [];
121
+ // The window starts before the request, so a server that withholds headers cannot outlast it.
122
+ const deadline = new AbortController();
123
+ let timer;
124
+ const elapsed = new Promise((resolve) => { timer = setTimeout(() => { resolve('time'); deadline.abort(); }, seconds * 1000); });
125
+ const signal = options.signal ? AbortSignal.any([options.signal, deadline.signal]) : deadline.signal;
126
+ let sse;
127
+ try {
128
+ const response = await Promise.race([open(project_id, q, { signal }), elapsed]);
129
+ if (response === 'time')
130
+ return { events, ended: 'time' };
131
+ sse = hivesSseReader(response);
132
+ for (;;) {
133
+ const next = await Promise.race([sse.next(), elapsed]);
134
+ if (next === 'time')
135
+ return { events, ended: 'time' };
136
+ if (!next)
137
+ return { events, ended: 'closed' };
138
+ events.push(next);
139
+ if (events.length >= maxEvents)
140
+ return { events, ended: 'max_events' };
141
+ }
142
+ }
143
+ catch (error) {
144
+ if (deadline.signal.aborted && !options.signal?.aborted)
145
+ return { events, ended: 'time' };
146
+ throw error;
147
+ }
148
+ finally {
149
+ clearTimeout(timer);
150
+ await sse?.cancel();
151
+ }
152
+ },
153
+ },
154
+ domains: {
155
+ list: (project_id, q = {}) => client.request('hives_list_domains', { ...q, project_id }),
156
+ add: (project_id, body) => client.request('hives_add_domain', { project_id, body }),
157
+ verify: (project_id, domain_id) => client.request('hives_verify_domain', { project_id, domain_id }),
158
+ provisionSsl: (project_id, domain_id) => client.request('hives_provision_ssl', { project_id, domain_id }),
159
+ },
160
+ auth: { me: () => client.request('hives_me') },
161
+ fleets: {
162
+ list: () => client.request('hives_list_fleets'),
163
+ deploy: (body) => client.request('hives_deploy_fleet', { body }),
164
+ status: (fleet_id) => client.request('hives_get_fleet_status', { fleet_id }),
165
+ teardown: (fleet_id) => client.request('hives_teardown_fleet', { fleet_id }),
166
+ },
167
+ remote: {
168
+ sessions: {
169
+ list: (project_id, q = {}) => client.request('hives_list_remote_sessions', { ...q, project_id }),
170
+ close: (project_id, session_id) => client.request('hives_close_remote_session', { project_id, session_id }),
171
+ },
172
+ ssh: (project_id, body) => client.request('hives_create_ssh_session', { project_id, body }),
173
+ terminal: (project_id, body) => client.request('hives_create_terminal_session', { project_id, body }),
174
+ debug: (project_id, body) => client.request('hives_create_debug_session', { project_id, body }),
175
+ sftp: {
176
+ list: (project_id, target_id, q = {}) => client.request('hives_sftp_list', { ...q, project_id, target_id }),
177
+ read: (project_id, target_id, path) => client.request('hives_sftp_read', { project_id, target_id, path }),
178
+ write: (project_id, target_id, body) => client.request('hives_sftp_write', { project_id, target_id, body }),
179
+ delete: (project_id, target_id, body) => client.request('hives_sftp_delete', { project_id, target_id, body }),
180
+ },
181
+ },
182
+ };
183
+ }
@@ -0,0 +1,56 @@
1
+ import type { GenesisClient } from './client.js';
2
+ import { type HivesResourceOptions } from './hives-resources-transport.js';
3
+ /** Every delivery setting must match the existing standard queue. */
4
+ export interface HivesQueueConsumerConfig {
5
+ functionId: string;
6
+ queueName: string;
7
+ batchSize: 1;
8
+ maxConcurrent: 1;
9
+ visibilityTimeoutSecs: number;
10
+ maxRetries: number;
11
+ deadLetterQueue?: string | null;
12
+ autoAck: true;
13
+ enabled: boolean;
14
+ }
15
+ export interface HivesQueueConsumerBinding {
16
+ queueId: string;
17
+ projectId: string;
18
+ functionId: string;
19
+ enabled: boolean;
20
+ revision: number;
21
+ createdAt: string;
22
+ updatedAt: string;
23
+ }
24
+ export interface HivesQueueConsumerAttempt {
25
+ id: string;
26
+ functionId: string;
27
+ consumerRevision: number;
28
+ messageId: string;
29
+ receiveCount: number;
30
+ status: 'running' | 'succeeded' | 'failed' | 'unconfirmed';
31
+ leaseExpiresAt: string;
32
+ startedAt: string;
33
+ completedAt: string | null;
34
+ executionId: string | null;
35
+ guestStatus: number | null;
36
+ }
37
+ export interface HivesQueueConsumerStatus {
38
+ consumer: {
39
+ binding: HivesQueueConsumerBinding | null;
40
+ latestAttempt: HivesQueueConsumerAttempt | null;
41
+ exhaustedMessages: number;
42
+ };
43
+ /** An operator setting, not evidence that an invocation succeeded. */
44
+ runtimeEnabled: boolean;
45
+ batchSize: 1;
46
+ maxConcurrent: 1;
47
+ autoAck: true;
48
+ }
49
+ export declare function hivesQueueConsumer(client: GenesisClient): {
50
+ get(project: string, queue: string, options?: HivesResourceOptions): Promise<HivesQueueConsumerStatus>;
51
+ configure(project: string, queue: string, input: HivesQueueConsumerConfig, options?: HivesResourceOptions): Promise<HivesQueueConsumerBinding>;
52
+ remove(project: string, queue: string, options?: HivesResourceOptions): Promise<{
53
+ success: true;
54
+ queueId: string;
55
+ }>;
56
+ };
@@ -0,0 +1,95 @@
1
+ import { GenesisError } from './errors.js';
2
+ import { hivesResourceCall, hivesResourceId, resourceError } from './hives-resources-transport.js';
3
+ const badResponse = () => new GenesisError({ status: 0, type: 'invalid_response',
4
+ message: 'Hives returned an invalid or mismatched queue-consumer response. Read saved state before another mutation.' });
5
+ function record(value) {
6
+ if (!value || typeof value !== 'object' || Array.isArray(value))
7
+ throw badResponse();
8
+ return value;
9
+ }
10
+ function id(value) {
11
+ if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/.test(value))
12
+ throw badResponse();
13
+ return value;
14
+ }
15
+ function integer(value, minimum) {
16
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum)
17
+ throw badResponse();
18
+ return value;
19
+ }
20
+ function date(value) {
21
+ if (typeof value !== 'string' || !Number.isFinite(Date.parse(value)))
22
+ throw badResponse();
23
+ return value;
24
+ }
25
+ function binding(value, project, queue) {
26
+ const row = record(value);
27
+ if (row.queueId !== queue || row.projectId !== project || typeof row.enabled !== 'boolean')
28
+ throw badResponse();
29
+ return { queueId: queue, projectId: project, functionId: id(row.functionId), enabled: row.enabled,
30
+ revision: integer(row.revision, 1), createdAt: date(row.createdAt), updatedAt: date(row.updatedAt) };
31
+ }
32
+ function attempt(value) {
33
+ const row = record(value);
34
+ if (!['running', 'succeeded', 'failed', 'unconfirmed'].includes(row.status))
35
+ throw badResponse();
36
+ const confirmed = row.status === 'succeeded' || row.status === 'failed';
37
+ if (confirmed) {
38
+ if (typeof row.executionId !== 'string' || !/^exec_[a-f0-9]{32}$/.test(row.executionId)
39
+ || typeof row.guestStatus !== 'number' || !Number.isInteger(row.guestStatus)
40
+ || row.guestStatus < 200 || row.guestStatus > 599 || row.completedAt === null
41
+ || (row.status === 'succeeded') !== (row.guestStatus < 300))
42
+ throw badResponse();
43
+ }
44
+ else if (row.executionId !== null || row.guestStatus !== null || row.status === 'running' && row.completedAt !== null)
45
+ throw badResponse();
46
+ // History can belong to an earlier function/revision even after the binding is removed.
47
+ return { id: id(row.id), functionId: id(row.functionId), consumerRevision: integer(row.consumerRevision, 1),
48
+ messageId: id(row.messageId), receiveCount: integer(row.receiveCount, 1), status: row.status,
49
+ leaseExpiresAt: date(row.leaseExpiresAt), startedAt: date(row.startedAt),
50
+ completedAt: row.completedAt === null ? null : date(row.completedAt),
51
+ executionId: row.executionId, guestStatus: row.guestStatus };
52
+ }
53
+ function config(value) {
54
+ const allowed = ['functionId', 'queueName', 'batchSize', 'maxConcurrent', 'visibilityTimeoutSecs', 'maxRetries', 'deadLetterQueue', 'autoAck', 'enabled'];
55
+ if (!value || typeof value !== 'object' || Array.isArray(value) || Object.keys(value).some(key => !allowed.includes(key))
56
+ || value.batchSize !== 1 || value.maxConcurrent !== 1 || value.autoAck !== true || typeof value.enabled !== 'boolean'
57
+ || !Number.isInteger(value.visibilityTimeoutSecs) || value.visibilityTimeoutSecs < 75 || value.visibilityTimeoutSecs > 4_294_967_295
58
+ || !Number.isInteger(value.maxRetries) || value.maxRetries < 0 || value.maxRetries > 9)
59
+ throw resourceError(0);
60
+ hivesResourceId(value.functionId);
61
+ hivesResourceId(value.queueName);
62
+ if (value.deadLetterQueue != null)
63
+ hivesResourceId(value.deadLetterQueue);
64
+ return { functionId: value.functionId, queueName: value.queueName, batchSize: 1, maxConcurrent: 1,
65
+ visibilityTimeoutSecs: value.visibilityTimeoutSecs, maxRetries: value.maxRetries,
66
+ deadLetterQueue: value.deadLetterQueue ?? null, autoAck: true, enabled: value.enabled };
67
+ }
68
+ export function hivesQueueConsumer(client) {
69
+ const params = (project, queue) => ({ project_id: hivesResourceId(project), queue_id: hivesResourceId(queue) });
70
+ const call = (operation, input, options) => hivesResourceCall(client, operation, input, options, 'json', 64 * 1024, 20_000, 200);
71
+ return {
72
+ async get(project, queue, options) {
73
+ const row = record(await call('hives_get_native_queue_consumer', params(project, queue), options));
74
+ const status = record(row.consumer);
75
+ if (typeof row.runtimeEnabled !== 'boolean' || row.batchSize !== 1 || row.maxConcurrent !== 1 || row.autoAck !== true)
76
+ throw badResponse();
77
+ return { consumer: { binding: status.binding === null ? null : binding(status.binding, project, queue),
78
+ latestAttempt: status.latestAttempt === null ? null : attempt(status.latestAttempt), exhaustedMessages: integer(status.exhaustedMessages, 0) },
79
+ runtimeEnabled: row.runtimeEnabled, batchSize: 1, maxConcurrent: 1, autoAck: true };
80
+ },
81
+ async configure(project, queue, input, options) {
82
+ const body = config(input);
83
+ const result = binding(await call('hives_configure_native_queue_consumer', { ...params(project, queue), body }, options), project, queue);
84
+ if (result.functionId !== body.functionId || result.enabled !== body.enabled)
85
+ throw badResponse();
86
+ return result;
87
+ },
88
+ async remove(project, queue, options) {
89
+ const result = record(await call('hives_remove_native_queue_consumer', params(project, queue), options));
90
+ if (result.success !== true || result.queueId !== queue)
91
+ throw badResponse();
92
+ return { success: true, queueId: queue };
93
+ },
94
+ };
95
+ }
@@ -0,0 +1,28 @@
1
+ import { GenesisError } from './errors.js';
2
+ export interface HivesQueueSendOptions {
3
+ signal?: AbortSignal;
4
+ idempotencyKey?: string;
5
+ }
6
+ export interface HivesQueueOperation {
7
+ object: 'queue_send_operation';
8
+ operation_id: string;
9
+ state: 'prepared' | 'reserve_unknown' | 'reserved' | 'dispatch_unknown' | 'dispatch_authorized' | 'commit_unknown' | 'settle_unknown' | 'settled' | 'denied' | 'released';
10
+ code: string;
11
+ message_id: string | null;
12
+ funding_source: 'sandbox_allowance' | null;
13
+ reservation_id: string | null;
14
+ native_meter: 'hives.queue_operations';
15
+ quantity_base: string | null;
16
+ upper_bound_quantity_base: string;
17
+ retry_send: false;
18
+ }
19
+ export declare const isHivesQueueFundingOperation: (id: string) => id is "hives_send_native_queue" | "hives_get_operation_native_queue";
20
+ export declare function hivesQueueOperationId(value: unknown): string;
21
+ export declare function hivesQueueSendHeaders(options: HivesQueueSendOptions): Record<string, string>;
22
+ export declare function hivesQueueOperation(value: unknown, expected: unknown): HivesQueueOperation;
23
+ export declare class HivesQueueOperationError extends GenesisError {
24
+ readonly operation: HivesQueueOperation;
25
+ constructor(status: number, operation: HivesQueueOperation);
26
+ }
27
+ /** Only a bounded typed receipt is retained from an error; never an echoed message body. */
28
+ export declare function hivesQueueOperationError(response: Response, expected?: unknown): Promise<HivesQueueOperationError | undefined>;
@@ -0,0 +1,81 @@
1
+ import { GenesisError } from './errors.js';
2
+ export const isHivesQueueFundingOperation = (id) => id === 'hives_send_native_queue' || id === 'hives_get_operation_native_queue';
3
+ export function hivesQueueOperationId(value) {
4
+ if (typeof value !== 'string' || !/^qop_[0-9a-f]{12}7[0-9a-f]{3}[89ab][0-9a-f]{15}$/.test(value))
5
+ throw new Error('Use the original queue operation ID. No send was retried.');
6
+ return value;
7
+ }
8
+ export function hivesQueueSendHeaders(options) {
9
+ if (options.idempotencyKey === undefined)
10
+ return {};
11
+ if (typeof options.idempotencyKey !== 'string' || !/^[ -~]{1,128}$/.test(options.idempotencyKey))
12
+ throw new Error('Use one persisted queue Idempotency-Key of 1–128 printable ASCII bytes.');
13
+ return { 'idempotency-key': options.idempotencyKey };
14
+ }
15
+ export function hivesQueueOperation(value, expected) {
16
+ const operation = hivesQueueOperationId(expected), r = value;
17
+ const keys = ['object', 'operation_id', 'state', 'code', 'message_id', 'funding_source', 'reservation_id', 'native_meter', 'quantity_base', 'upper_bound_quantity_base', 'retry_send'];
18
+ if (!r || typeof r !== 'object' || Array.isArray(r) || Object.keys(r).length !== keys.length || keys.some(k => !Object.hasOwn(r, k))
19
+ || r.object !== 'queue_send_operation' || r.operation_id !== operation || r.retry_send !== false || r.native_meter !== 'hives.queue_operations'
20
+ || !['prepared', 'reserve_unknown', 'reserved', 'dispatch_unknown', 'dispatch_authorized', 'commit_unknown', 'settle_unknown', 'settled', 'denied', 'released'].includes(r.state)
21
+ || typeof r.code !== 'string' || !/^[a-z_]{1,80}$/.test(r.code)
22
+ || r.funding_source !== null && r.funding_source !== 'sandbox_allowance'
23
+ || r.reservation_id !== null && !/^gfr_[A-Za-z0-9_.:@-]{1,124}$/.test(r.reservation_id)
24
+ || r.message_id !== null && !/^msg_[0-9a-f]{12}7[0-9a-f]{3}[89ab][0-9a-f]{15}$/.test(r.message_id)
25
+ || typeof r.upper_bound_quantity_base !== 'string' || !/^[1-5]$/.test(r.upper_bound_quantity_base)
26
+ || r.quantity_base !== null && (typeof r.quantity_base !== 'string' || !/^[1-5]$/.test(r.quantity_base) || Number(r.quantity_base) > Number(r.upper_bound_quantity_base))
27
+ || r.quantity_base !== null && (!r.message_id || !r.reservation_id || !r.funding_source)
28
+ || r.state === 'settled' && (!r.quantity_base || !r.message_id || !r.reservation_id || !r.funding_source)) {
29
+ throw new Error('Queue operation receipt is invalid or mismatched. Retain its original identity; no send was retried.');
30
+ }
31
+ return Object.fromEntries(keys.map(k => [k, r[k]]));
32
+ }
33
+ export class HivesQueueOperationError extends GenesisError {
34
+ operation;
35
+ constructor(status, operation) {
36
+ super({ status, type: 'hives_queue_operation', message: 'Read the original queue operation. Do not retry the send with a new key.', body: operation });
37
+ this.operation = operation;
38
+ }
39
+ }
40
+ /** Only a bounded typed receipt is retained from an error; never an echoed message body. */
41
+ export async function hivesQueueOperationError(response, expected) {
42
+ const id = response.headers.get('x-hives-operation-id');
43
+ try {
44
+ hivesQueueOperationId(id);
45
+ if (expected !== undefined && id !== hivesQueueOperationId(expected))
46
+ return undefined;
47
+ }
48
+ catch {
49
+ return undefined;
50
+ }
51
+ if (!response.body || !response.headers.get('content-type')?.toLowerCase().includes('application/json'))
52
+ return undefined;
53
+ const reader = response.body.getReader(), chunks = [];
54
+ let size = 0;
55
+ try {
56
+ for (;;) {
57
+ const { value, done } = await reader.read();
58
+ if (done)
59
+ break;
60
+ size += value.length;
61
+ if (size > 4096) {
62
+ await reader.cancel();
63
+ return undefined;
64
+ }
65
+ chunks.push(value);
66
+ }
67
+ const bytes = new Uint8Array(size);
68
+ let at = 0;
69
+ for (const chunk of chunks) {
70
+ bytes.set(chunk, at);
71
+ at += chunk.length;
72
+ }
73
+ return new HivesQueueOperationError(response.status, hivesQueueOperation(JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)), id));
74
+ }
75
+ catch {
76
+ return undefined;
77
+ }
78
+ finally {
79
+ reader.releaseLock();
80
+ }
81
+ }
@@ -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
+ };