@lifesi/genesis 0.1.1 → 0.1.3

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 (44) hide show
  1. package/dist/beacons.d.ts +46 -0
  2. package/dist/beacons.js +20 -0
  3. package/dist/client.d.ts +7669 -1635
  4. package/dist/client.js +54 -5
  5. package/dist/dials.d.ts +171 -1
  6. package/dist/dials.js +40 -0
  7. package/dist/fleets.d.ts +109 -1
  8. package/dist/fleets.js +89 -1
  9. package/dist/flocks.d.ts +73 -0
  10. package/dist/flocks.js +22 -0
  11. package/dist/generated/operations.d.ts +7669 -1635
  12. package/dist/generated/operations.js +9193 -1691
  13. package/dist/generated/schema.d.ts +16979 -5698
  14. package/dist/genesis.d.ts +795 -13
  15. package/dist/genesis.js +21 -0
  16. package/dist/genesis.openapi.json +23483 -7599
  17. package/dist/henry.d.ts +7 -0
  18. package/dist/henry.js +23 -0
  19. package/dist/hives-cells.d.ts +127 -0
  20. package/dist/hives-cells.js +151 -0
  21. package/dist/hives-environment.d.ts +28 -0
  22. package/dist/hives-environment.js +58 -0
  23. package/dist/hives-functions.d.ts +1 -1
  24. package/dist/hives-functions.js +3 -1
  25. package/dist/hives-marketplace.d.ts +128 -0
  26. package/dist/hives-marketplace.js +187 -0
  27. package/dist/hives-node.js +2 -0
  28. package/dist/hives-operations.d.ts +304 -0
  29. package/dist/hives-operations.js +39 -0
  30. package/dist/hives-queues.d.ts +121 -0
  31. package/dist/hives-queues.js +106 -0
  32. package/dist/hives-resources-transport.d.ts +18 -0
  33. package/dist/hives-resources-transport.js +165 -0
  34. package/dist/hives-runtimes.d.ts +34 -0
  35. package/dist/hives-runtimes.js +32 -0
  36. package/dist/hives-volumes.d.ts +64 -0
  37. package/dist/hives-volumes.js +117 -0
  38. package/dist/index.d.ts +8 -1
  39. package/dist/index.js +3 -0
  40. package/dist/runner-grant.d.ts +10 -0
  41. package/dist/runner-grant.js +133 -0
  42. package/dist/runner.d.ts +16 -0
  43. package/dist/runner.js +4 -0
  44. package/package.json +6 -1
