@lifesi/genesis 0.1.2 → 0.1.4
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/dist/client.d.ts +1497 -244
- package/dist/client.js +12 -2
- package/dist/fleets.d.ts +56 -0
- package/dist/fleets.js +54 -0
- package/dist/generated/operations.d.ts +1497 -244
- package/dist/generated/operations.js +1809 -325
- package/dist/generated/schema.d.ts +3184 -592
- package/dist/genesis.d.ts +158 -0
- package/dist/genesis.js +13 -0
- package/dist/genesis.openapi.json +6218 -2791
- package/dist/henry.d.ts +7 -0
- package/dist/henry.js +23 -0
- package/dist/hives-functions.d.ts +1 -1
- package/dist/hives-functions.js +3 -1
- package/dist/hives-marketplace.d.ts +128 -0
- package/dist/hives-marketplace.js +187 -0
- package/dist/hives-node.js +1 -1
- package/dist/hives-resources-transport.js +1 -1
- package/dist/hives-volumes.d.ts +64 -0
- package/dist/hives-volumes.js +117 -0
- package/dist/index.d.ts +2 -0
- package/package.json +1 -1
package/dist/henry.d.ts
CHANGED
|
@@ -14,6 +14,13 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
14
14
|
id: string;
|
|
15
15
|
}[];
|
|
16
16
|
}>;
|
|
17
|
+
receipts: {
|
|
18
|
+
/** Current standalone Henry public signer. Pin through trusted deployment custody before verifying a receipt. */
|
|
19
|
+
verificationKey: () => Promise<{
|
|
20
|
+
keyId: string;
|
|
21
|
+
publicKeyBase64: string;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
17
24
|
runs: {
|
|
18
25
|
list: (page_token?: string) => Promise<{
|
|
19
26
|
runs: import("./index.js").components["schemas"]["Henry.Run"][];
|
package/dist/henry.js
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
|
+
function receiptVerificationKey(value) {
|
|
2
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
3
|
+
throw new Error('Henry returned an invalid receipt verification key.');
|
|
4
|
+
const key = value;
|
|
5
|
+
if (Object.keys(key).length !== 2 || !Object.hasOwn(key, 'keyId') || !Object.hasOwn(key, 'publicKeyBase64')
|
|
6
|
+
|| typeof key.keyId !== 'string' || !key.keyId.trim() || key.keyId.length > 256 || /[\x00-\x1f\x7f]/.test(key.keyId)
|
|
7
|
+
|| typeof key.publicKeyBase64 !== 'string' || key.publicKeyBase64.length !== 44
|
|
8
|
+
|| !/^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/.test(key.publicKeyBase64)) {
|
|
9
|
+
throw new Error('Henry returned an invalid receipt verification key.');
|
|
10
|
+
}
|
|
11
|
+
return { keyId: key.keyId, publicKeyBase64: key.publicKeyBase64 };
|
|
12
|
+
}
|
|
1
13
|
/** Henry always derives its organization from the gateway's verified caller. */
|
|
2
14
|
export function henryModule(client) {
|
|
3
15
|
return {
|
|
4
16
|
config: () => client.request('henry_getConfig'),
|
|
5
17
|
credential: (api_key) => client.request('henry_putCredential', { body: { api_key } }),
|
|
18
|
+
receipts: {
|
|
19
|
+
/** Current standalone Henry public signer. Pin through trusted deployment custody before verifying a receipt. */
|
|
20
|
+
verificationKey: async () => {
|
|
21
|
+
try {
|
|
22
|
+
return receiptVerificationKey(await client.request('henry_getReceiptVerificationKey'));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new Error('Henry returned an invalid receipt verification key.');
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
},
|
|
6
29
|
runs: {
|
|
7
30
|
list: (page_token) => client.request('henry_listRuns', page_token ? { page_token } : {}),
|
|
8
31
|
create: (body) => client.request('henry_createRun', { body: { ...body, run_id: body.run_id ?? globalThis.crypto.randomUUID() } }),
|
|
@@ -12,4 +12,4 @@ export declare function validateHivesInvocation(input: unknown): asserts input i
|
|
|
12
12
|
/** Safe display/transport headers; customer headers never establish identity. */
|
|
13
13
|
export declare function hivesFunctionResponseHeaders(headers: Headers): Headers;
|
|
14
14
|
/** Metadata contracts cannot accidentally expose an upstream env/ciphertext field. */
|
|
15
|
-
export declare function hivesFunctionMetadata(input: unknown, project: unknown): Record<string, unknown>;
|
|
15
|
+
export declare function hivesFunctionMetadata(input: unknown, project: unknown, expectedId?: unknown): Record<string, unknown>;
|
package/dist/hives-functions.js
CHANGED
|
@@ -84,11 +84,13 @@ export function hivesFunctionResponseHeaders(headers) {
|
|
|
84
84
|
return safe;
|
|
85
85
|
}
|
|
86
86
|
/** Metadata contracts cannot accidentally expose an upstream env/ciphertext field. */
|
|
87
|
-
export function hivesFunctionMetadata(input, project) {
|
|
87
|
+
export function hivesFunctionMetadata(input, project, expectedId) {
|
|
88
88
|
if (!input || typeof input !== 'object' || input.project_id !== project) {
|
|
89
89
|
throw new Error('Hives returned invalid or wrong-project function metadata.');
|
|
90
90
|
}
|
|
91
91
|
const row = input;
|
|
92
|
+
if (expectedId !== undefined && row.id !== expectedId)
|
|
93
|
+
throw new Error('Hives returned mismatched function metadata.');
|
|
92
94
|
return Object.fromEntries(['id', 'tenant_id', 'project_id', 'name', 'description', 'handler', 'route', 'memory_mb', 'timeout_ms',
|
|
93
95
|
'status', 'invocations', 'avg_duration_ms', 'created_at', 'updated_at'].map((key) => [key, row[key]]));
|
|
94
96
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { GenesisClient } from './client.js';
|
|
2
|
+
import { type HivesResourceOptions } from './hives-resources-transport.js';
|
|
3
|
+
export interface HivesMarketplacePackage {
|
|
4
|
+
id: string;
|
|
5
|
+
slug: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
author_name: string;
|
|
9
|
+
visibility: 'public' | 'private' | 'unlisted';
|
|
10
|
+
categories: string[];
|
|
11
|
+
keywords: string[];
|
|
12
|
+
license: string;
|
|
13
|
+
installs: number;
|
|
14
|
+
stars: number;
|
|
15
|
+
verified: boolean;
|
|
16
|
+
featured: boolean;
|
|
17
|
+
free: boolean;
|
|
18
|
+
latest_version: string;
|
|
19
|
+
version_count: number;
|
|
20
|
+
owned: boolean;
|
|
21
|
+
created_at: string;
|
|
22
|
+
updated_at: string;
|
|
23
|
+
}
|
|
24
|
+
export interface HivesMarketplaceVersion {
|
|
25
|
+
id: string;
|
|
26
|
+
package_id: string;
|
|
27
|
+
version: string;
|
|
28
|
+
module_hash: string;
|
|
29
|
+
size_bytes: number;
|
|
30
|
+
readme: string;
|
|
31
|
+
changelog: string;
|
|
32
|
+
required_env: string[];
|
|
33
|
+
downloads: number;
|
|
34
|
+
deprecated: boolean;
|
|
35
|
+
published_at: string;
|
|
36
|
+
}
|
|
37
|
+
export interface HivesMarketplaceInstallation {
|
|
38
|
+
id: string;
|
|
39
|
+
package_id: string;
|
|
40
|
+
slug: string;
|
|
41
|
+
name: string;
|
|
42
|
+
project_id: string;
|
|
43
|
+
version: string | null;
|
|
44
|
+
deployment_id: string | null;
|
|
45
|
+
deployment_status: string | null;
|
|
46
|
+
pending_version: string | null;
|
|
47
|
+
pending_deployment_id: string | null;
|
|
48
|
+
pending_deployment_status: string | null;
|
|
49
|
+
operation: 'install' | 'update' | 'cleanup' | 'uninstall' | null;
|
|
50
|
+
status: 'active' | 'updating' | 'failed' | 'uninstalled';
|
|
51
|
+
latest_version: string | null;
|
|
52
|
+
installed_at: string;
|
|
53
|
+
}
|
|
54
|
+
export interface HivesMarketplaceCategory {
|
|
55
|
+
id: string;
|
|
56
|
+
slug: string;
|
|
57
|
+
name: string;
|
|
58
|
+
description: string | null;
|
|
59
|
+
icon_url: string | null;
|
|
60
|
+
package_count: number;
|
|
61
|
+
sort_order: number;
|
|
62
|
+
}
|
|
63
|
+
export interface HivesMarketplacePage<T> {
|
|
64
|
+
data: T[];
|
|
65
|
+
pagination: {
|
|
66
|
+
page: number;
|
|
67
|
+
page_size: number;
|
|
68
|
+
total: number;
|
|
69
|
+
total_pages: number;
|
|
70
|
+
has_next: boolean;
|
|
71
|
+
has_prev: boolean;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export interface HivesMarketplacePublish {
|
|
75
|
+
slug: string;
|
|
76
|
+
name: string;
|
|
77
|
+
module_hash: string;
|
|
78
|
+
version: string;
|
|
79
|
+
description?: string;
|
|
80
|
+
visibility?: HivesMarketplacePackage['visibility'];
|
|
81
|
+
categories?: string[];
|
|
82
|
+
keywords?: string[];
|
|
83
|
+
readme?: string;
|
|
84
|
+
changelog?: string;
|
|
85
|
+
required_env?: string[];
|
|
86
|
+
license?: string;
|
|
87
|
+
}
|
|
88
|
+
export interface HivesMarketplaceInstall {
|
|
89
|
+
version?: string | null;
|
|
90
|
+
env_overrides?: Record<string, string>;
|
|
91
|
+
}
|
|
92
|
+
export interface HivesMarketplaceSearch {
|
|
93
|
+
q?: string | null;
|
|
94
|
+
category?: string | null;
|
|
95
|
+
free_only?: boolean;
|
|
96
|
+
verified_only?: boolean;
|
|
97
|
+
sort?: 'name' | 'installs' | 'stars' | 'created' | 'updated';
|
|
98
|
+
order?: 'asc' | 'desc';
|
|
99
|
+
page?: number;
|
|
100
|
+
page_size?: number;
|
|
101
|
+
}
|
|
102
|
+
export type HivesMarketplaceDetail = HivesMarketplacePackage & {
|
|
103
|
+
versions: HivesMarketplaceVersion[];
|
|
104
|
+
};
|
|
105
|
+
/** Native Marketplace reuses verified project ownership and persisted deployment lifecycle.
|
|
106
|
+
* Writes are sent once. Read/reconcile saved state after an uncertain acknowledgement. */
|
|
107
|
+
export declare function hivesMarketplace(client: GenesisClient): {
|
|
108
|
+
list(project: string, query?: HivesMarketplaceSearch, options?: HivesResourceOptions): Promise<HivesMarketplacePage<HivesMarketplacePackage>>;
|
|
109
|
+
get(project: string, packageSlug: string, query?: {
|
|
110
|
+
version?: string | null;
|
|
111
|
+
}, options?: HivesResourceOptions): Promise<HivesMarketplaceDetail>;
|
|
112
|
+
versions(project: string, packageSlug: string, query?: {
|
|
113
|
+
page?: number;
|
|
114
|
+
page_size?: number;
|
|
115
|
+
}, options?: HivesResourceOptions): Promise<HivesMarketplacePage<HivesMarketplaceVersion>>;
|
|
116
|
+
featured(project: string, options?: HivesResourceOptions): Promise<HivesMarketplacePage<HivesMarketplacePackage>>;
|
|
117
|
+
categories(project: string, options?: HivesResourceOptions): Promise<HivesMarketplaceCategory[]>;
|
|
118
|
+
publish(project: string, input: HivesMarketplacePublish, options?: HivesResourceOptions): Promise<HivesMarketplaceDetail>;
|
|
119
|
+
install(project: string, packageSlug: string, input?: HivesMarketplaceInstall, options?: HivesResourceOptions): Promise<HivesMarketplaceInstallation>;
|
|
120
|
+
update(project: string, packageSlug: string, input?: HivesMarketplaceInstall, options?: HivesResourceOptions): Promise<HivesMarketplaceInstallation>;
|
|
121
|
+
installed(project: string, query?: {
|
|
122
|
+
page?: number;
|
|
123
|
+
page_size?: number;
|
|
124
|
+
}, options?: HivesResourceOptions): Promise<HivesMarketplacePage<HivesMarketplaceInstallation>>;
|
|
125
|
+
getInstallation(project: string, id: string, options?: HivesResourceOptions): Promise<HivesMarketplaceInstallation>;
|
|
126
|
+
reconcile(project: string, id: string, options?: HivesResourceOptions): Promise<HivesMarketplaceInstallation>;
|
|
127
|
+
uninstall(project: string, id: string, options?: HivesResourceOptions): Promise<HivesMarketplaceInstallation>;
|
|
128
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { hivesResourceCall, hivesResourceId, resourceError } from './hives-resources-transport.js';
|
|
2
|
+
function invalid() { throw resourceError(0); }
|
|
3
|
+
function record(value) { if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
4
|
+
invalid(); return value; }
|
|
5
|
+
function keys(value, allowed) { if (Object.keys(value).some(key => !allowed.includes(key)))
|
|
6
|
+
invalid(); }
|
|
7
|
+
function text(value, max) { if (typeof value !== 'string' || new TextEncoder().encode(value).length > max)
|
|
8
|
+
invalid(); return value; }
|
|
9
|
+
function uuid(value) { const result = text(value, 36); if (!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(result))
|
|
10
|
+
invalid(); return result.toLowerCase(); }
|
|
11
|
+
function slug(value) { const result = text(value, 64); if (!/^[a-z][a-z0-9-]*[a-z0-9]$/.test(result))
|
|
12
|
+
invalid(); return result; }
|
|
13
|
+
function semver(value, maxCore = 18446744073709551615n) {
|
|
14
|
+
const result = text(value, 64);
|
|
15
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(result);
|
|
16
|
+
if (!match || match.slice(1, 4).some(part => BigInt(part) > maxCore)
|
|
17
|
+
|| match[4]?.split('.').some(part => /^\d+$/.test(part) && part.length > 1 && part.startsWith('0')))
|
|
18
|
+
invalid();
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
function count(value, min = 0, max = Number.MAX_SAFE_INTEGER) { if (!Number.isSafeInteger(value) || value < min || value > max)
|
|
22
|
+
invalid(); return value; }
|
|
23
|
+
function bool(value) { if (typeof value !== 'boolean')
|
|
24
|
+
invalid(); return value; }
|
|
25
|
+
function strings(value, limit, max) { if (!Array.isArray(value) || value.length > limit)
|
|
26
|
+
invalid(); return value.map(item => text(item, max)); }
|
|
27
|
+
function date(value) { const result = text(value, 64); if (!Number.isFinite(Date.parse(result)))
|
|
28
|
+
invalid(); return result; }
|
|
29
|
+
function nullable(value, parse) { return value === null ? null : parse(value); }
|
|
30
|
+
function deployment(value) { const id = text(value, 64); if (!/^dpl_[A-Za-z0-9_-]+$/.test(id))
|
|
31
|
+
invalid(); return id; }
|
|
32
|
+
function packageRow(value) {
|
|
33
|
+
const r = record(value);
|
|
34
|
+
if (!['public', 'private', 'unlisted'].includes(String(r.visibility)) || r.visibility === 'private' && r.owned !== true)
|
|
35
|
+
invalid();
|
|
36
|
+
return { id: uuid(r.id), slug: slug(r.slug), name: text(r.name, 128), description: text(r.description, 500), author_name: text(r.author_name, 1000),
|
|
37
|
+
visibility: r.visibility, categories: strings(r.categories, 5, 64), keywords: strings(r.keywords, 20, 64), license: text(r.license, 64),
|
|
38
|
+
installs: count(r.installs), stars: count(r.stars), verified: bool(r.verified), featured: bool(r.featured), free: bool(r.free),
|
|
39
|
+
latest_version: semver(r.latest_version), version_count: count(r.version_count, 1), owned: bool(r.owned), created_at: date(r.created_at), updated_at: date(r.updated_at) };
|
|
40
|
+
}
|
|
41
|
+
function versionRow(value, expectedPackage) {
|
|
42
|
+
const r = record(value);
|
|
43
|
+
const packageId = uuid(r.package_id);
|
|
44
|
+
const hash = text(r.module_hash, 64);
|
|
45
|
+
if (expectedPackage && packageId !== expectedPackage || !/^[a-f0-9]{64}$/.test(hash))
|
|
46
|
+
invalid();
|
|
47
|
+
return { id: uuid(r.id), package_id: packageId, version: semver(r.version), module_hash: hash, size_bytes: count(r.size_bytes, 1, 10 * 1024 * 1024),
|
|
48
|
+
readme: text(r.readme, 50_000), changelog: text(r.changelog, 2000), required_env: strings(r.required_env, 50, 128), downloads: count(r.downloads), deprecated: bool(r.deprecated), published_at: date(r.published_at) };
|
|
49
|
+
}
|
|
50
|
+
function installationRow(value, project, expectedId) {
|
|
51
|
+
const r = record(value);
|
|
52
|
+
if (r.project_id !== project || expectedId && uuid(r.id) !== uuid(expectedId) || !['active', 'updating', 'failed', 'uninstalled'].includes(String(r.status))
|
|
53
|
+
|| !(r.operation === null || ['install', 'update', 'cleanup', 'uninstall'].includes(String(r.operation))))
|
|
54
|
+
invalid();
|
|
55
|
+
const result = { id: uuid(r.id), package_id: uuid(r.package_id), slug: slug(r.slug), name: text(r.name, 128), project_id: project,
|
|
56
|
+
version: nullable(r.version, semver), deployment_id: nullable(r.deployment_id, deployment), deployment_status: nullable(r.deployment_status, v => text(v, 32)),
|
|
57
|
+
pending_version: nullable(r.pending_version, semver), pending_deployment_id: nullable(r.pending_deployment_id, deployment), pending_deployment_status: nullable(r.pending_deployment_status, v => text(v, 32)),
|
|
58
|
+
operation: r.operation, status: r.status,
|
|
59
|
+
latest_version: nullable(r.latest_version, semver), installed_at: date(r.installed_at) };
|
|
60
|
+
if (result.status === 'uninstalled' && (result.operation || result.deployment_id || result.pending_deployment_id))
|
|
61
|
+
invalid();
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
function page(value, pageNumber, pageSize, parse) {
|
|
65
|
+
const r = record(value);
|
|
66
|
+
const p = record(r.pagination);
|
|
67
|
+
const total = count(p.total);
|
|
68
|
+
const pages = Math.ceil(total / pageSize);
|
|
69
|
+
if (p.page !== pageNumber || p.page_size !== pageSize || p.total_pages !== pages || p.has_next !== (pageNumber < pages) || p.has_prev !== (pageNumber > 1)
|
|
70
|
+
|| !Array.isArray(r.data) || r.data.length > pageSize)
|
|
71
|
+
invalid();
|
|
72
|
+
const data = r.data.map(parse);
|
|
73
|
+
if (new Set(data.map(row => row.id)).size !== data.length)
|
|
74
|
+
invalid();
|
|
75
|
+
return { data, pagination: { page: pageNumber, page_size: pageSize, total, total_pages: pages, has_next: pageNumber < pages, has_prev: pageNumber > 1 } };
|
|
76
|
+
}
|
|
77
|
+
function details(value, expectedSlug, exactVersion) {
|
|
78
|
+
const r = record(value);
|
|
79
|
+
const pkg = packageRow(r);
|
|
80
|
+
if (pkg.slug !== expectedSlug || !Array.isArray(r.versions) || r.versions.length > 5 || r.versions.length === 0)
|
|
81
|
+
invalid();
|
|
82
|
+
const versions = r.versions.map(row => versionRow(row, pkg.id));
|
|
83
|
+
if (new Set(versions.map(row => row.id)).size !== versions.length || exactVersion && versions.some(row => row.version !== exactVersion))
|
|
84
|
+
invalid();
|
|
85
|
+
return { ...pkg, versions };
|
|
86
|
+
}
|
|
87
|
+
function pagination(query, max) {
|
|
88
|
+
keys(record(query), ['page', 'page_size']);
|
|
89
|
+
return { page: count(query.page ?? 1, 1, 100_000), page_size: count(query.page_size ?? max, 1, max) };
|
|
90
|
+
}
|
|
91
|
+
function installInput(input) {
|
|
92
|
+
const r = record(input);
|
|
93
|
+
keys(r, ['version', 'env_overrides']);
|
|
94
|
+
const env = record(r.env_overrides ?? {});
|
|
95
|
+
if (Object.keys(env).length > 50)
|
|
96
|
+
invalid();
|
|
97
|
+
const entries = Object.entries(env).map(([key, value]) => [text(key, 128), text(value, 4096)]);
|
|
98
|
+
return { ...(r.version == null ? {} : { version: semver(r.version) }), env_overrides: Object.fromEntries(entries) };
|
|
99
|
+
}
|
|
100
|
+
function publishInput(input) {
|
|
101
|
+
const r = record(input);
|
|
102
|
+
keys(r, ['slug', 'name', 'module_hash', 'version', 'description', 'visibility', 'categories', 'keywords', 'readme', 'changelog', 'required_env', 'license']);
|
|
103
|
+
const name = text(r.name, 128);
|
|
104
|
+
const hash = text(r.module_hash, 64);
|
|
105
|
+
const visibility = r.visibility ?? 'public';
|
|
106
|
+
if (!name.trim() || !/^[a-f0-9]{64}$/.test(hash) || !['public', 'private', 'unlisted'].includes(String(visibility)))
|
|
107
|
+
invalid();
|
|
108
|
+
const required = strings(r.required_env ?? [], 50, 128);
|
|
109
|
+
if (new Set(required).size !== required.length || required.some(key => !/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)))
|
|
110
|
+
invalid();
|
|
111
|
+
return { slug: slug(r.slug), name, module_hash: hash, version: semver(r.version, 2147483647n), description: text(r.description ?? '', 500),
|
|
112
|
+
visibility: visibility, categories: strings(r.categories ?? [], 5, 64), keywords: strings(r.keywords ?? [], 20, 64),
|
|
113
|
+
readme: text(r.readme ?? '', 50_000), changelog: text(r.changelog ?? '', 2000), required_env: required, license: text(r.license ?? '', 64) };
|
|
114
|
+
}
|
|
115
|
+
/** Native Marketplace reuses verified project ownership and persisted deployment lifecycle.
|
|
116
|
+
* Writes are sent once. Read/reconcile saved state after an uncertain acknowledgement. */
|
|
117
|
+
export function hivesMarketplace(client) {
|
|
118
|
+
const projectInput = (project) => ({ project_id: hivesResourceId(project) });
|
|
119
|
+
const call = (operation, input, options) => hivesResourceCall(client, `hives_marketplace_${operation}`, input, options);
|
|
120
|
+
const mutate = async (operation, project, packageSlug, input, options) => {
|
|
121
|
+
const body = installInput(input);
|
|
122
|
+
const result = installationRow(await call(operation, { ...projectInput(project), slug: slug(packageSlug), body }, options), project);
|
|
123
|
+
if (result.slug !== packageSlug || result.status === 'uninstalled' || body.version && result.version !== body.version && result.pending_version !== body.version)
|
|
124
|
+
invalid();
|
|
125
|
+
return result;
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
async list(project, query = {}, options) {
|
|
129
|
+
keys(record(query), ['q', 'category', 'free_only', 'verified_only', 'sort', 'order', 'page', 'page_size']);
|
|
130
|
+
const p = { page: count(query.page ?? 1, 1, 100_000), page_size: count(query.page_size ?? 20, 1, 100) };
|
|
131
|
+
const sort = query.sort ?? 'installs';
|
|
132
|
+
const order = query.order ?? 'desc';
|
|
133
|
+
if (!['name', 'installs', 'stars', 'created', 'updated'].includes(sort) || !['asc', 'desc'].includes(order))
|
|
134
|
+
invalid();
|
|
135
|
+
const input = { ...projectInput(project), ...p, sort, order, free_only: bool(query.free_only ?? false), verified_only: bool(query.verified_only ?? false),
|
|
136
|
+
...(query.q == null ? {} : { q: text(query.q, 200) }), ...(query.category == null ? {} : { category: text(query.category, 64) }) };
|
|
137
|
+
return page(await call('list_packages', input, options), p.page, p.page_size, packageRow);
|
|
138
|
+
},
|
|
139
|
+
async get(project, packageSlug, query = {}, options) {
|
|
140
|
+
keys(record(query), ['version']);
|
|
141
|
+
const version = query.version == null ? undefined : semver(query.version);
|
|
142
|
+
return details(await call('get_package', { ...projectInput(project), slug: slug(packageSlug), ...(version === undefined ? {} : { version }) }, options), packageSlug, version);
|
|
143
|
+
},
|
|
144
|
+
async versions(project, packageSlug, query = {}, options) {
|
|
145
|
+
const p = pagination(query, 5);
|
|
146
|
+
const result = page(await call('list_versions', { ...projectInput(project), slug: slug(packageSlug), ...p }, options), p.page, p.page_size, row => versionRow(row));
|
|
147
|
+
if (new Set(result.data.map(row => row.package_id)).size > 1)
|
|
148
|
+
invalid();
|
|
149
|
+
return result;
|
|
150
|
+
},
|
|
151
|
+
async featured(project, options) { return page(await call('featured', projectInput(project), options), 1, 20, packageRow); },
|
|
152
|
+
async categories(project, options) {
|
|
153
|
+
const result = await call('categories', projectInput(project), options);
|
|
154
|
+
if (!Array.isArray(result) || result.length > 100)
|
|
155
|
+
invalid();
|
|
156
|
+
const data = result.map(value => {
|
|
157
|
+
const r = record(value);
|
|
158
|
+
return { id: uuid(r.id), slug: slug(r.slug), name: text(r.name, 128),
|
|
159
|
+
description: nullable(r.description, v => text(v, 1000)), icon_url: nullable(r.icon_url, v => text(v, 2048)), package_count: count(r.package_count), sort_order: count(r.sort_order, -2147483648, 2147483647) };
|
|
160
|
+
});
|
|
161
|
+
if (new Set(data.map(row => row.id)).size !== data.length)
|
|
162
|
+
invalid();
|
|
163
|
+
return data;
|
|
164
|
+
},
|
|
165
|
+
async publish(project, input, options) {
|
|
166
|
+
const body = publishInput(input);
|
|
167
|
+
const result = details(await call('publish', { ...projectInput(project), body }, options), body.slug);
|
|
168
|
+
if (!result.owned || !result.versions.some(v => v.version === body.version && v.module_hash === body.module_hash))
|
|
169
|
+
invalid();
|
|
170
|
+
return result;
|
|
171
|
+
},
|
|
172
|
+
async install(project, packageSlug, input = {}, options) { return mutate('install', project, packageSlug, input, options); },
|
|
173
|
+
async update(project, packageSlug, input = {}, options) { return mutate('update', project, packageSlug, input, options); },
|
|
174
|
+
async installed(project, query = {}, options) {
|
|
175
|
+
const p = pagination(query, 20);
|
|
176
|
+
return page(await call('installed', { ...projectInput(project), ...p }, options), p.page, p.page_size, row => installationRow(row, project));
|
|
177
|
+
},
|
|
178
|
+
async getInstallation(project, id, options) { return installationRow(await call('get_installation', { ...projectInput(project), installation_id: uuid(id) }, options), project, id); },
|
|
179
|
+
async reconcile(project, id, options) { return installationRow(await call('reconcile', { ...projectInput(project), installation_id: uuid(id) }, options), project, id); },
|
|
180
|
+
async uninstall(project, id, options) {
|
|
181
|
+
const result = installationRow(await call('uninstall', { ...projectInput(project), installation_id: uuid(id) }, options), project, id);
|
|
182
|
+
if (result.status !== 'uninstalled' || result.operation || result.deployment_id || result.pending_deployment_id)
|
|
183
|
+
invalid();
|
|
184
|
+
return result;
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
package/dist/hives-node.js
CHANGED
|
@@ -14,7 +14,7 @@ export async function closeHivesNodeTransport() {
|
|
|
14
14
|
export function hivesOperationBudget(id) {
|
|
15
15
|
if (['hives_list_buckets', 'hives_create_bucket', 'hives_get_bucket', 'hives_delete_bucket', 'hives_list_objects', 'hives_upload_object', 'hives_upload_object_by_key', 'hives_delete_object', 'hives_delete_object_by_key', 'hives_download_object_by_key', 'hives_get_cors_config', 'hives_set_cors_config', 'hives_generate_presigned_url', 'hives_reconcile'].includes(id))
|
|
16
16
|
return 100_000;
|
|
17
|
-
if (id === 'hives_cancel_deployment' || id === 'hives_delete_deployment')
|
|
17
|
+
if (id === 'hives_cancel_deployment' || id === 'hives_delete_deployment' || id === 'hives_stop_deployment')
|
|
18
18
|
return 330_000;
|
|
19
19
|
if (['hives_create_deployment', 'hives_upload_deployment', 'hives_invoke_deployment', 'hives_invoke_function', 'hives_invoke_function_async'].includes(id))
|
|
20
20
|
return 40_000;
|
|
@@ -14,7 +14,7 @@ export function resourceError(status, id) {
|
|
|
14
14
|
: status === 503 ? 'Hives outcome is unavailable. Read persisted state or reconcile before another mutation.'
|
|
15
15
|
: 'Hives resource request failed. Check the request and persisted state; no automatic retry was made.' });
|
|
16
16
|
}
|
|
17
|
-
export const isHivesResourceOperation = (id) => /^(?:hives_.*_native_queue|hives_(?:list_buckets|create_bucket|get_bucket|delete_bucket|list_objects|upload_object(?:_by_key)?|delete_object(?:_by_key)?|download_object_by_key|get_cors_config|set_cors_config|generate_presigned_url|reconcile|list_runtimes|get_runtime|select_runtime|list_project_runtimes))$/.test(id);
|
|
17
|
+
export const isHivesResourceOperation = (id) => /^(?:hives_marketplace_(?:categories|featured|installed|get_installation|uninstall|reconcile|list_packages|publish|get_package|install|update|list_versions)|hives_.*_native_queue|hives_(?:(?:list_volumes|create_volume|get_volume|delete_volume|mount_volume|unmount_volume)|list_buckets|create_bucket|get_bucket|delete_bucket|list_objects|upload_object(?:_by_key)?|delete_object(?:_by_key)?|download_object_by_key|get_cors_config|set_cors_config|generate_presigned_url|reconcile|list_runtimes|get_runtime|select_runtime|list_project_runtimes))$/.test(id);
|
|
18
18
|
export const isHivesObjectUpload = (id) => id === 'hives_upload_object_by_key' || id === 'hives_upload_object';
|
|
19
19
|
/** Shared-client hook proposal: snapshot only the two real raw Cells upload operations. */
|
|
20
20
|
export async function hivesObjectBody(value) {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { GenesisClient } from './client.js';
|
|
2
|
+
import { type HivesResourceOptions } from './hives-resources-transport.js';
|
|
3
|
+
declare const states: readonly ["creating", "available", "attaching", "attached", "detaching", "deleting", "failed"];
|
|
4
|
+
export interface HivesVolume {
|
|
5
|
+
id: string;
|
|
6
|
+
project_id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
size_gib: number;
|
|
9
|
+
backing_bytes: number;
|
|
10
|
+
capacity_bytes: number | null;
|
|
11
|
+
used_bytes: number | null;
|
|
12
|
+
storage_class: 'local';
|
|
13
|
+
access_mode: 'read_write_once';
|
|
14
|
+
state: typeof states[number];
|
|
15
|
+
operation_pending: boolean;
|
|
16
|
+
generation: number;
|
|
17
|
+
mount_path: string | null;
|
|
18
|
+
attached_to: string | null;
|
|
19
|
+
read_only: boolean | null;
|
|
20
|
+
created_at: string;
|
|
21
|
+
updated_at: string;
|
|
22
|
+
}
|
|
23
|
+
export type HivesVolumeCreate = {
|
|
24
|
+
name: string;
|
|
25
|
+
storage_class?: 'local';
|
|
26
|
+
access_mode?: 'read_write_once';
|
|
27
|
+
} & ({
|
|
28
|
+
size_mib: number;
|
|
29
|
+
size_gib?: never;
|
|
30
|
+
} | {
|
|
31
|
+
size_gib: 1;
|
|
32
|
+
size_mib?: never;
|
|
33
|
+
});
|
|
34
|
+
export interface HivesVolumeMount {
|
|
35
|
+
target_id: string;
|
|
36
|
+
mount_path: string;
|
|
37
|
+
read_only: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface HivesVolumePage {
|
|
40
|
+
volumes: HivesVolume[];
|
|
41
|
+
pagination: {
|
|
42
|
+
page: number;
|
|
43
|
+
per_page: number;
|
|
44
|
+
total: number;
|
|
45
|
+
total_pages: number;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Persisted project storage. A failed acknowledgement never triggers an automatic write retry. */
|
|
49
|
+
export declare function hivesVolumes(client: GenesisClient): {
|
|
50
|
+
list(project: string, query?: {
|
|
51
|
+
page?: number;
|
|
52
|
+
per_page?: number;
|
|
53
|
+
}, options?: HivesResourceOptions): Promise<HivesVolumePage>;
|
|
54
|
+
get(project: string, id: string, options?: HivesResourceOptions): Promise<HivesVolume>;
|
|
55
|
+
create(project: string, input: HivesVolumeCreate, options?: HivesResourceOptions): Promise<HivesVolume>;
|
|
56
|
+
mount(project: string, id: string, input: HivesVolumeMount, options?: HivesResourceOptions): Promise<HivesVolume>;
|
|
57
|
+
unmount(project: string, id: string, options?: HivesResourceOptions): Promise<HivesVolume>;
|
|
58
|
+
remove(project: string, id: string, options?: HivesResourceOptions): Promise<{
|
|
59
|
+
success: true;
|
|
60
|
+
id: string;
|
|
61
|
+
message: string;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
export {};
|
|
@@ -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
|
@@ -14,4 +14,6 @@ export { dialsModule, dialsEmergencyAddressFeedback, type DialsEmergencyAddressF
|
|
|
14
14
|
export { hivesObjectKey, type HivesBucket, type HivesObject, type HivesObjectAcknowledgement, type HivesObjectList, type HivesCorsRule, type HivesCreateBucket, type HivesPresign, type HivesPresignedUrl } from './hives-cells.js';
|
|
15
15
|
export { hivesQueueBody, type HivesQueue, type HivesQueueConfig, type HivesQueueCreate, type HivesQueueSend, type HivesQueueDelivery, type HivesDeadLetter, type HivesDeadLetterStats } from './hives-queues.js';
|
|
16
16
|
export type { HivesRuntime, HivesRuntimeSelection } from './hives-runtimes.js';
|
|
17
|
+
export type { HivesVolume, HivesVolumeCreate, HivesVolumeMount, HivesVolumePage } from './hives-volumes.js';
|
|
17
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';
|