@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.
Files changed (87) hide show
  1. package/README.md +29 -0
  2. package/dist/beacons.d.ts +103 -0
  3. package/dist/beacons.js +77 -0
  4. package/dist/blinds-owner-enrollment.d.ts +171 -0
  5. package/dist/blinds-owner-enrollment.js +150 -0
  6. package/dist/client.d.ts +19996 -0
  7. package/dist/client.js +277 -0
  8. package/dist/context.d.ts +50 -0
  9. package/dist/context.js +153 -0
  10. package/dist/dials.d.ts +299 -0
  11. package/dist/dials.js +100 -0
  12. package/dist/errors.d.ts +35 -0
  13. package/dist/errors.js +66 -0
  14. package/dist/flares.d.ts +170 -0
  15. package/dist/flares.js +56 -0
  16. package/dist/fleets.d.ts +186 -0
  17. package/dist/fleets.js +136 -0
  18. package/dist/flocks.d.ts +155 -0
  19. package/dist/flocks.js +39 -0
  20. package/dist/foundry-billing.d.ts +97 -0
  21. package/dist/foundry-billing.js +107 -0
  22. package/dist/gears.d.ts +107 -0
  23. package/dist/gears.js +20 -0
  24. package/dist/generated/operations.d.ts +19949 -0
  25. package/dist/generated/operations.js +23846 -0
  26. package/dist/generated/schema.d.ts +35413 -0
  27. package/dist/generated/schema.js +1 -0
  28. package/dist/genesis.d.ts +2926 -0
  29. package/dist/genesis.js +206 -0
  30. package/dist/genesis.openapi.json +49321 -0
  31. package/dist/henry.d.ts +168 -0
  32. package/dist/henry.js +45 -0
  33. package/dist/hives-cells.d.ts +127 -0
  34. package/dist/hives-cells.js +151 -0
  35. package/dist/hives-environment.d.ts +28 -0
  36. package/dist/hives-environment.js +58 -0
  37. package/dist/hives-functions.d.ts +36 -0
  38. package/dist/hives-functions.js +185 -0
  39. package/dist/hives-marketplace.d.ts +128 -0
  40. package/dist/hives-marketplace.js +187 -0
  41. package/dist/hives-node.d.ts +9 -0
  42. package/dist/hives-node.js +152 -0
  43. package/dist/hives-operations.d.ts +337 -0
  44. package/dist/hives-operations.js +41 -0
  45. package/dist/hives-queue-consumer.d.ts +56 -0
  46. package/dist/hives-queue-consumer.js +95 -0
  47. package/dist/hives-queue-funding.d.ts +28 -0
  48. package/dist/hives-queue-funding.js +81 -0
  49. package/dist/hives-queues.d.ts +137 -0
  50. package/dist/hives-queues.js +143 -0
  51. package/dist/hives-resources-transport.d.ts +23 -0
  52. package/dist/hives-resources-transport.js +204 -0
  53. package/dist/hives-response.d.ts +2 -0
  54. package/dist/hives-response.js +32 -0
  55. package/dist/hives-runtimes.d.ts +34 -0
  56. package/dist/hives-runtimes.js +32 -0
  57. package/dist/hives-topics.d.ts +51 -0
  58. package/dist/hives-topics.js +79 -0
  59. package/dist/hives-upload.d.ts +9 -0
  60. package/dist/hives-upload.js +23 -0
  61. package/dist/hives-volumes.d.ts +64 -0
  62. package/dist/hives-volumes.js +117 -0
  63. package/dist/idempotency.d.ts +4 -0
  64. package/dist/idempotency.js +17 -0
  65. package/dist/index.d.ts +33 -0
  66. package/dist/index.js +25 -0
  67. package/dist/instances.d.ts +25 -0
  68. package/dist/instances.js +11 -0
  69. package/dist/lanes.d.ts +267 -0
  70. package/dist/lanes.js +41 -0
  71. package/dist/minds-agent.d.ts +60 -0
  72. package/dist/minds-agent.js +190 -0
  73. package/dist/minds-owner.d.ts +110 -0
  74. package/dist/minds-owner.js +226 -0
  75. package/dist/minds.d.ts +269 -0
  76. package/dist/minds.js +193 -0
  77. package/dist/relays-enrollment.d.ts +33 -0
  78. package/dist/relays-enrollment.js +115 -0
  79. package/dist/runner-grant.d.ts +10 -0
  80. package/dist/runner-grant.js +133 -0
  81. package/dist/runner.d.ts +68 -0
  82. package/dist/runner.js +116 -0
  83. package/dist/types.d.ts +87 -0
  84. package/dist/types.js +1 -0
  85. package/dist/urls.d.ts +6 -0
  86. package/dist/urls.js +31 -0
  87. package/package.json +49 -1