@@ -0,0 +1,117 @@
1
+ import { hivesResourceCall, hivesResourceId, resourceError } from './hives-resources-transport.js';
2
+ const MIB = 1024 * 1024;
3
+ const states = ['creating', 'available', 'attaching', 'attached', 'detaching', 'deleting', 'failed'];
4
+ function object(value) {
5
+ if (!value || typeof value !== 'object' || Array.isArray(value))
6
+ throw resourceError(0);
7
+ return value;
8
+ }
9
+ function text(value, max = 128) {
10
+ if (typeof value !== 'string' || !value || value.length > max || /[\u0000-\u001f\u007f]/.test(value))
11
+ throw resourceError(0);
12
+ return value;
13
+ }
14
+ function count(value) {
15
+ if (!Number.isSafeInteger(value) || value < 0)
16
+ throw resourceError(0);
17
+ return value;
18
+ }
19
+ function date(value) { const result = text(value, 64); if (!Number.isFinite(Date.parse(result)))
20
+ throw resourceError(0); return result; }
21
+ function volume(value, project, expectedId) {
22
+ const row = object(value);
23
+ if (row.project_id !== project || row.storage_class !== 'local' || row.access_mode !== 'read_write_once'
24
+ || !states.includes(row.state) || typeof row.operation_pending !== 'boolean')
25
+ throw resourceError(0);
26
+ const id = hivesResourceId(text(row.id));
27
+ if (expectedId && id !== expectedId)
28
+ throw resourceError(0);
29
+ const backing = count(row.backing_bytes);
30
+ const capacity = row.capacity_bytes === null ? null : count(row.capacity_bytes);
31
+ const used = row.used_bytes === null ? null : count(row.used_bytes);
32
+ if (backing < 32 * MIB || backing > 1024 * MIB || row.size_gib !== backing / (1024 * MIB)
33
+ || capacity !== null && capacity > backing || used !== null && (capacity === null || used > capacity))
34
+ throw resourceError(0);
35
+ const path = row.mount_path === null ? null : text(row.mount_path, 512);
36
+ const attached = row.attached_to === null ? null : hivesResourceId(text(row.attached_to));
37
+ if ((path === null) !== (attached === null) || (attached === null ? row.read_only !== null : typeof row.read_only !== 'boolean'))
38
+ throw resourceError(0);
39
+ const generation = count(row.generation);
40
+ if (generation < 1)
41
+ throw resourceError(0);
42
+ return { id, project_id: project, name: text(row.name, 64), size_gib: backing / (1024 * MIB), backing_bytes: backing,
43
+ capacity_bytes: capacity, used_bytes: used, storage_class: 'local', access_mode: 'read_write_once',
44
+ state: row.state, operation_pending: row.operation_pending, generation,
45
+ mount_path: path, attached_to: attached, read_only: row.read_only,
46
+ created_at: date(row.created_at), updated_at: date(row.updated_at) };
47
+ }
48
+ /** Persisted project storage. A failed acknowledgement never triggers an automatic write retry. */
49
+ export function hivesVolumes(client) {
50
+ const ids = (project, id) => ({ project_id: hivesResourceId(project), ...(id === undefined ? {} : { volume_id: hivesResourceId(id) }) });
51
+ const call = (id, input, options) => hivesResourceCall(client, id, input, options);
52
+ return {
53
+ async list(project, query = {}, options) {
54
+ const page = query.page ?? 1;
55
+ const perPage = query.per_page ?? 25;
56
+ if (Object.keys(query).some(key => !['page', 'per_page'].includes(key)) || !Number.isSafeInteger(page) || page < 1 || page > 10000
57
+ || !Number.isSafeInteger(perPage) || perPage < 1 || perPage > 100)
58
+ throw resourceError(0);
59
+ const result = object(await call('hives_list_volumes', { ...ids(project), page, per_page: perPage }, options));
60
+ const pagination = object(result.pagination);
61
+ const total = count(pagination.total);
62
+ const pages = count(pagination.total_pages);
63
+ if (pagination.page !== page || pagination.per_page !== perPage || pages !== Math.ceil(total / perPage)
64
+ || !Array.isArray(result.volumes) || result.volumes.length > perPage)
65
+ throw resourceError(0);
66
+ const volumes = result.volumes.map(row => volume(row, project));
67
+ if (new Set(volumes.map(row => row.id)).size !== volumes.length)
68
+ throw resourceError(0);
69
+ return { volumes, pagination: { page, per_page: perPage, total, total_pages: pages } };
70
+ },
71
+ async get(project, id, options) { return volume(await call('hives_get_volume', ids(project, id), options), project, id); },
72
+ async create(project, input, options) {
73
+ const body = object(input);
74
+ const name = text(body.name, 64);
75
+ let size;
76
+ if (body.size_mib !== undefined && body.size_gib === undefined)
77
+ size = count(body.size_mib);
78
+ else if (body.size_mib === undefined && body.size_gib === 1)
79
+ size = 1024;
80
+ else
81
+ throw resourceError(0);
82
+ if (name.trim() !== name || size < 32 || size > 1024 || body.storage_class !== undefined && body.storage_class !== 'local'
83
+ || body.access_mode !== undefined && body.access_mode !== 'read_write_once'
84
+ || Object.keys(body).some(key => !['name', 'size_mib', 'size_gib', 'storage_class', 'access_mode'].includes(key)))
85
+ throw resourceError(0);
86
+ const result = volume(await call('hives_create_volume', { ...ids(project), body: { name, size_mib: size, storage_class: 'local', access_mode: 'read_write_once' } }, options), project);
87
+ if (result.name !== name || result.backing_bytes !== size * MIB)
88
+ throw resourceError(0);
89
+ return result;
90
+ },
91
+ async mount(project, id, input, options) {
92
+ const body = object(input);
93
+ const target = hivesResourceId(text(body.target_id));
94
+ const path = text(body.mount_path, 128);
95
+ if (!/^\/[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*$/.test(path) || typeof body.read_only !== 'boolean'
96
+ || Object.keys(body).some(key => !['target_id', 'mount_path', 'read_only'].includes(key)))
97
+ throw resourceError(0);
98
+ const readOnly = body.read_only;
99
+ const result = volume(await call('hives_mount_volume', { ...ids(project, id), body: { target_id: target, mount_path: path, read_only: readOnly } }, options), project, id);
100
+ if (result.attached_to !== target || result.mount_path !== path || result.read_only !== readOnly)
101
+ throw resourceError(0);
102
+ return result;
103
+ },
104
+ async unmount(project, id, options) {
105
+ const result = volume(await call('hives_unmount_volume', ids(project, id), options), project, id);
106
+ if (result.state !== 'available' || result.operation_pending || result.attached_to !== null || result.mount_path !== null || result.read_only !== null)
107
+ throw resourceError(0);
108
+ return result;
109
+ },
110
+ async remove(project, id, options) {
111
+ const result = object(await call('hives_delete_volume', ids(project, id), options));
112
+ if (result.id !== id || result.success !== true)
113
+ throw resourceError(0);
114
+ return { success: true, id, message: text(result.message, 256) };
115
+ },
116
+ };
117
+ }
package/dist/index.d.ts CHANGED
@@ -8,5 +8,12 @@ export { hivesUploadBody, MAX_WASM_BYTES, type HivesUploadOptions } from './hive
8
8
  export { validateHivesInvocation, hivesFunctionResponseHeaders, MAX_FUNCTION_BODY_BYTES, MAX_FUNCTION_JSON_BYTES, type HivesInvokeRequest } from './hives-functions.js';
9
9
  export { hivesResponseBytes } from './hives-response.js';
10
10
  export { runnerModule, type RunnerStartInput, type RunnerSnapshot, type RunnerCatalog, type RunnerEvent, type RunnerProviderResult, type RunnerRequestOptions } from './runner.js';
11
+ export type { RunnerSelfExecutionGrantInput, RunnerSelfExecutionGrant } from './runner-grant.js';
11
12
  export { beaconsModule } from './beacons.js';
12
- export { dialsModule, dialsEmergencyAddressFeedback, type DialsEmergencyAddressFeedback, type DialsScope, type DialsOutboundCall, type DialsCallControl, type DialsEmergencyAddress } from './dials.js';
13
+ export { dialsModule, dialsEmergencyAddressFeedback, type DialsEmergencyAddressFeedback, type DialsScope, type DialsOutboundCall, type DialsCallControl, type DialsEmergencyAddress, type DialsCallListItem, type DialsCallDispatchState, type DialsMessage, type DialsMessageTemplate, type DialsMessagingBrand, type DialsMessagingCampaign, type DialsWorkflowDocument, type DialsRoutingAction, type DialsRoutingRule, type DialsRoutingRuleReceipt, type DialsOutboundCallReceipt, type DialsRecoveredOutboundCallReceipt } from './dials.js';
14
+ export { hivesObjectKey, type HivesBucket, type HivesObject, type HivesObjectAcknowledgement, type HivesObjectList, type HivesCorsRule, type HivesCreateBucket, type HivesPresign, type HivesPresignedUrl } from './hives-cells.js';
15
+ export { hivesQueueBody, type HivesQueue, type HivesQueueConfig, type HivesQueueCreate, type HivesQueueSend, type HivesQueueDelivery, type HivesDeadLetter, type HivesDeadLetterStats } from './hives-queues.js';
16
+ export type { HivesRuntime, HivesRuntimeSelection } from './hives-runtimes.js';
17
+ export type { HivesVolume, HivesVolumeCreate, HivesVolumeMount, HivesVolumePage } from './hives-volumes.js';
18
+ export { HIVES_OBJECT_BYTES, HIVES_QUEUE_BYTES, type HivesResourceOptions } from './hives-resources-transport.js';
19
+ export type { HivesMarketplacePackage, HivesMarketplaceVersion, HivesMarketplaceInstallation, HivesMarketplaceCategory, HivesMarketplacePage, HivesMarketplacePublish, HivesMarketplaceInstall, HivesMarketplaceSearch, HivesMarketplaceDetail } from './hives-marketplace.js';
package/dist/index.js CHANGED
@@ -8,3 +8,6 @@ export { hivesResponseBytes } from './hives-response.js';
8
8
  export { runnerModule } from './runner.js';
9
9
  export { beaconsModule } from './beacons.js';
10
10
  export { dialsModule, dialsEmergencyAddressFeedback } from './dials.js';
11
+ export { hivesObjectKey } from './hives-cells.js';
12
+ export { hivesQueueBody } from './hives-queues.js';
13
+ export { HIVES_OBJECT_BYTES, HIVES_QUEUE_BYTES } from './hives-resources-transport.js';
@@ -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
+ }
package/dist/runner.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { GenesisClient } from './client.js';
2
2
  import type { components } from './generated/schema.js';
