@onesi/genesis 0.0.0-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 +28 -2
- 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 +46 -3
package/README.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @onesi/genesis
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The TypeScript SDK for OneOS. One typed client for every Genesis service, through the Genesis API at `https://os.one.ml/api`.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install @onesi/genesis@0.1.13
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Genesis, GenesisError } from '@onesi/genesis';
|
|
11
|
+
|
|
12
|
+
const genesis = new Genesis({ apiKey: process.env.GENESIS_API_KEY });
|
|
13
|
+
try {
|
|
14
|
+
const projects = await genesis.hives.projects.list();
|
|
15
|
+
} catch (e) {
|
|
16
|
+
if (e instanceof GenesisError) console.error(e.status, e.code, e.requestId, e.message);
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- **Credentials:** create an organization API key in the Console at https://os.one.ml (API keys → Create) and pass it as `apiKey` or `GENESIS_API_KEY`. A WorkOS M2M or session token goes in `token` / `GENESIS_TOKEN`.
|
|
21
|
+
- **Gateway:** defaults to `https://os.one.ml/api`; `https://console.life.one/api` is an alias. Override with `baseUrl` or `GENESIS_BASE_URL`. Only `https://` (or `http://` on loopback) is accepted.
|
|
22
|
+
- **Every operation:** `genesis.call(operationId, input)` reaches any operation in the bundled OpenAPI document (`@onesi/genesis/spec.json`). `operationTable` lists them.
|
|
23
|
+
- **Live service state:** `GET /v1/status` (or `genesis status` in the CLI).
|
|
24
|
+
- **Errors:** every failure is a `GenesisError` with `status`, `code`, `requestId` and a message from the gateway's error catalog. `errorCatalog(e)` adds `required_scope` and `docs_url`.
|
|
25
|
+
- **Runtime:** ESM only, Node.js 20.19 or later.
|
|
26
|
+
|
|
27
|
+
Use the same version of the SDK, [`@onesi/genesis-cli`](https://www.npmjs.com/package/@onesi/genesis-cli) and [`@onesi/genesis-mcp`](https://www.npmjs.com/package/@onesi/genesis-mcp).
|
|
28
|
+
|
|
29
|
+
Docs: https://os.one.ml/docs · API reference: https://os.one.ml/api/v1/openapi.json · Error codes: https://os.one.ml/api/v1/errors
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { GenesisClient } from './client.js';
|
|
2
|
+
import type { OperationInput, OperationOutput } from './types.js';
|
|
3
|
+
type DashboardOptions = {
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
};
|
|
6
|
+
type PolicyConfig = OperationInput<'beacons_updateDashboardPolicy'>['body']['config'];
|
|
7
|
+
/** Beacons uses the authenticated Genesis organization; never supply an org header. */
|
|
8
|
+
export declare function beaconsModule(client: GenesisClient): {
|
|
9
|
+
fleets: {
|
|
10
|
+
/** Current human-authorized selected Sandbox scope; no caller tenant identifiers. */
|
|
11
|
+
list: (options?: DashboardOptions) => Promise<{
|
|
12
|
+
data: import("./index.js").components["schemas"]["Beacons.DashboardFleet"][];
|
|
13
|
+
}>;
|
|
14
|
+
update: (id: string, body: {
|
|
15
|
+
name: string;
|
|
16
|
+
}, options?: DashboardOptions) => Promise<{
|
|
17
|
+
data: import("./index.js").components["schemas"]["Beacons.DashboardFleet"];
|
|
18
|
+
}>;
|
|
19
|
+
peers: (id: string, options?: DashboardOptions) => Promise<{
|
|
20
|
+
data: import("./index.js").components["schemas"]["Beacons.DashboardPeer"][];
|
|
21
|
+
}>;
|
|
22
|
+
policy: {
|
|
23
|
+
get: (id: string, options?: DashboardOptions) => Promise<{
|
|
24
|
+
data: {
|
|
25
|
+
fleet_id: string;
|
|
26
|
+
config: import("./index.js").components["schemas"]["Beacons.DashboardPolicyConfig"];
|
|
27
|
+
source: "default" | "persisted";
|
|
28
|
+
updated_at: string | null;
|
|
29
|
+
scope: import("./index.js").components["schemas"]["Beacons.DashboardScope"];
|
|
30
|
+
};
|
|
31
|
+
}>;
|
|
32
|
+
/** Future device admissions only; this never grants IAM rights or revokes an existing peer. */
|
|
33
|
+
update: (id: string, config: PolicyConfig, options?: DashboardOptions) => Promise<{
|
|
34
|
+
data: {
|
|
35
|
+
fleet_id: string;
|
|
36
|
+
config: import("./index.js").components["schemas"]["Beacons.DashboardPolicyConfig"];
|
|
37
|
+
source: "default" | "persisted";
|
|
38
|
+
updated_at: string | null;
|
|
39
|
+
scope: import("./index.js").components["schemas"]["Beacons.DashboardScope"];
|
|
40
|
+
};
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
/** Reuse the same request ID and body after an interrupted response. Creates metadata only. */
|
|
44
|
+
provision: (requestId: string, body?: {
|
|
45
|
+
name?: string;
|
|
46
|
+
}) => Promise<{
|
|
47
|
+
data: {
|
|
48
|
+
fleet_id: string;
|
|
49
|
+
organization_id: string;
|
|
50
|
+
workspace_id: string;
|
|
51
|
+
project_id: string;
|
|
52
|
+
environment_id: string;
|
|
53
|
+
metadata_only: true;
|
|
54
|
+
};
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
devices: {
|
|
58
|
+
revocations: (id: string) => Promise<{
|
|
59
|
+
data: import("./index.js").components["schemas"]["Beacons.DeviceRevocation"][];
|
|
60
|
+
}>;
|
|
61
|
+
acknowledge: (id: string, version: number, body: OperationInput<"beacons_acknowledgeBridgeDeviceRevocation">["body"]) => Promise<{
|
|
62
|
+
data: import("./index.js").components["schemas"]["Beacons.DeviceRevocation"];
|
|
63
|
+
}>;
|
|
64
|
+
challenge: (body: OperationInput<"beacons_issueBridgeDeviceChallenge">["body"]) => Promise<{
|
|
65
|
+
version: 1;
|
|
66
|
+
id: string;
|
|
67
|
+
nonce: string;
|
|
68
|
+
issuer: string;
|
|
69
|
+
organization: string;
|
|
70
|
+
principal: string;
|
|
71
|
+
workspace: string;
|
|
72
|
+
project: string;
|
|
73
|
+
environment: string;
|
|
74
|
+
binding_revision: string;
|
|
75
|
+
transport: string;
|
|
76
|
+
fleet_id: string;
|
|
77
|
+
proof_key: string;
|
|
78
|
+
tunnel_key: string;
|
|
79
|
+
issued_at: number;
|
|
80
|
+
expires_at: number;
|
|
81
|
+
}>;
|
|
82
|
+
enroll: (body: OperationInput<"beacons_enrollBridgeDevice">["body"]) => Promise<{
|
|
83
|
+
device_id: string;
|
|
84
|
+
fleet_id: string;
|
|
85
|
+
mesh: {
|
|
86
|
+
[key: string]: unknown;
|
|
87
|
+
};
|
|
88
|
+
}>;
|
|
89
|
+
list: () => Promise<{
|
|
90
|
+
data?: import("./index.js").components["schemas"]["Beacons.BridgeDevice"][];
|
|
91
|
+
}>;
|
|
92
|
+
update: (id: string, body: OperationInput<"beacons_updateBridgeDevice">["body"]) => Promise<{
|
|
93
|
+
id: string;
|
|
94
|
+
org_id: string;
|
|
95
|
+
name: string;
|
|
96
|
+
nicknames: string[];
|
|
97
|
+
created_at: string;
|
|
98
|
+
status: string;
|
|
99
|
+
}>;
|
|
100
|
+
revoke: (id: string) => Promise<OperationOutput<"beacons_revokeBridgeDevice"> | undefined>;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
export {};
|
package/dist/beacons.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { GenesisError } from './errors.js';
|
|
2
|
+
function invalidDashboard(operationId) {
|
|
3
|
+
throw new GenesisError({ status: 0, type: 'invalid_request', operationId,
|
|
4
|
+
message: 'Provide a canonical fleet UUID and only the documented Beacons fields.' });
|
|
5
|
+
}
|
|
6
|
+
function fleetId(id, operationId) {
|
|
7
|
+
if (typeof id !== 'string' || id.length !== 36 || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id)
|
|
8
|
+
|| id === '00000000-0000-0000-0000-000000000000')
|
|
9
|
+
invalidDashboard(operationId);
|
|
10
|
+
return id;
|
|
11
|
+
}
|
|
12
|
+
function renameInput(body) {
|
|
13
|
+
const op = 'beacons_updateDashboardFleet';
|
|
14
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)
|
|
15
|
+
|| Object.keys(body).length !== 1 || !Object.hasOwn(body, 'name'))
|
|
16
|
+
invalidDashboard(op);
|
|
17
|
+
const suppliedName = body.name;
|
|
18
|
+
if (typeof suppliedName !== 'string')
|
|
19
|
+
invalidDashboard(op);
|
|
20
|
+
const name = suppliedName.trim();
|
|
21
|
+
if (!name || new TextEncoder().encode(name).length > 128 || /[\u0000-\u001f\u007f-\u009f]/.test(name))
|
|
22
|
+
invalidDashboard(op);
|
|
23
|
+
return { name };
|
|
24
|
+
}
|
|
25
|
+
function policyInput(config) {
|
|
26
|
+
const op = 'beacons_updateDashboardPolicy';
|
|
27
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)
|
|
28
|
+
|| Object.keys(config).some(key => !['device_enrollment', 'max_devices'].includes(key))
|
|
29
|
+
|| !Object.hasOwn(config, 'device_enrollment'))
|
|
30
|
+
invalidDashboard(op);
|
|
31
|
+
const mode = config.device_enrollment;
|
|
32
|
+
const limit = config.max_devices;
|
|
33
|
+
if (!['allowed_with_permission', 'paused'].includes(mode)
|
|
34
|
+
|| (limit !== undefined && (!Number.isInteger(limit) || limit < 1 || limit > 10000)))
|
|
35
|
+
invalidDashboard(op);
|
|
36
|
+
// Snapshot before the asynchronous credential provider can change the caller's object.
|
|
37
|
+
return { config: { device_enrollment: mode,
|
|
38
|
+
...(limit === undefined ? {} : { max_devices: limit }) } };
|
|
39
|
+
}
|
|
40
|
+
function provisioningInput(requestId, body) {
|
|
41
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(requestId)
|
|
42
|
+
|| requestId === '00000000-0000-0000-0000-000000000000'
|
|
43
|
+
|| !body || typeof body !== 'object' || Array.isArray(body)
|
|
44
|
+
|| Object.keys(body).some(key => key !== 'name')
|
|
45
|
+
|| (body.name !== undefined && (typeof body.name !== 'string' || !body.name.trim()
|
|
46
|
+
|| new TextEncoder().encode(body.name).length > 256 || /[\u0000-\u001f\u007f-\u009f]/.test(body.name)))) {
|
|
47
|
+
throw new GenesisError({ status: 0, type: 'invalid_request', operationId: 'beacons_provisionBridgeFleet', message: 'Provide a nonzero UUID request ID and an optional fleet name of up to 256 UTF-8 bytes.' });
|
|
48
|
+
}
|
|
49
|
+
return body.name === undefined ? {} : { name: body.name };
|
|
50
|
+
}
|
|
51
|
+
/** Beacons uses the authenticated Genesis organization; never supply an org header. */
|
|
52
|
+
export function beaconsModule(client) {
|
|
53
|
+
return {
|
|
54
|
+
fleets: {
|
|
55
|
+
/** Current human-authorized selected Sandbox scope; no caller tenant identifiers. */
|
|
56
|
+
list: (options = {}) => client.request('beacons_listDashboardFleets', {}, options),
|
|
57
|
+
update: (id, body, options = {}) => client.request('beacons_updateDashboardFleet', { fleet_id: fleetId(id, 'beacons_updateDashboardFleet'), body: renameInput(body) }, options),
|
|
58
|
+
peers: (id, options = {}) => client.request('beacons_listDashboardPeers', { fleet_id: fleetId(id, 'beacons_listDashboardPeers') }, options),
|
|
59
|
+
policy: {
|
|
60
|
+
get: (id, options = {}) => client.request('beacons_getDashboardPolicy', { fleet_id: fleetId(id, 'beacons_getDashboardPolicy') }, options),
|
|
61
|
+
/** Future device admissions only; this never grants IAM rights or revokes an existing peer. */
|
|
62
|
+
update: (id, config, options = {}) => client.request('beacons_updateDashboardPolicy', { fleet_id: fleetId(id, 'beacons_updateDashboardPolicy'), body: policyInput(config) }, options),
|
|
63
|
+
},
|
|
64
|
+
/** Reuse the same request ID and body after an interrupted response. Creates metadata only. */
|
|
65
|
+
provision: (requestId, body = {}) => client.request('beacons_provisionBridgeFleet', { body: provisioningInput(requestId, body) }, { headers: { 'idempotency-key': requestId } }),
|
|
66
|
+
},
|
|
67
|
+
devices: {
|
|
68
|
+
revocations: (id) => client.request('beacons_listBridgeDeviceRevocations', { id }),
|
|
69
|
+
acknowledge: (id, version, body) => client.request('beacons_acknowledgeBridgeDeviceRevocation', { id, version, body }),
|
|
70
|
+
challenge: (body) => client.request('beacons_issueBridgeDeviceChallenge', { body }),
|
|
71
|
+
enroll: (body) => client.request('beacons_enrollBridgeDevice', { body }),
|
|
72
|
+
list: () => client.request('beacons_listBridgeDevices'),
|
|
73
|
+
update: (id, body) => client.request('beacons_updateBridgeDevice', { id, body }),
|
|
74
|
+
revoke: (id) => client.request('beacons_revokeBridgeDevice', { id }),
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { GenesisClient } from './client.js';
|
|
2
|
+
import type { OperationInput } from './types.js';
|
|
3
|
+
export declare const isBlindsOwnerOperation: (id: string) => boolean;
|
|
4
|
+
/** One original-human operation; all public metadata, no arbitrary signing payload or private key. */
|
|
5
|
+
export declare function blindsOwnerTransport(options: {
|
|
6
|
+
operationId: string;
|
|
7
|
+
input: Record<string, unknown>;
|
|
8
|
+
routing: string;
|
|
9
|
+
url: string;
|
|
10
|
+
credential: () => Promise<string | undefined>;
|
|
11
|
+
fetch: typeof fetch;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
}): Promise<Response>;
|
|
14
|
+
export declare function blindsModule(client: GenesisClient): {
|
|
15
|
+
credentials: {
|
|
16
|
+
/** Variable names only; values never leave Blinds. */
|
|
17
|
+
list: (init?: {
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
}) => Promise<{
|
|
20
|
+
credentials: string[];
|
|
21
|
+
}>;
|
|
22
|
+
/** Connect a static credential. The value is KMS-encrypted and never returned. */
|
|
23
|
+
store: (body: OperationInput<"blinds_storeCredential">["body"], init?: {
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
idempotencyKey?: string;
|
|
26
|
+
}) => Promise<{
|
|
27
|
+
variable_name: string;
|
|
28
|
+
}>;
|
|
29
|
+
revoke: (variable: string, init?: {
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
idempotencyKey?: string;
|
|
32
|
+
}) => Promise<unknown>;
|
|
33
|
+
};
|
|
34
|
+
oauth: {
|
|
35
|
+
connections: (init?: {
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
}) => Promise<{
|
|
38
|
+
connections: import("./index.js").components["schemas"]["Blinds.OAuthConnection"][];
|
|
39
|
+
total: number;
|
|
40
|
+
}>;
|
|
41
|
+
};
|
|
42
|
+
consent: {
|
|
43
|
+
pending: (init?: {
|
|
44
|
+
signal?: AbortSignal;
|
|
45
|
+
}) => Promise<{
|
|
46
|
+
requests: import("./index.js").components["schemas"]["Blinds.ConsentPending"][];
|
|
47
|
+
}>;
|
|
48
|
+
records: (init?: {
|
|
49
|
+
signal?: AbortSignal;
|
|
50
|
+
}) => Promise<{
|
|
51
|
+
records: import("./index.js").components["schemas"]["Blinds.ConsentRecord"][];
|
|
52
|
+
}>;
|
|
53
|
+
approve: (consent_id: string, body: OperationInput<"blinds_approveConsent">["body"], init?: {
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
idempotencyKey?: string;
|
|
56
|
+
}) => Promise<unknown>;
|
|
57
|
+
deny: (consent_id: string, init?: {
|
|
58
|
+
signal?: AbortSignal;
|
|
59
|
+
idempotencyKey?: string;
|
|
60
|
+
}) => Promise<unknown>;
|
|
61
|
+
revoke: (consent_id: string, init?: {
|
|
62
|
+
signal?: AbortSignal;
|
|
63
|
+
idempotencyKey?: string;
|
|
64
|
+
}) => Promise<unknown>;
|
|
65
|
+
};
|
|
66
|
+
delegates: {
|
|
67
|
+
list: (init?: {
|
|
68
|
+
signal?: AbortSignal;
|
|
69
|
+
}) => Promise<{
|
|
70
|
+
delegates: import("./index.js").components["schemas"]["Blinds.Delegate"][];
|
|
71
|
+
}>;
|
|
72
|
+
create: (body: OperationInput<"blinds_createDelegate">["body"], init?: {
|
|
73
|
+
signal?: AbortSignal;
|
|
74
|
+
idempotencyKey?: string;
|
|
75
|
+
}) => Promise<{
|
|
76
|
+
delegate_id: string;
|
|
77
|
+
parent_id?: string | null;
|
|
78
|
+
name: string;
|
|
79
|
+
issuer_did: string;
|
|
80
|
+
delegated_variables: string[];
|
|
81
|
+
max_depth?: number;
|
|
82
|
+
current_depth?: number;
|
|
83
|
+
ttl_seconds?: number;
|
|
84
|
+
created_at?: string;
|
|
85
|
+
expires_at: string;
|
|
86
|
+
}>;
|
|
87
|
+
revoke: (delegate_id: string, init?: {
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
idempotencyKey?: string;
|
|
90
|
+
}) => Promise<unknown>;
|
|
91
|
+
};
|
|
92
|
+
activity: (init?: {
|
|
93
|
+
signal?: AbortSignal;
|
|
94
|
+
}) => Promise<{
|
|
95
|
+
events: import("./index.js").components["schemas"]["Blinds.ActivityEvent"][];
|
|
96
|
+
}>;
|
|
97
|
+
ownerEnrollment: {
|
|
98
|
+
reserve: (body: OperationInput<"blinds_ownerReserve">["body"], init?: {
|
|
99
|
+
signal?: AbortSignal;
|
|
100
|
+
}) => Promise<{
|
|
101
|
+
schemaVersion: 1;
|
|
102
|
+
requestId: string;
|
|
103
|
+
edReservationId: string;
|
|
104
|
+
operationId: string;
|
|
105
|
+
publicKey: string;
|
|
106
|
+
state: "key_ready" | "attached";
|
|
107
|
+
expiresAtMs: number;
|
|
108
|
+
originalOrganizationGeneration: number;
|
|
109
|
+
}>;
|
|
110
|
+
sign: (body: OperationInput<"blinds_ownerSign">["body"], init?: {
|
|
111
|
+
signal?: AbortSignal;
|
|
112
|
+
}) => Promise<{
|
|
113
|
+
schemaVersion: 1;
|
|
114
|
+
requestId: string;
|
|
115
|
+
edReservationId: string;
|
|
116
|
+
enrollmentIntentId: string;
|
|
117
|
+
operationId: string;
|
|
118
|
+
signingPayloadSha256: string;
|
|
119
|
+
signatureMultibase: string;
|
|
120
|
+
}>;
|
|
121
|
+
attach: (body: OperationInput<"blinds_ownerAttach">["body"], init?: {
|
|
122
|
+
signal?: AbortSignal;
|
|
123
|
+
}) => Promise<{
|
|
124
|
+
schemaVersion: 1;
|
|
125
|
+
requestId: string;
|
|
126
|
+
edReservationId: string;
|
|
127
|
+
enrollmentIntentId: string;
|
|
128
|
+
state: "attached";
|
|
129
|
+
creation: {
|
|
130
|
+
intent_id: string;
|
|
131
|
+
operation_id: string;
|
|
132
|
+
creation_receipt_id: string;
|
|
133
|
+
agent_id: string;
|
|
134
|
+
canonical_did: string;
|
|
135
|
+
registered_public_key: string;
|
|
136
|
+
owner: {
|
|
137
|
+
issuer: "https://auth.life.one";
|
|
138
|
+
original_owner: string;
|
|
139
|
+
organization_generation: number;
|
|
140
|
+
scope: {
|
|
141
|
+
platform_id: "blinds";
|
|
142
|
+
organization_id: string;
|
|
143
|
+
workspace_id: string | null;
|
|
144
|
+
project_id: string | null;
|
|
145
|
+
environment_id: "sandbox" | "live";
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
}>;
|
|
150
|
+
ensureP256: (body: OperationInput<"blinds_ownerP256Ensure">["body"], init?: {
|
|
151
|
+
signal?: AbortSignal;
|
|
152
|
+
}) => Promise<{
|
|
153
|
+
schemaVersion: 1;
|
|
154
|
+
requestId: string;
|
|
155
|
+
edReservationId: string;
|
|
156
|
+
enrollmentIntentId: string;
|
|
157
|
+
state: "ready";
|
|
158
|
+
dpopPublicJwk: {
|
|
159
|
+
kty: "EC";
|
|
160
|
+
crv: "P-256";
|
|
161
|
+
x: string;
|
|
162
|
+
y: string;
|
|
163
|
+
};
|
|
164
|
+
senderJkt: string;
|
|
165
|
+
}>;
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
/** Blinds admits a mutation only with one UUID Idempotency-Key, the logical operation ID it
|
|
169
|
+
* records a receipt under. Take the caller's (input.idempotency_key or the header) so a retry
|
|
170
|
+
* after an uncertain outcome is recognised, else mint a new one. Never retried here. */
|
|
171
|
+
export declare function blindsOperationKey(operationId: string, input: Record<string, unknown>, headers: Record<string, string>): string;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { GenesisError } from './errors.js';
|
|
2
|
+
const operations = ['blinds_ownerReserve', 'blinds_ownerSign', 'blinds_ownerAttach', 'blinds_ownerP256Ensure'];
|
|
3
|
+
export const isBlindsOwnerOperation = (id) => operations.includes(id);
|
|
4
|
+
const uuid = (v) => typeof v === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(v);
|
|
5
|
+
/** One original-human operation; all public metadata, no arbitrary signing payload or private key. */
|
|
6
|
+
export async function blindsOwnerTransport(options) {
|
|
7
|
+
const { operationId, input, signal } = options;
|
|
8
|
+
const error = (status, type) => new GenesisError({ status, type, operationId,
|
|
9
|
+
message: 'Blinds owner enrollment was not confirmed. Preserve the original operation and locators; do not replay an unknown outcome automatically.' });
|
|
10
|
+
if (options.routing !== 'gateway')
|
|
11
|
+
throw error(0, 'invalid_request');
|
|
12
|
+
const body = input.body;
|
|
13
|
+
if (!body || typeof body !== 'object' || Array.isArray(body) || body.schemaVersion !== 1 || !uuid(body.requestId))
|
|
14
|
+
throw error(0, 'invalid_request');
|
|
15
|
+
const serialized = JSON.stringify(body);
|
|
16
|
+
if (new TextEncoder().encode(serialized).byteLength > 2048)
|
|
17
|
+
throw error(0, 'invalid_request');
|
|
18
|
+
const controller = new AbortController(), cancel = () => controller.abort(signal?.reason);
|
|
19
|
+
if (signal?.aborted)
|
|
20
|
+
cancel();
|
|
21
|
+
else
|
|
22
|
+
signal?.addEventListener('abort', cancel, { once: true });
|
|
23
|
+
const timer = setTimeout(() => controller.abort(), 12_000);
|
|
24
|
+
let abort = () => { };
|
|
25
|
+
const bounded = async (promise) => {
|
|
26
|
+
controller.signal.throwIfAborted();
|
|
27
|
+
try {
|
|
28
|
+
return await Promise.race([promise, new Promise((_, reject) => { abort = () => reject(error(0, 'transport_error')); controller.signal.addEventListener('abort', abort, { once: true }); })]);
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
controller.signal.removeEventListener('abort', abort);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
try {
|
|
35
|
+
const credential = await bounded(options.credential());
|
|
36
|
+
controller.signal.throwIfAborted();
|
|
37
|
+
if (!credential)
|
|
38
|
+
throw error(401, 'unauthenticated');
|
|
39
|
+
const response = await bounded(options.fetch(options.url, { method: 'POST', body: serialized,
|
|
40
|
+
headers: { authorization: `Bearer ${credential}`, 'content-type': 'application/json', accept: 'application/json', 'x-l1fe-request-id': body.requestId },
|
|
41
|
+
redirect: 'error', cache: 'no-store', signal: controller.signal }).then(response => { if (controller.signal.aborted) {
|
|
42
|
+
void response.body?.cancel().catch(() => { });
|
|
43
|
+
throw error(0, 'transport_error');
|
|
44
|
+
} return response; }));
|
|
45
|
+
if (response.status !== 200) {
|
|
46
|
+
void response.body?.cancel().catch(() => { });
|
|
47
|
+
throw error(response.status, 'unconfirmed_operation');
|
|
48
|
+
}
|
|
49
|
+
if (!response.body || !/^application\/json(?:;|$)/i.test(response.headers.get('content-type') ?? ''))
|
|
50
|
+
throw error(0, 'invalid_response');
|
|
51
|
+
const reader = response.body.getReader(), chunks = [];
|
|
52
|
+
let length = 0;
|
|
53
|
+
const stop = () => { void reader.cancel().catch(() => { }); };
|
|
54
|
+
controller.signal.addEventListener('abort', stop, { once: true });
|
|
55
|
+
try {
|
|
56
|
+
for (;;) {
|
|
57
|
+
const r = await bounded(reader.read());
|
|
58
|
+
if (r.done)
|
|
59
|
+
break;
|
|
60
|
+
length += r.value.length;
|
|
61
|
+
if (length > 16384)
|
|
62
|
+
throw error(0, 'invalid_response');
|
|
63
|
+
chunks.push(r.value);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
controller.signal.removeEventListener('abort', stop);
|
|
68
|
+
stop();
|
|
69
|
+
try {
|
|
70
|
+
reader.releaseLock();
|
|
71
|
+
}
|
|
72
|
+
catch { /* pending cancelled read */ }
|
|
73
|
+
}
|
|
74
|
+
const data = new Uint8Array(length);
|
|
75
|
+
let offset = 0;
|
|
76
|
+
for (const chunk of chunks) {
|
|
77
|
+
data.set(chunk, offset);
|
|
78
|
+
offset += chunk.length;
|
|
79
|
+
}
|
|
80
|
+
let value;
|
|
81
|
+
try {
|
|
82
|
+
value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(data));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
throw error(0, 'invalid_response');
|
|
86
|
+
}
|
|
87
|
+
if (!value || value.schemaVersion !== 1 || value.requestId !== body.requestId || !uuid(value.edReservationId)
|
|
88
|
+
|| operationId === 'blinds_ownerReserve' && value.operationId !== body.operationId
|
|
89
|
+
|| operationId !== 'blinds_ownerReserve' && (value.edReservationId !== body.edReservationId || value.enrollmentIntentId !== body.enrollmentIntentId))
|
|
90
|
+
throw error(0, 'invalid_response');
|
|
91
|
+
return Response.json(value, { headers: { 'cache-control': 'no-store' } });
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
if (e instanceof GenesisError)
|
|
95
|
+
throw e;
|
|
96
|
+
throw error(0, 'transport_error');
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
controller.abort();
|
|
101
|
+
signal?.removeEventListener('abort', cancel);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export function blindsModule(client) {
|
|
105
|
+
const write = (id, input, init = {}) => client.request(id, { ...input, ...(init.idempotencyKey ? { idempotency_key: init.idempotencyKey } : {}) }, { signal: init.signal });
|
|
106
|
+
const read = (id, init = {}) => client.request(id, {}, init);
|
|
107
|
+
return {
|
|
108
|
+
credentials: {
|
|
109
|
+
/** Variable names only; values never leave Blinds. */
|
|
110
|
+
list: (init) => read('blinds_listCredentials', init),
|
|
111
|
+
/** Connect a static credential. The value is KMS-encrypted and never returned. */
|
|
112
|
+
store: (body, init) => write('blinds_storeCredential', { body }, init),
|
|
113
|
+
revoke: (variable, init) => write('blinds_deleteCredential', { variable }, init),
|
|
114
|
+
},
|
|
115
|
+
oauth: { connections: (init) => read('blinds_listOAuthConnections', init) },
|
|
116
|
+
consent: {
|
|
117
|
+
pending: (init) => read('blinds_listPendingConsent', init),
|
|
118
|
+
records: (init) => read('blinds_listConsentRecords', init),
|
|
119
|
+
approve: (consent_id, body, init) => write('blinds_approveConsent', { consent_id, body }, init),
|
|
120
|
+
deny: (consent_id, init) => write('blinds_denyConsent', { consent_id }, init),
|
|
121
|
+
revoke: (consent_id, init) => write('blinds_revokeConsent', { consent_id }, init),
|
|
122
|
+
},
|
|
123
|
+
delegates: {
|
|
124
|
+
list: (init) => read('blinds_listDelegates', init),
|
|
125
|
+
create: (body, init) => write('blinds_createDelegate', { body }, init),
|
|
126
|
+
revoke: (delegate_id, init) => write('blinds_revokeDelegate', { delegate_id }, init),
|
|
127
|
+
},
|
|
128
|
+
activity: (init) => read('blinds_listActivity', init),
|
|
129
|
+
ownerEnrollment: {
|
|
130
|
+
reserve: (body, init = {}) => client.request('blinds_ownerReserve', { body }, init),
|
|
131
|
+
sign: (body, init = {}) => client.request('blinds_ownerSign', { body }, init),
|
|
132
|
+
attach: (body, init = {}) => client.request('blinds_ownerAttach', { body }, init),
|
|
133
|
+
ensureP256: (body, init = {}) => client.request('blinds_ownerP256Ensure', { body }, init),
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const blindsKey = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
138
|
+
/** Blinds admits a mutation only with one UUID Idempotency-Key, the logical operation ID it
|
|
139
|
+
* records a receipt under. Take the caller's (input.idempotency_key or the header) so a retry
|
|
140
|
+
* after an uncertain outcome is recognised, else mint a new one. Never retried here. */
|
|
141
|
+
export function blindsOperationKey(operationId, input, headers) {
|
|
142
|
+
const names = Object.keys(headers).filter(name => name.toLowerCase() === 'idempotency-key');
|
|
143
|
+
const given = [...names.map(name => headers[name]), ...(input.idempotency_key === undefined ? [] : [input.idempotency_key])];
|
|
144
|
+
if (new Set(given).size > 1 || given.some(v => typeof v !== 'string' || !blindsKey.test(v))) {
|
|
145
|
+
throw new GenesisError({ status: 0, type: 'invalid_request', message: 'A Blinds mutation takes one UUID idempotency key.', operationId });
|
|
146
|
+
}
|
|
147
|
+
for (const name of names)
|
|
148
|
+
delete headers[name];
|
|
149
|
+
return headers['idempotency-key'] = given[0] ?? crypto.randomUUID();
|
|
150
|
+
}
|