package/dist/minds.js ADDED
@@ -0,0 +1,193 @@
1
+ import { GenesisError } from './errors.js';
2
+ import { mindsAgentModule } from './minds-agent.js';
3
+ import { mindsOwnerModule } from './minds-owner.js';
4
+ export const mindsOperations = ['minds_listMinds', 'minds_getMind', 'minds_getUsage', 'minds_createMind', 'minds_resumeMind', 'minds_stopMind', 'minds_insertEpisodicMemory', 'minds_getEpisodicMemory', 'minds_updateEpisodicMemory', 'minds_searchMemory'];
5
+ export const isMindsOperation = (id) => mindsOperations.includes(id);
6
+ const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
7
+ const uuid4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
8
+ const writes = new Set(['minds_createMind', 'minds_resumeMind', 'minds_stopMind', 'minds_insertEpisodicMemory', 'minds_updateEpisodicMemory']);
9
+ // Match the native gateway's RFC3339/calendar and nanosecond window bounds.
10
+ function usageInstant(value) {
11
+ if (typeof value !== 'string' || value.length > 40)
12
+ return undefined;
13
+ const match = /^(\d{4})-(\d\d)-(\d\d)[Tt](\d\d):(\d\d):(\d\d)(?:\.(\d{1,9}))?([Zz]|([+-])(\d\d):(\d\d))$/.exec(value);
14
+ if (!match)
15
+ return undefined;
16
+ const [, year, month, day, hour, minute, second, fraction, zone, sign, offsetHour, offsetMinute] = match;
17
+ const [y, mo, d, h, mi, s] = [year, month, day, hour, minute, second].map(Number);
18
+ if (mo < 1 || mo > 12 || d < 1 || d > 31 || h > 23 || mi > 59 || s > 59
19
+ || (zone.toUpperCase() !== 'Z' && (Number(offsetHour) > 23 || Number(offsetMinute) > 59)))
20
+ return undefined;
21
+ const parsed = new Date(0);
22
+ parsed.setUTCFullYear(y, mo - 1, d);
23
+ parsed.setUTCHours(h, mi, s, 0);
24
+ if (parsed.getUTCFullYear() !== y || parsed.getUTCMonth() !== mo - 1 || parsed.getUTCDate() !== d)
25
+ return undefined;
26
+ const offset = zone.toUpperCase() === 'Z' ? 0 : (Number(offsetHour) * 60 + Number(offsetMinute)) * (sign === '+' ? 1 : -1);
27
+ return BigInt(parsed.getTime() - offset * 60_000) * 1000000n + BigInt((fraction ?? '').padEnd(9, '0'));
28
+ }
29
+ /** One dispatch only. Creation retains its operation key; episodic insertion returns a storage UUID distinct from event.id. */
30
+ export async function mindsTransport(options) {
31
+ const id = options.operationId, input = options.input, write = writes.has(id);
32
+ let dispatchAttempted = false;
33
+ const error = (status, type, code, unknownOutcome = false) => new GenesisError({ status, type, code, operationId: id,
34
+ message: status === 403 ? 'Minds requires an admitted original human One account session with a Console Sandbox selection.'
35
+ : write ? 'Minds write was not confirmed. Preserve the lifecycle/create key or reconcile memory before an explicit retry.' : 'Minds request was not confirmed.',
36
+ ...(write && (unknownOutcome || dispatchAttempted && (status === 0 || status >= 500 || type === 'invalid_response')) ? { body: { outcome: 'unknown' } } : {}) });
37
+ const fields = id === 'minds_getUsage' ? ['from', 'to'] : id === 'minds_listMinds' ? ['after', 'limit'] : id === 'minds_getMind' ? ['mind_id'] : id === 'minds_updateEpisodicMemory' ? ['mind', 'storage_id', 'body'] : ['minds_resumeMind', 'minds_stopMind'].includes(id) ? ['mind_id', 'body']
38
+ : id === 'minds_createMind' ? ['body'] : id === 'minds_getEpisodicMemory' ? ['mind', 'storage_id'] : ['mind', 'body'];
39
+ if (options.routing !== 'gateway' || !isMindsOperation(id) || Object.keys(input).some(key => !fields.includes(key)))
40
+ throw error(0, 'invalid_request');
41
+ if (id === 'minds_getUsage') {
42
+ const from = usageInstant(input.from), to = usageInstant(input.to);
43
+ if (from === undefined || to === undefined || to <= from || to - from > 93n * 86400n * 1000000000n)
44
+ throw error(0, 'invalid_request');
45
+ }
46
+ for (const key of ['mind', 'mind_id', 'storage_id', 'after'])
47
+ if (input[key] !== undefined && (typeof input[key] !== 'string' || !uuid.test(input[key])))
48
+ throw error(0, 'invalid_request');
49
+ if (id === 'minds_updateEpisodicMemory') {
50
+ const body = input.body;
51
+ if (typeof input.mind !== 'string' || input.mind.length !== 36 || typeof input.storage_id !== 'string' || input.storage_id.length !== 36
52
+ || !body || typeof body !== 'object' || Array.isArray(body) || Object.keys(body).sort().join() !== 'content,event_id'
53
+ || typeof body.event_id !== 'string' || body.event_id.length !== 36 || !uuid.test(body.event_id)
54
+ || typeof body.content !== 'string' || !body.content.trim() || body.content.length > 16_000)
55
+ throw error(0, 'invalid_request');
56
+ }
57
+ if (id === 'minds_createMind') {
58
+ const body = input.body;
59
+ if (!uuid4.test(options.headers?.['idempotency-key'] ?? '') || !/^[a-f0-9]{64}$/.test(options.headers?.['x-genesis-minds-creation-context'] ?? '')
60
+ || !body || typeof body !== 'object' || Array.isArray(body) || typeof body.name !== 'string'
61
+ || Object.keys(body).some(key => !['name', 'plan', 'profile_id'].includes(key))
62
+ || (body.plan !== undefined && body.plan !== 'free' && body.plan !== 'pro')
63
+ || (body.profile_id !== undefined && (typeof body.profile_id !== 'string' || !['F1', 'D1', 'D2'].includes(body.profile_id) || (body.plan !== 'pro' && body.profile_id !== 'F1'))))
64
+ throw error(0, 'invalid_request');
65
+ }
66
+ if (id === 'minds_resumeMind' || id === 'minds_stopMind') {
67
+ const body = input.body;
68
+ if (!uuid4.test(options.headers?.['idempotency-key'] ?? '') || !body || typeof body !== 'object' || Array.isArray(body)
69
+ || Object.keys(body).some(key => !(id === 'minds_resumeMind' ? ['expected_generation', 'wake_reason'] : ['expected_generation']).includes(key))
70
+ || (body.wake_reason !== undefined && (typeof body.wake_reason !== 'string' || !['manual', 'scheduled_job', 'webhook', 'memory_consolidation', 'activity'].includes(body.wake_reason)))
71
+ || !Number.isSafeInteger(body.expected_generation) || body.expected_generation < 1
72
+ || body.expected_generation >= Number.MAX_SAFE_INTEGER)
73
+ throw error(0, 'invalid_request');
74
+ }
75
+ const controller = new AbortController(), cancel = () => controller.abort(options.signal?.reason);
76
+ options.signal?.addEventListener('abort', cancel, { once: true });
77
+ if (options.signal?.aborted)
78
+ cancel();
79
+ const timer = setTimeout(() => controller.abort(), 35_000);
80
+ async function bounded(work) {
81
+ controller.signal.throwIfAborted();
82
+ let abort = () => { };
83
+ try {
84
+ return await Promise.race([work(), new Promise((_, reject) => { abort = () => reject(error(0, 'transport_error')); controller.signal.addEventListener('abort', abort, { once: true }); })]);
85
+ }
86
+ finally {
87
+ controller.signal.removeEventListener('abort', abort);
88
+ }
89
+ }
90
+ try {
91
+ const credential = await bounded(options.credential);
92
+ controller.signal.throwIfAborted();
93
+ if (!credential)
94
+ throw error(401, 'unauthenticated');
95
+ const body = Object.hasOwn(input, 'body') ? JSON.stringify(input.body) : undefined;
96
+ if (body !== undefined && new TextEncoder().encode(body).length > 65_536)
97
+ throw error(0, 'invalid_request');
98
+ const response = await bounded(() => {
99
+ dispatchAttempted = true;
100
+ return options.fetch(options.url, { method: id === 'minds_updateEpisodicMemory' ? 'PUT' : ['minds_listMinds', 'minds_getMind', 'minds_getUsage', 'minds_getEpisodicMemory'].includes(id) ? 'GET' : 'POST',
101
+ headers: { authorization: `Bearer ${credential}`, accept: 'application/json', ...(body === undefined ? {} : { 'content-type': 'application/json' }),
102
+ ...(['minds_resumeMind', 'minds_stopMind'].includes(id) ? { 'idempotency-key': options.headers['idempotency-key'] } : {}),
103
+ ...(id === 'minds_createMind' ? { 'idempotency-key': options.headers['idempotency-key'], 'x-genesis-minds-creation-context': options.headers['x-genesis-minds-creation-context'] } : {}) },
104
+ ...(body === undefined ? {} : { body }), signal: controller.signal, redirect: 'error', cache: 'no-store' }).then(result => {
105
+ if (controller.signal.aborted) {
106
+ void result.body?.cancel().catch(() => { });
107
+ throw error(0, 'transport_error');
108
+ }
109
+ return result;
110
+ });
111
+ });
112
+ const reader = response.body?.getReader();
113
+ if (!reader)
114
+ throw error(response.status, 'invalid_response');
115
+ const chunks = [];
116
+ let size = 0;
117
+ const stop = () => { void reader.cancel().catch(() => { }); };
118
+ controller.signal.addEventListener('abort', stop, { once: true });
119
+ try {
120
+ for (;;) {
121
+ const next = await bounded(() => reader.read());
122
+ if (next.done)
123
+ break;
124
+ size += next.value.length;
125
+ if (size > 2 * 1024 * 1024)
126
+ throw error(response.status, 'invalid_response');
127
+ chunks.push(next.value);
128
+ }
129
+ }
130
+ finally {
131
+ controller.signal.removeEventListener('abort', stop);
132
+ stop();
133
+ try {
134
+ reader.releaseLock();
135
+ }
136
+ catch { /* cancellation owns a pending read */ }
137
+ }
138
+ const bytes = new Uint8Array(size);
139
+ let offset = 0;
140
+ for (const chunk of chunks) {
141
+ bytes.set(chunk, offset);
142
+ offset += chunk.length;
143
+ }
144
+ let value;
145
+ try {
146
+ value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
147
+ }
148
+ catch {
149
+ throw error(response.status, 'invalid_response');
150
+ }
151
+ if (!response.ok) {
152
+ const row = value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
153
+ const detail = row && Object.hasOwn(row, 'error') && row.error && typeof row.error === 'object' && !Array.isArray(row.error)
154
+ ? row.error : undefined;
155
+ const code = detail && Object.hasOwn(detail, 'code') && typeof detail.code === 'string' ? detail.code : undefined;
156
+ const unknownOutcome = ['minds_resumeMind', 'minds_stopMind'].includes(id) && response.status === 401 && code === 'SELECTION_EXPIRED'
157
+ && detail !== undefined && Object.hasOwn(detail, 'outcome') && detail.outcome === 'unknown';
158
+ throw error(response.status, 'minds_error', code, unknownOutcome);
159
+ }
160
+ if (['minds_createMind', 'minds_resumeMind', 'minds_stopMind'].includes(id) && response.status !== 202)
161
+ throw error(response.status, 'invalid_response');
162
+ return Response.json(value, { status: response.status, headers: { 'cache-control': 'no-store' } });
163
+ }
164
+ catch (cause) {
165
+ if (cause instanceof GenesisError)
166
+ throw cause;
167
+ throw error(0, 'transport_error');
168
+ }
169
+ finally {
170
+ clearTimeout(timer);
171
+ controller.abort();
172
+ options.signal?.removeEventListener('abort', cancel);
173
+ }
174
+ }
175
+ export function mindsModule(client) {
176
+ return {
177
+ ...mindsOwnerModule(client),
178
+ agent: mindsAgentModule(client),
179
+ list: (query = {}, options = {}) => client.request('minds_listMinds', query, options),
180
+ get: (mind_id, options = {}) => client.request('minds_getMind', { mind_id }, options),
181
+ usage: (window, options = {}) => client.request('minds_getUsage', window, options),
182
+ create: (name, options) => client.request('minds_createMind', { body: { name, ...(options.plan === undefined ? {} : { plan: options.plan }), ...(options.profileId === undefined ? {} : { profile_id: options.profileId }) } }, { signal: options.signal,
183
+ headers: { 'idempotency-key': options.idempotencyKey, 'x-genesis-minds-creation-context': options.contextSha256 } }),
184
+ resume: (mind_id, expected_generation, options) => client.request('minds_resumeMind', { mind_id, body: { expected_generation, ...(options.wakeReason === undefined ? {} : { wake_reason: options.wakeReason }) } }, { signal: options.signal, headers: { 'idempotency-key': options.idempotencyKey } }),
185
+ stop: (mind_id, expected_generation, options) => client.request('minds_stopMind', { mind_id, body: { expected_generation } }, { signal: options.signal, headers: { 'idempotency-key': options.idempotencyKey } }),
186
+ memory: {
187
+ insert: (mind, event, options = {}) => client.request('minds_insertEpisodicMemory', { mind, body: { event } }, options),
188
+ get: (mind, storage_id, options = {}) => client.request('minds_getEpisodicMemory', { mind, storage_id }, options),
189
+ update: (mind, storage_id, body, options = {}) => client.request('minds_updateEpisodicMemory', { mind, storage_id, body }, options),
190
+ search: (mind, text, limit = 20, options = {}) => client.request('minds_searchMemory', { mind, body: { text, limit } }, options),
191
+ },
192
+ };
193
+ }
@@ -0,0 +1,33 @@
1
+ import type { GenesisClient } from './client.js';
2
+ export declare const isRelaysEnrollmentOperation: (id: string) => id is "relays_getEnrollment" | "relays_enroll";
3
+ /** Read status or send one explicit bodyless enrollment. No inferred tenant or mutation replay. */
4
+ export declare function relaysEnrollmentTransport(options: {
5
+ operationId: string;
6
+ input: Record<string, unknown>;
7
+ routing: string;
8
+ url: string;
9
+ credential: () => Promise<string | undefined>;
10
+ fetch: typeof fetch;
11
+ signal?: AbortSignal;
12
+ }): Promise<Response>;
13
+ export declare function relaysEnrollment(client: GenesisClient): {
14
+ get: (options?: {
15
+ signal?: AbortSignal;
16
+ }) => Promise<{
17
+ state: "ready" | "not_enrolled";
18
+ organizationId: string;
19
+ projectId: string;
20
+ workspaceId: string;
21
+ resourceEnvironment: "sandbox";
22
+ }>;
23
+ activate: (options?: {
24
+ signal?: AbortSignal;
25
+ }) => Promise<{
26
+ state: "ready";
27
+ organizationId: string;
28
+ projectId: string;
29
+ workspaceId: string;
30
+ resourceEnvironment: "sandbox";
31
+ created: boolean;
32
+ }>;
33
+ };
@@ -0,0 +1,115 @@
1
+ import { GenesisError } from './errors.js';
2
+ export const isRelaysEnrollmentOperation = (id) => id === 'relays_getEnrollment' || id === 'relays_enroll';
3
+ const nativeId = (value, prefix) => typeof value === 'string'
4
+ && value.startsWith(prefix) && /^[A-Za-z0-9_-]{1,128}$/.test(value.slice(prefix.length));
5
+ /** Read status or send one explicit bodyless enrollment. No inferred tenant or mutation replay. */
6
+ export async function relaysEnrollmentTransport(options) {
7
+ const write = options.operationId === 'relays_enroll';
8
+ const error = (status, type) => new GenesisError({ status, type, operationId: options.operationId,
9
+ message: 'Relays enrollment was not confirmed. Read enrollment status before explicitly trying another activation.' });
10
+ if (options.routing !== 'gateway' || !options.input || typeof options.input !== 'object'
11
+ || Array.isArray(options.input) || Object.keys(options.input).length)
12
+ throw error(0, 'invalid_request');
13
+ const controller = new AbortController();
14
+ const cancel = () => controller.abort(options.signal?.reason);
15
+ options.signal?.addEventListener('abort', cancel, { once: true });
16
+ if (options.signal?.aborted)
17
+ cancel();
18
+ const timer = setTimeout(() => controller.abort(), 20_000);
19
+ async function bounded(promise) {
20
+ controller.signal.throwIfAborted();
21
+ let abort = () => { };
22
+ try {
23
+ return await Promise.race([promise, new Promise((_, reject) => {
24
+ abort = () => reject(error(0, 'transport_error'));
25
+ controller.signal.addEventListener('abort', abort, { once: true });
26
+ })]);
27
+ }
28
+ finally {
29
+ controller.signal.removeEventListener('abort', abort);
30
+ }
31
+ }
32
+ try {
33
+ controller.signal.throwIfAborted();
34
+ const credential = await bounded(options.credential());
35
+ controller.signal.throwIfAborted();
36
+ if (!credential)
37
+ throw error(401, 'unauthenticated');
38
+ const response = await bounded(options.fetch(options.url, { method: write ? 'POST' : 'GET',
39
+ headers: { authorization: `Bearer ${credential}`, accept: 'application/json' },
40
+ redirect: 'error', cache: 'no-store', signal: controller.signal }).then(response => {
41
+ if (controller.signal.aborted) {
42
+ void response.body?.cancel().catch(() => { });
43
+ throw error(0, 'transport_error');
44
+ }
45
+ return response;
46
+ }));
47
+ if (!(response.status === 200 || write && response.status === 201)) {
48
+ void response.body?.cancel().catch(() => { });
49
+ throw error(response.status, 'enrollment_unconfirmed');
50
+ }
51
+ if (!response.body || !/^application\/json(?:;|$)/i.test(response.headers.get('content-type') ?? '')) {
52
+ void response.body?.cancel().catch(() => { });
53
+ throw error(0, 'invalid_response');
54
+ }
55
+ const reader = response.body.getReader(), chunks = [];
56
+ let size = 0;
57
+ const stop = () => { void reader.cancel().catch(() => { }); };
58
+ controller.signal.addEventListener('abort', stop, { once: true });
59
+ try {
60
+ for (;;) {
61
+ const next = await bounded(reader.read());
62
+ if (next.done)
63
+ break;
64
+ size += next.value.length;
65
+ if (size > 8192)
66
+ throw error(0, 'invalid_response');
67
+ chunks.push(next.value);
68
+ }
69
+ }
70
+ finally {
71
+ controller.signal.removeEventListener('abort', stop);
72
+ stop();
73
+ try {
74
+ reader.releaseLock();
75
+ }
76
+ catch { /* cancelled read */ }
77
+ }
78
+ const bytes = new Uint8Array(size);
79
+ let offset = 0;
80
+ for (const chunk of chunks) {
81
+ bytes.set(chunk, offset);
82
+ offset += chunk.length;
83
+ }
84
+ let value;
85
+ try {
86
+ value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
87
+ }
88
+ catch {
89
+ throw error(0, 'invalid_response');
90
+ }
91
+ const fields = ['state', 'organizationId', 'projectId', 'workspaceId', 'resourceEnvironment', ...(write ? ['created'] : [])];
92
+ if (!value || Array.isArray(value) || Object.keys(value).length !== fields.length || Object.keys(value).some(k => !fields.includes(k))
93
+ || !nativeId(value.organizationId, 'o_') || !nativeId(value.projectId, 'pr_') || !nativeId(value.workspaceId, 'w_')
94
+ || value.resourceEnvironment !== 'sandbox' || !['ready', ...(write ? [] : ['not_enrolled'])].includes(String(value.state))
95
+ || write && value.created !== (response.status === 201))
96
+ throw error(0, 'invalid_response');
97
+ return Response.json(value, { status: response.status, headers: { 'cache-control': 'no-store' } });
98
+ }
99
+ catch (e) {
100
+ if (e instanceof GenesisError)
101
+ throw e;
102
+ throw error(0, 'transport_error');
103
+ }
104
+ finally {
105
+ clearTimeout(timer);
106
+ controller.abort();
107
+ options.signal?.removeEventListener('abort', cancel);
108
+ }
109
+ }
110
+ export function relaysEnrollment(client) {
111
+ return {
112
+ get: (options = {}) => client.request('relays_getEnrollment', {}, options),
113
+ activate: (options = {}) => client.request('relays_enroll', {}, options),
114
+ };
115
+ }
@@ -0,0 +1,10 @@
1
+ import { GenesisError } from './errors.js';
2
+ import type { components } from './generated/schema.js';
3
+ export type RunnerSelfExecutionGrantInput = components['schemas']['Iam.RunnerSelfExecutionGrantRequest'];
4
+ export type RunnerSelfExecutionGrant = components['schemas']['Iam.RunnerSelfExecutionGrant'];
5
+ export declare const RUNNER_SELF_GRANT_OPERATION: "iam_runnerSelfExecutionGrant";
6
+ /** Copy only primitive data descriptors before any asynchronous credential call. */
7
+ export declare function snapshotRunnerSelfGrant(args: Record<string, unknown>, routing: string): RunnerSelfExecutionGrantInput;
8
+ export declare function runnerGrantTransportError(): GenesisError;
9
+ /** A bounded closed response; no arbitrary upstream body reaches CLI or MCP. */
10
+ export declare function runnerGrantResponse(res: Response, input: RunnerSelfExecutionGrantInput): Promise<Response>;
@@ -0,0 +1,133 @@
1
+ import { GenesisError } from './errors.js';
2
+ export const RUNNER_SELF_GRANT_OPERATION = 'iam_runnerSelfExecutionGrant';
3
+ const requestKeys = ['schemaVersion', 'requestId', 'operationId', 'organizationId', 'projectId', 'platformId', 'workspaceId', 'fleetId', 'resourceEnvironment', 'expiresAtMs'];
4
+ const receiptKeys = ['id', 'principal_id', 'organization_id', 'project_id', 'platform_id', 'workspace_id', 'environmentId', 'role_ids', 'permissions', 'expires_at', 'created_at'];
5
+ const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
6
+ const match = (p, v) => typeof v === 'string' && p.exec(v)?.[0] === v;
7
+ const native = (v, prefix) => match(new RegExp('^' + prefix + '[A-Za-z0-9_]{1,32}$'), v);
8
+ const instant = (v) => typeof v === 'number' && Number.isSafeInteger(v) && v > 0;
9
+ function exact(v, keys) {
10
+ return !!v && typeof v === 'object' && !Array.isArray(v) && Object.keys(v).length === keys.length && keys.every(k => Object.hasOwn(v, k));
11
+ }
12
+ const invalid = () => new TypeError('Runner self-execution permission requires the exact ordinary-human Sandbox selection, operation, request correlation and finite expiry');
13
+ /** Copy only primitive data descriptors before any asynchronous credential call. */
14
+ export function snapshotRunnerSelfGrant(args, routing) {
15
+ if (routing !== 'gateway' || !exact(args, ['body']) || Reflect.ownKeys(args).length !== 1)
16
+ throw invalid();
17
+ const descriptor = Object.getOwnPropertyDescriptor(args, 'body');
18
+ if (!descriptor || !('value' in descriptor))
19
+ throw invalid();
20
+ const body = descriptor.value;
21
+ if (!exact(body, requestKeys) || ![Object.prototype, null].includes(Object.getPrototypeOf(body)) || Reflect.ownKeys(body).length !== requestKeys.length)
22
+ throw invalid();
23
+ const copy = {};
24
+ for (const key of requestKeys) {
25
+ const d = Object.getOwnPropertyDescriptor(body, key);
26
+ if (!d || !('value' in d) || !d.enumerable || (d.value !== null && !['string', 'number'].includes(typeof d.value)))
27
+ throw invalid();
28
+ copy[key] = d.value;
29
+ }
30
+ const now = Date.now();
31
+ if (copy.schemaVersion !== 1 || !match(uuid, copy.requestId) || !match(uuid, copy.operationId)
32
+ || !native(copy.organizationId, 'o_') || !native(copy.projectId, 'pr_') || !native(copy.workspaceId, 'w_')
33
+ || copy.platformId !== 'pf_console' || copy.fleetId !== null || copy.resourceEnvironment !== 'sandbox'
34
+ || !instant(copy.expiresAtMs) || copy.expiresAtMs <= now || copy.expiresAtMs > now + 1_800_000)
35
+ throw invalid();
36
+ return Object.freeze(copy);
37
+ }
38
+ function closedJson(raw) {
39
+ const value = JSON.parse(raw);
40
+ const stack = [];
41
+ for (const token of raw.match(/"(?:\\.|[^"\\])*"|[{}\[\],:]|true|false|null|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/g) ?? []) {
42
+ const frame = stack.at(-1);
43
+ if (token === '{' || token === '[')
44
+ stack.push({ object: token === '{', key: token === '{', keys: new Set() });
45
+ else if (token === '}' || token === ']')
46
+ stack.pop();
47
+ else if (token === ',' && frame?.object)
48
+ frame.key = true;
49
+ else if (token === ':' && frame?.object)
50
+ frame.key = false;
51
+ else if (token.startsWith('"') && frame?.object && frame.key) {
52
+ const key = JSON.parse(token);
53
+ if (frame.keys.has(key))
54
+ throw invalid();
55
+ frame.keys.add(key);
56
+ }
57
+ else if (/^-?\d/.test(token) && !/^-?(?:0|[1-9]\d*)$/.test(token))
58
+ throw invalid();
59
+ }
60
+ return value;
61
+ }
62
+ const errorRows = [
63
+ [400, 'INVALID_ARGUMENT', 'invalid Runner self-execution grant request', 'invalid_runner_self_execution_grant_request'],
64
+ [400, 'INVALID_ARGUMENT', 'Runner self-execution grant expiry is out of bounds', 'runner_self_execution_grant_expiry_out_of_bounds'],
65
+ [401, 'UNAUTHENTICATED', 'Runner self-execution authority inactive', 'runner_self_execution_grant_inactive'],
66
+ [403, 'PERMISSION_DENIED', 'Runner self-execution authority denied', 'runner_self_execution_grant_denied'],
67
+ [409, 'CONFLICT', 'Runner self-execution grant operation conflict', 'runner_self_execution_grant_conflict'],
68
+ [409, 'CONFLICT', 'Runner self-execution grant replay is stale', 'runner_self_execution_grant_replay_stale'],
69
+ [503, 'PROVIDER_UNAVAILABLE', 'Runner self-execution grant unavailable', 'runner_self_execution_grant_unavailable'],
70
+ ];
71
+ function uncertain(status, message) {
72
+ return new GenesisError({ status, type: 'runner_grant_uncertain', operationId: RUNNER_SELF_GRANT_OPERATION, message });
73
+ }
74
+ export function runnerGrantTransportError() {
75
+ return uncertain(0, 'Runner permission response was lost. Retry the same operation, scope and expiry with fresh request correlation.');
76
+ }
77
+ /** A bounded closed response; no arbitrary upstream body reaches CLI or MCP. */
78
+ export async function runnerGrantResponse(res, input) {
79
+ let value;
80
+ try {
81
+ if (res.redirected || res.headers.get('content-type')?.split(';')[0].trim().toLowerCase() !== 'application/json')
82
+ throw invalid();
83
+ const reader = res.body?.getReader();
84
+ const chunks = [];
85
+ let size = 0;
86
+ if (reader) {
87
+ try {
88
+ while (true) {
89
+ const next = await reader.read();
90
+ if (next.done)
91
+ break;
92
+ size += next.value.byteLength;
93
+ if (size > 8192) {
94
+ await reader.cancel();
95
+ throw invalid();
96
+ }
97
+ chunks.push(next.value);
98
+ }
99
+ }
100
+ finally {
101
+ reader.releaseLock();
102
+ }
103
+ }
104
+ const bytes = new Uint8Array(size);
105
+ let offset = 0;
106
+ for (const chunk of chunks) {
107
+ bytes.set(chunk, offset);
108
+ offset += chunk.byteLength;
109
+ }
110
+ value = closedJson(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
111
+ }
112
+ catch {
113
+ throw uncertain(res.status, 'Runner permission could not be confirmed. Retry the same operation, scope and expiry with fresh request correlation.');
114
+ }
115
+ if (res.status !== 200) {
116
+ if (exact(value, ['code', 'message', 'details']) && exact(value.details, ['schemaVersion', 'reason']) && value.details.schemaVersion === 1) {
117
+ const details = value.details;
118
+ const row = errorRows.find(r => r[0] === res.status && r[1] === value.code && r[2] === value.message && r[3] === details.reason);
119
+ if (row)
120
+ throw new GenesisError({ status: res.status, type: 'runner_grant_denied', code: row[1], operationId: RUNNER_SELF_GRANT_OPERATION, message: row[2], body: value });
121
+ }
122
+ throw uncertain(res.status, 'Runner permission is unavailable or unconfirmed. Retry the same operation, scope and expiry with fresh request correlation.');
123
+ }
124
+ if (!exact(value, receiptKeys) || !match(/^g_[0-7][0123456789ABCDEFGHJKMNPQRSTVWXYZ]{25}$/, value.id)
125
+ || !native(value.principal_id, 'h_') || value.organization_id !== input.organizationId || value.project_id !== input.projectId
126
+ || value.platform_id !== input.platformId || value.workspace_id !== input.workspaceId || value.environmentId !== input.resourceEnvironment
127
+ || !Array.isArray(value.role_ids) || value.role_ids.length !== 0 || !Array.isArray(value.permissions)
128
+ || value.permissions.length !== 1 || value.permissions[0] !== 'runner.tasks.execute'
129
+ || value.expires_at !== input.expiresAtMs || input.expiresAtMs <= Date.now() || !instant(value.created_at) || value.created_at >= input.expiresAtMs) {
130
+ throw uncertain(502, 'Runner returned an unqualified permission receipt. Retry the same operation, scope and expiry to reconcile it.');
131
+ }
132
+ return Response.json(value, { status: 200, headers: { 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff' } });
133
+ }
@@ -0,0 +1,68 @@
1
+ import type { GenesisClient } from './client.js';
2
+ import type { components } from './generated/schema.js';
3
+ import { type RunnerSelfExecutionGrantInput } from './runner-grant.js';
4
+ type Schemas = components['schemas'];
5
+ export type RunnerStartInput = Schemas['Runner.StartInput'];
6
+ export type RunnerSnapshot = Schemas['Runner.Snapshot'];
7
+ export type RunnerCatalog = Schemas['Runner.Catalog'];
8
+ export type RunnerEvent = Schemas['Runner.Event'];
9
+ export type RunnerProviderResult = Schemas['Runner.ProviderResult'];
10
+ export type RunnerRequestOptions = {
11
+ signal?: AbortSignal;
12
+ };
13
+ /** Runner routes use the Genesis client's credential; the backend owns org/subject scoping. */
14
+ export declare function runnerModule(client: GenesisClient): Readonly<{
15
+ permission: Readonly<{
16
+ grant: (input: RunnerSelfExecutionGrantInput, opts?: RunnerRequestOptions) => Promise<{
17
+ id: string;
18
+ principal_id: string;
19
+ organization_id: string;
20
+ project_id: string;
21
+ platform_id: "pf_console";
22
+ workspace_id: string;
23
+ environmentId: "sandbox";
24
+ role_ids: unknown[];
25
+ permissions: "runner.tasks.execute"[];
26
+ expires_at: number;
27
+ created_at: number;
28
+ }>;
29
+ }>;
30
+ catalog: (opts?: RunnerRequestOptions) => Promise<{
31
+ workspaces: {
32
+ key: components["schemas"]["Runner.SafeOpaqueRef"];
33
+ label: string;
34
+ }[];
35
+ routes: {
36
+ routeId: components["schemas"]["Runner.SafeOpaqueRef"];
37
+ kind: "external-harness" | "internal-model";
38
+ name: string;
39
+ via: string;
40
+ state: "synthetic" | "bound" | "unbound";
41
+ default: boolean;
42
+ }[];
43
+ }>;
44
+ jobs: Readonly<{
45
+ list: (opts?: RunnerRequestOptions) => Promise<{
46
+ jobs: components["schemas"]["Runner.Snapshot"][];
47
+ }>;
48
+ start: (input: RunnerStartInput, opts?: RunnerRequestOptions) => Promise<{
49
+ jobId: components["schemas"]["Runner.SafeOpaqueRef"];
50
+ snapshot: components["schemas"]["Runner.Snapshot"];
51
+ }>;
52
+ get: (jobId: string, opts?: RunnerRequestOptions) => Promise<{
53
+ snapshot: components["schemas"]["Runner.Snapshot"];
54
+ }>;
55
+ events: (jobId: string, afterSeq?: number, opts?: RunnerRequestOptions) => Promise<{
56
+ events: components["schemas"]["Runner.Event"][];
57
+ nextAfterSeq: number;
58
+ hasMore: boolean;
59
+ }>;
60
+ result: (jobId: string, opts?: RunnerRequestOptions) => Promise<{
61
+ result: components["schemas"]["Runner.ProviderResult"];
62
+ }>;
63
+ cancel: (jobId: string, opts?: RunnerRequestOptions) => Promise<{
64
+ snapshot: components["schemas"]["Runner.Snapshot"];
65
+ }>;
66
+ }>;
67
+ }>;
68
+ export {};