3
+ import { type RunnerSelfExecutionGrantInput } from './runner-grant.js';
3
4
  type Schemas = components['schemas'];
4
5
  export type RunnerStartInput = Schemas['Runner.StartInput'];
5
6
  export type RunnerSnapshot = Schemas['Runner.Snapshot'];
@@ -11,6 +12,21 @@ export type RunnerRequestOptions = {
11
12
  };
12
13
  /** Runner routes use the Genesis client's credential; the backend owns org/subject scoping. */
13
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
+ }>;
14
30
  catalog: (opts?: RunnerRequestOptions) => Promise<{
15
31
  workspaces: {
16
32
  key: components["schemas"]["Runner.SafeOpaqueRef"];
package/dist/runner.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { RUNNER_SELF_GRANT_OPERATION } from './runner-grant.js';
1
2
  const requestOptions = (options) => ({ signal: options.signal });
2
3
  const opaqueId = (v) => typeof v === 'string' && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(v);
3
4
  const pathLike = (v) => /^[A-Za-z]:/.test(v) || v.includes('..');
@@ -95,6 +96,9 @@ function checkedStartInput(input) {
95
96
  /** Runner routes use the Genesis client's credential; the backend owns org/subject scoping. */
96
97
  export function runnerModule(client) {
97
98
  return Object.freeze({
99
+ permission: Object.freeze({
100
+ grant: (input, opts = {}) => client.request(RUNNER_SELF_GRANT_OPERATION, { body: input }, requestOptions(opts)),
101
+ }),
98
102
  catalog: (opts = {}) => client.request('runner_getCatalog', undefined, requestOptions(opts)),
99
103
  jobs: Object.freeze({
100
104
  list: (opts = {}) => client.request('runner_listJobs', undefined, requestOptions(opts)),
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@lifesi/genesis",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/l1felabs/genesis-api.git",
7
+ "directory": "packages/sdk"
8
+ },
4
9
  "description": "One typed SDK for every Genesis service (Foundry, Hives, Relays, IAM...) via the Genesis API gateway",
5
10
  "type": "module",
6
11
  "main": "dist/index.js",