@hypit/hypit 0.2.0 → 0.2.1
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 +1 -1
- package/examples/provider-package/hypit.runtime.json +2 -2
- package/package.json +2 -1
- package/packages/credential-store-file/README.md +3 -1
- package/packages/credential-store-os/README.md +4 -0
- package/packages/credential-store-platform/README.md +62 -0
- package/packages/credential-store-platform/package.json +23 -0
- package/packages/credential-store-platform/src/activation.ts +39 -0
- package/packages/credential-store-platform/src/index.ts +1 -0
- package/packages/credential-store-platform/src/store.ts +89 -0
package/README.md
CHANGED
|
@@ -110,7 +110,7 @@ Drop in a video and your agent clones the whole workflow — or describe what yo
|
|
|
110
110
|
|
|
111
111
|
## Stay Tuned with Us
|
|
112
112
|
|
|
113
|
-
Star
|
|
113
|
+
Star us, and you will receive all release notifications from GitHub without any delay!
|
|
114
114
|
|
|
115
115
|

|
|
116
116
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "hypit.runtime-local@1",
|
|
3
3
|
"dataRoot": ".hypit/execution",
|
|
4
|
-
"credentials": { "
|
|
4
|
+
"credentials": { "platform": { "use": "@hypit/credential-store-platform" } },
|
|
5
5
|
"endpoints": {
|
|
6
6
|
"images.personal": {
|
|
7
7
|
"use": "@example/provider-images",
|
|
8
|
-
"config": { "baseUrl": "https://images.example", "apiKey": { "store": "
|
|
8
|
+
"config": { "baseUrl": "https://images.example", "apiKey": { "store": "platform", "key": "images.personal" } }
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"bindings": { "@hypit/gpt-image@1#gpt-image-2": "images.personal" }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypit/hypit",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"homepage": "https://hypit.ai",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -205,6 +205,7 @@
|
|
|
205
205
|
"@hypit/credential-store-env": "workspace:*",
|
|
206
206
|
"@hypit/credential-store-file": "workspace:*",
|
|
207
207
|
"@hypit/credential-store-os": "workspace:*",
|
|
208
|
+
"@hypit/credential-store-platform": "workspace:*",
|
|
208
209
|
"@hypit/deck-track": "workspace:*",
|
|
209
210
|
"@hypit/deck-track-studio": "workspace:*",
|
|
210
211
|
"@hypit/elevenlabs-speech": "workspace:*",
|
|
@@ -4,7 +4,9 @@ A writable CredentialStore for a deployment that explicitly chooses local file s
|
|
|
4
4
|
Linux without an OS credential locker. It stores unencrypted credential values in an owner-private
|
|
5
5
|
directory outside the video project. On Windows the selected directory must have a private user ACL;
|
|
6
6
|
POSIX file modes do not set Windows ACLs. Choose `@hypit/credential-store-os` when using macOS Keychain
|
|
7
|
-
or Windows Credential Locker,
|
|
7
|
+
or Windows Credential Locker, `@hypit/credential-store-platform` for OS storage on macOS/Windows
|
|
8
|
+
and this file Store on Linux or `@hypit/credential-store-env` for externally
|
|
9
|
+
supplied, read-only values.
|
|
8
10
|
|
|
9
11
|
## Select it before login
|
|
10
12
|
|
|
@@ -11,3 +11,7 @@ bytes do not appear in command arguments or temporary files.
|
|
|
11
11
|
|
|
12
12
|
Use `hypit auth login <endpoint> --runtime <profile>` to write the selected credential and
|
|
13
13
|
`hypit auth logout` to remove it.
|
|
14
|
+
|
|
15
|
+
A Profile that must also run on Linux can select `@hypit/credential-store-platform`:
|
|
16
|
+
that package uses this Store on macOS and Windows, and an unencrypted, owner-private file on Linux.
|
|
17
|
+
Selecting `@hypit/credential-store-os` directly continues to require macOS or Windows.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# `@hypit/credential-store-platform`
|
|
2
|
+
|
|
3
|
+
An explicitly selected CredentialStore policy: macOS Keychain on macOS, Windows Credential Locker
|
|
4
|
+
on Windows, and an unencrypted, owner-private file on Linux. Other platforms are unsupported by this
|
|
5
|
+
package and report an error. Linux may offer other credential services; this package chooses file
|
|
6
|
+
storage there and does not detect or integrate those services.
|
|
7
|
+
|
|
8
|
+
A Profile can select this package to use that policy on Linux, macOS and Windows.
|
|
9
|
+
`@hypit/credential-store-os`, `@hypit/credential-store-file` and `@hypit/credential-store-env`
|
|
10
|
+
remain selectable directly for a deployment with a different storage choice.
|
|
11
|
+
|
|
12
|
+
## Select it
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"credentials": {
|
|
17
|
+
"platform": { "use": "@hypit/credential-store-platform" }
|
|
18
|
+
},
|
|
19
|
+
"endpoints": {
|
|
20
|
+
"hypihub.default": {
|
|
21
|
+
"use": "@hypit/provider-hypihub",
|
|
22
|
+
"config": {
|
|
23
|
+
"baseUrl": "https://hypit.ai",
|
|
24
|
+
"apiKey": { "store": "platform", "key": "hypihub.oauth" }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The Endpoint still owns its acquisition flow and the Store only persists the result:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
hypit auth login hypihub.default --runtime <profile>
|
|
35
|
+
hypit auth status hypihub.default --runtime <profile>
|
|
36
|
+
hypit auth logout hypihub.default --runtime <profile>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## What it does not do
|
|
40
|
+
|
|
41
|
+
The choice is made once per host, from the platform the Runtime is running on. This is not a lookup
|
|
42
|
+
chain: a miss or failure in one store never tries another, and no credential is migrated between them. A
|
|
43
|
+
credential stored in a locker stays in that locker; a credential stored in a file stays in that file.
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
- `path` selects the directory for Linux file storage, resolved against the Host state root printed by
|
|
48
|
+
`hypit paths`. The default is the same `credentials` directory `@hypit/credential-store-file` uses,
|
|
49
|
+
so on Linux, switching between the two Stores finds the credential already stored.
|
|
50
|
+
- `service` selects the locker service name. The OS Store's own default applies when it is absent.
|
|
51
|
+
|
|
52
|
+
## Storage on each platform
|
|
53
|
+
|
|
54
|
+
On macOS and Windows the credential is held by the platform locker, with exactly the rules of
|
|
55
|
+
`@hypit/credential-store-os`: it is encrypted and access-controlled by the operating system, and it
|
|
56
|
+
is not readable from another machine.
|
|
57
|
+
|
|
58
|
+
On Linux the credential is held by an owner-private document with exactly the rules of
|
|
59
|
+
`@hypit/credential-store-file`: unencrypted JSON, one document per key, directory mode `0700`, file
|
|
60
|
+
mode `0600`, outside the video project, and never enumerated or indexed. Filesystem path-length
|
|
61
|
+
limits apply to an overlong key, which fails rather than selecting another name. A damaged document
|
|
62
|
+
can be replaced by `auth login` or deleted by `auth logout` without decoding the old value.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hypit/credential-store-platform",
|
|
3
|
+
"version": "0.0.0-dev",
|
|
4
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"hypit": {
|
|
15
|
+
"activation": "./src/activation.ts"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@hypit/credential-store-file": "workspace:*",
|
|
19
|
+
"@hypit/credential-store-os": "workspace:*",
|
|
20
|
+
"@hypit/runtime": "workspace:*",
|
|
21
|
+
"@hypit/runtime-kit": "workspace:*"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
createRuntimeCredentialStoreAdapterFacet,
|
|
4
|
+
runtimeConfigExact,
|
|
5
|
+
runtimeConfigObject,
|
|
6
|
+
runtimeConfigString,
|
|
7
|
+
} from "@hypit/runtime-kit";
|
|
8
|
+
import { PlatformCredentialStore } from "./store.js";
|
|
9
|
+
|
|
10
|
+
const platformCredentialStoreAdapter = createRuntimeCredentialStoreAdapterFacet({
|
|
11
|
+
use: "@hypit/credential-store-platform",
|
|
12
|
+
validate(context) {
|
|
13
|
+
const config = runtimeConfigObject(context.config, "platform CredentialStore");
|
|
14
|
+
runtimeConfigExact(config, ["path", "service"], "platform CredentialStore");
|
|
15
|
+
runtimeConfigString(config.path, "platform credential path");
|
|
16
|
+
runtimeConfigString(config.service, "platform credential service");
|
|
17
|
+
},
|
|
18
|
+
open(context) {
|
|
19
|
+
const config = runtimeConfigObject(context.config, "platform CredentialStore");
|
|
20
|
+
const path = runtimeConfigString(config.path, "platform credential path");
|
|
21
|
+
const service = runtimeConfigString(config.service, "platform credential service");
|
|
22
|
+
return {
|
|
23
|
+
value: new PlatformCredentialStore({
|
|
24
|
+
// Linux uses the same directory the file Store uses by default, so a Profile
|
|
25
|
+
// that switches between them on Linux finds the credential it stored.
|
|
26
|
+
directory: path === undefined
|
|
27
|
+
? join(context.hostStateRoot, "credentials")
|
|
28
|
+
: resolve(context.hostStateRoot, path),
|
|
29
|
+
...(service === undefined ? {} : { service }),
|
|
30
|
+
}),
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const hypitPackage = {
|
|
36
|
+
format: "hypit.node-package@1" as const,
|
|
37
|
+
hostFacets: [platformCredentialStoreAdapter],
|
|
38
|
+
};
|
|
39
|
+
export default hypitPackage;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PlatformCredentialStore } from "./store.js";
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {
|
|
2
|
+
credentialRef,
|
|
3
|
+
verifyCredentialRef,
|
|
4
|
+
} from "@hypit/runtime";
|
|
5
|
+
import type {
|
|
6
|
+
CredentialRef,
|
|
7
|
+
CredentialValue,
|
|
8
|
+
WritableCredentialStore,
|
|
9
|
+
} from "@hypit/runtime";
|
|
10
|
+
import { FileCredentialStore } from "@hypit/credential-store-file";
|
|
11
|
+
import { OsCredentialStore } from "@hypit/credential-store-os";
|
|
12
|
+
import type {
|
|
13
|
+
OsCredentialDeleter,
|
|
14
|
+
OsCredentialReader,
|
|
15
|
+
OsCredentialWriter,
|
|
16
|
+
} from "@hypit/credential-store-os";
|
|
17
|
+
|
|
18
|
+
export type PlatformCredentialStoreOptions = {
|
|
19
|
+
/** Directory holding the documents this Store selects on Linux. */
|
|
20
|
+
readonly directory: string;
|
|
21
|
+
/** Service the locker's entries are filed under; the OS Store's own default applies where absent. */
|
|
22
|
+
readonly service?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The platform to select for, defaulting to the running one. A Profile never states this: it is
|
|
25
|
+
* separate so the selection can be exercised on one machine for every platform.
|
|
26
|
+
*/
|
|
27
|
+
readonly platform?: NodeJS.Platform;
|
|
28
|
+
/** Locker backend to read and write with, where the platform's own locker is not the one to use. */
|
|
29
|
+
readonly locker?: {
|
|
30
|
+
readonly read: OsCredentialReader;
|
|
31
|
+
readonly write: OsCredentialWriter;
|
|
32
|
+
readonly remove: OsCredentialDeleter;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* An explicitly selected storage policy: OS credentials on macOS/Windows, files on Linux.
|
|
38
|
+
* The selected backend's errors propagate; other platforms are unsupported by this package.
|
|
39
|
+
*/
|
|
40
|
+
export class PlatformCredentialStore implements WritableCredentialStore {
|
|
41
|
+
readonly #delegate: WritableCredentialStore;
|
|
42
|
+
readonly #backing: "os" | "file";
|
|
43
|
+
|
|
44
|
+
constructor(options: PlatformCredentialStoreOptions) {
|
|
45
|
+
const platform = options.platform ?? process.platform;
|
|
46
|
+
if (platform === "darwin" || platform === "win32") {
|
|
47
|
+
this.#backing = "os";
|
|
48
|
+
this.#delegate = new OsCredentialStore({
|
|
49
|
+
...(options.service === undefined ? {} : { service: options.service }),
|
|
50
|
+
...options.locker,
|
|
51
|
+
});
|
|
52
|
+
} else if (platform === "linux") {
|
|
53
|
+
this.#backing = "file";
|
|
54
|
+
this.#delegate = new FileCredentialStore(options.directory);
|
|
55
|
+
} else {
|
|
56
|
+
throw new Error(`Platform CredentialStore does not support ${platform}; select an explicit CredentialStore supported by this host`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
owns(ref: CredentialRef): boolean {
|
|
61
|
+
return ref.store === "platform";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Each delegate owns its own name and refuses refs filed under another, so a ref this Store owns
|
|
66
|
+
* is retargeted before the delegate sees it. Only the name changes; the opaque key is untouched.
|
|
67
|
+
*/
|
|
68
|
+
#translated(ref: CredentialRef): CredentialRef {
|
|
69
|
+
return credentialRef(this.#backing, ref.key);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async resolve(ref: CredentialRef): Promise<CredentialValue | undefined> {
|
|
73
|
+
verifyCredentialRef(ref);
|
|
74
|
+
if (!this.owns(ref)) return undefined;
|
|
75
|
+
return await this.#delegate.resolve(this.#translated(ref));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async put(ref: CredentialRef, value: CredentialValue): Promise<void> {
|
|
79
|
+
verifyCredentialRef(ref);
|
|
80
|
+
if (!this.owns(ref)) throw new Error(`Platform CredentialStore does not own ${ref.store}`);
|
|
81
|
+
await this.#delegate.put(this.#translated(ref), value);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async delete(ref: CredentialRef): Promise<boolean> {
|
|
85
|
+
verifyCredentialRef(ref);
|
|
86
|
+
if (!this.owns(ref)) throw new Error(`Platform CredentialStore does not own ${ref.store}`);
|
|
87
|
+
return await this.#delegate.delete(this.#translated(ref));
|
|
88
|
+
}
|
|
89
|
+
}
|