@clidey/whodb-sdk 0.0.0
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 +81 -0
- package/dist/auth.d.ts +26 -0
- package/dist/auth.js +65 -0
- package/dist/client.d.ts +51 -0
- package/dist/client.js +157 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.js +39 -0
- package/dist/dataset.d.ts +26 -0
- package/dist/dataset.js +45 -0
- package/dist/errors.d.ts +43 -0
- package/dist/errors.js +59 -0
- package/dist/files.d.ts +25 -0
- package/dist/files.js +53 -0
- package/dist/generated/hydration.d.ts +3 -0
- package/dist/generated/hydration.js +32 -0
- package/dist/generated/manifest.d.ts +12 -0
- package/dist/generated/manifest.js +80 -0
- package/dist/generated/operations.d.ts +196 -0
- package/dist/generated/operations.js +145 -0
- package/dist/generated/surface.d.ts +190 -0
- package/dist/generated/surface.js +191 -0
- package/dist/generated/types.d.ts +302 -0
- package/dist/generated/types.js +2 -0
- package/dist/hydrate.d.ts +18 -0
- package/dist/hydrate.js +83 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +9 -0
- package/dist/manifest-check.d.ts +15 -0
- package/dist/manifest-check.js +43 -0
- package/dist/ontology.d.ts +73 -0
- package/dist/ontology.js +240 -0
- package/dist/pagination.d.ts +21 -0
- package/dist/pagination.js +33 -0
- package/dist/source.d.ts +31 -0
- package/dist/source.js +63 -0
- package/dist/transport-http.d.ts +22 -0
- package/dist/transport-http.js +60 -0
- package/dist/transport-ipc.d.ts +31 -0
- package/dist/transport-ipc.js +183 -0
- package/dist/transport.d.ts +9 -0
- package/dist/transport.js +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +5 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @clidey/whodb-sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript/JavaScript SDK for the [WhoDB](https://whodb.com) hosted
|
|
4
|
+
platform — your ontology, datasets, and sources as in-code function APIs.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @clidey/whodb-sdk
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Requires Node.js ≥ 20.
|
|
13
|
+
|
|
14
|
+
## Quickstart
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { WhoDB } from '@clidey/whodb-sdk';
|
|
18
|
+
|
|
19
|
+
// Production: API key (create one in org settings → API keys).
|
|
20
|
+
// The key carries its org; the project auto-resolves when the key
|
|
21
|
+
// has access to exactly one project.
|
|
22
|
+
const whodb = new WhoDB({ apiKey: process.env.WHODB_API_KEY });
|
|
23
|
+
|
|
24
|
+
// Local development: zero config — reuses your `whodb login` session.
|
|
25
|
+
// const whodb = new WhoDB();
|
|
26
|
+
|
|
27
|
+
const users = whodb.ontology('User');
|
|
28
|
+
|
|
29
|
+
const user = await users.get('u_123');
|
|
30
|
+
const active = await users.list({ where: { status: { eq: 'active' } }, pageSize: 100 });
|
|
31
|
+
await users.create({ email: 'a@b.co' });
|
|
32
|
+
await users.createMany(rows, { idempotencyKey: 'import-42' });
|
|
33
|
+
await users.update('u_123', { plan: 'pro' });
|
|
34
|
+
const orders = await users.followLink('u_123', 'orders');
|
|
35
|
+
|
|
36
|
+
// Iterate everything, page by page:
|
|
37
|
+
for await (const page of users.list({ pageSize: 500 }).pages()) {
|
|
38
|
+
console.log(page.rows.length);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Datasets and sources:
|
|
42
|
+
const kpis = await whodb.dataset('weekly_kpis').rows();
|
|
43
|
+
const raw = await whodb.source('src_...').rows({ Kind: 'Table', Locator: 'events' });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Authentication
|
|
47
|
+
|
|
48
|
+
Credential precedence:
|
|
49
|
+
|
|
50
|
+
1. `new WhoDB({ apiKey })` / `{ token }` / `{ credentials }` constructor options
|
|
51
|
+
2. `WHODB_API_KEY` environment variable
|
|
52
|
+
3. The `whodb` CLI's stored login (`whodb login`), gcloud-ADC-style — ideal
|
|
53
|
+
for local development
|
|
54
|
+
|
|
55
|
+
Workspace (`org` / `project`) is optional with an API key; pass `{ project }`
|
|
56
|
+
or set `WHODB_PROJECT` when the key has access to more than one project.
|
|
57
|
+
|
|
58
|
+
## Typed clients
|
|
59
|
+
|
|
60
|
+
Generate typed entity classes from your project's ontology:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
whodb sdk generate --language ts --out src/whodb-gen/
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { createClient } from './whodb-gen/whodb.generated.js';
|
|
68
|
+
|
|
69
|
+
const { ontology } = createClient({ apiKey: process.env.WHODB_API_KEY });
|
|
70
|
+
const user = await ontology.User.get('u_123'); // fully typed
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Versioning
|
|
74
|
+
|
|
75
|
+
Each SDK release is generated against one WhoDB platform release. Deprecated
|
|
76
|
+
operations warn once per process with their removal date; operations removed
|
|
77
|
+
from the platform raise `WhoDBVersionError` — upgrade the package to resolve.
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
Apache-2.0
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CredentialProvider yields a bearer credential for platform requests.
|
|
3
|
+
* refresh() is invoked once after a 401 before the request is retried.
|
|
4
|
+
*/
|
|
5
|
+
export interface CredentialProvider {
|
|
6
|
+
token(): Promise<string>;
|
|
7
|
+
refresh?(): Promise<void>;
|
|
8
|
+
/** Workspace defaults carried by the credential source, if any. */
|
|
9
|
+
defaults?(): Promise<WorkspaceDefaults>;
|
|
10
|
+
}
|
|
11
|
+
/** Workspace defaults resolved from a credential source (CLI helper). */
|
|
12
|
+
export interface WorkspaceDefaults {
|
|
13
|
+
host?: string;
|
|
14
|
+
orgId?: string;
|
|
15
|
+
projectId?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Static API-key credentials (production/headless usage). */
|
|
18
|
+
export declare function apiKeyProvider(apiKey: string): CredentialProvider;
|
|
19
|
+
/** Static OIDC token or caller-managed token callback. */
|
|
20
|
+
export declare function tokenProvider(source: string | (() => Promise<string>)): CredentialProvider;
|
|
21
|
+
/**
|
|
22
|
+
* CLI credentials: exec `whodb auth print-token --format json` and cache the
|
|
23
|
+
* token until shortly before its expiry — the gcloud-ADC pattern for local
|
|
24
|
+
* development. Requires the whodb CLI on PATH and a prior `whodb login`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function cliProvider(command?: string): CredentialProvider;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { AuthError, CliCredentialsError } from './errors.js';
|
|
3
|
+
/** Static API-key credentials (production/headless usage). */
|
|
4
|
+
export function apiKeyProvider(apiKey) {
|
|
5
|
+
return {
|
|
6
|
+
token: async () => apiKey,
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/** Static OIDC token or caller-managed token callback. */
|
|
10
|
+
export function tokenProvider(source) {
|
|
11
|
+
if (typeof source === 'string') {
|
|
12
|
+
return { token: async () => source };
|
|
13
|
+
}
|
|
14
|
+
return { token: source };
|
|
15
|
+
}
|
|
16
|
+
const CLI_REFRESH_SKEW_MS = 60_000;
|
|
17
|
+
/**
|
|
18
|
+
* CLI credentials: exec `whodb auth print-token --format json` and cache the
|
|
19
|
+
* token until shortly before its expiry — the gcloud-ADC pattern for local
|
|
20
|
+
* development. Requires the whodb CLI on PATH and a prior `whodb login`.
|
|
21
|
+
*/
|
|
22
|
+
export function cliProvider(command = 'whodb') {
|
|
23
|
+
let cached = null;
|
|
24
|
+
const exec = () => new Promise((resolvePromise, rejectPromise) => {
|
|
25
|
+
execFile(command, ['auth', 'print-token', '--format', 'json'], { timeout: 15_000 }, (error, stdout, stderr) => {
|
|
26
|
+
if (error) {
|
|
27
|
+
if (error.code === 'ENOENT') {
|
|
28
|
+
rejectPromise(new CliCredentialsError(`whodb CLI not found — install it or set WHODB_API_KEY`));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
rejectPromise(new CliCredentialsError(`whodb auth print-token failed: ${stderr.trim() || error.message}`));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
resolvePromise(JSON.parse(stdout));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
rejectPromise(new CliCredentialsError('whodb auth print-token returned invalid JSON'));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
const isFresh = (entry) => {
|
|
43
|
+
if (!entry.expires_at)
|
|
44
|
+
return false; // no expiry info — re-exec every call
|
|
45
|
+
return new Date(entry.expires_at).getTime() - Date.now() > CLI_REFRESH_SKEW_MS;
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
async token() {
|
|
49
|
+
if (cached && isFresh(cached))
|
|
50
|
+
return cached.access_token;
|
|
51
|
+
cached = await exec();
|
|
52
|
+
if (!cached.access_token)
|
|
53
|
+
throw new AuthError('whodb CLI returned an empty access token');
|
|
54
|
+
return cached.access_token;
|
|
55
|
+
},
|
|
56
|
+
async refresh() {
|
|
57
|
+
cached = null;
|
|
58
|
+
},
|
|
59
|
+
async defaults() {
|
|
60
|
+
if (!cached)
|
|
61
|
+
cached = await exec();
|
|
62
|
+
return { host: cached.host, orgId: cached.org_id, projectId: cached.project_id };
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Transport } from './transport.js';
|
|
2
|
+
import { type WhoDBConfig } from './config.js';
|
|
3
|
+
import { OntologyHandle } from './ontology.js';
|
|
4
|
+
import { DatasetHandle } from './dataset.js';
|
|
5
|
+
import { SourceHandle } from './source.js';
|
|
6
|
+
import { FilesHandle } from './files.js';
|
|
7
|
+
import type { OntologyObjectType, PlatformSource } from './generated/types.js';
|
|
8
|
+
/**
|
|
9
|
+
* WhoDB is the platform client. Configure with an API key (headless), a raw
|
|
10
|
+
* token, or nothing at all — local development falls back to `whodb login`
|
|
11
|
+
* credentials via the CLI helper.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* const whodb = new WhoDB({ apiKey: process.env.WHODB_API_KEY, org: "acme", project: "growth" });
|
|
15
|
+
* const user = await whodb.ontology("User").get("u_123");
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare class WhoDB {
|
|
19
|
+
/** SHA-256 of the platform manifest this SDK release was generated from. */
|
|
20
|
+
static readonly manifestHash = "4b84678f5fe7d777fbd4c4b2a93dff64f4c8951978ce68006ddc3a0e25c6942f";
|
|
21
|
+
/** This SDK package's version. */
|
|
22
|
+
static readonly version = "0.0.0";
|
|
23
|
+
private readonly transport;
|
|
24
|
+
private readonly httpTransport;
|
|
25
|
+
private readonly filesHandle;
|
|
26
|
+
private readonly orgInput?;
|
|
27
|
+
private readonly projectInput?;
|
|
28
|
+
private workspacePromise;
|
|
29
|
+
constructor(config?: WhoDBConfig, transportOverride?: Transport);
|
|
30
|
+
private cliDefaults;
|
|
31
|
+
private skipWorkspaceResolution;
|
|
32
|
+
private usingApiKey;
|
|
33
|
+
/**
|
|
34
|
+
* Resolves org/project slugs or IDs to IDs, once, and stamps the workspace
|
|
35
|
+
* headers onto the transport. IDs pass through without a lookup.
|
|
36
|
+
*/
|
|
37
|
+
private workspace;
|
|
38
|
+
private projectId;
|
|
39
|
+
/** Returns a handle for one ontology entity, addressed by apiName. */
|
|
40
|
+
ontology(name: string): OntologyHandle;
|
|
41
|
+
/** Lists all ontology entities in the project. */
|
|
42
|
+
ontologyEntities(): Promise<OntologyObjectType[]>;
|
|
43
|
+
/** Returns a handle for one dataset, addressed by name. */
|
|
44
|
+
dataset(name: string): DatasetHandle;
|
|
45
|
+
/** Returns a handle for one connected source, addressed by ID. */
|
|
46
|
+
source(id: string): SourceHandle;
|
|
47
|
+
/** Lists the project's connected sources. */
|
|
48
|
+
sources(): Promise<PlatformSource[]>;
|
|
49
|
+
/** File upload/download over the platform's bulk HTTP endpoints. */
|
|
50
|
+
get files(): FilesHandle;
|
|
51
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { HttpTransport } from './transport-http.js';
|
|
2
|
+
import { IpcTransport } from './transport-ipc.js';
|
|
3
|
+
import { resolveConfig, DEFAULT_HOST } from './config.js';
|
|
4
|
+
import { OntologyHandle } from './ontology.js';
|
|
5
|
+
import { DatasetHandle } from './dataset.js';
|
|
6
|
+
import { SourceHandle, listSources } from './source.js';
|
|
7
|
+
import { FilesHandle } from './files.js';
|
|
8
|
+
import * as ops from './generated/operations.js';
|
|
9
|
+
import { manifestHash } from './generated/manifest.js';
|
|
10
|
+
import { ValidationError } from './errors.js';
|
|
11
|
+
import { SDK_VERSION } from './version.js';
|
|
12
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
13
|
+
/**
|
|
14
|
+
* WhoDB is the platform client. Configure with an API key (headless), a raw
|
|
15
|
+
* token, or nothing at all — local development falls back to `whodb login`
|
|
16
|
+
* credentials via the CLI helper.
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* const whodb = new WhoDB({ apiKey: process.env.WHODB_API_KEY, org: "acme", project: "growth" });
|
|
20
|
+
* const user = await whodb.ontology("User").get("u_123");
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class WhoDB {
|
|
24
|
+
/** SHA-256 of the platform manifest this SDK release was generated from. */
|
|
25
|
+
static manifestHash = manifestHash;
|
|
26
|
+
/** This SDK package's version. */
|
|
27
|
+
static version = SDK_VERSION;
|
|
28
|
+
transport;
|
|
29
|
+
httpTransport;
|
|
30
|
+
filesHandle;
|
|
31
|
+
orgInput;
|
|
32
|
+
projectInput;
|
|
33
|
+
workspacePromise = null;
|
|
34
|
+
constructor(config = {}, transportOverride) {
|
|
35
|
+
// Functions runtime autodetect: no explicit transport/credentials and the
|
|
36
|
+
// IPC env vars are present → route through the in-container IPC server.
|
|
37
|
+
if (!transportOverride &&
|
|
38
|
+
!config.credentials && !config.apiKey && !config.token &&
|
|
39
|
+
!process.env.WHODB_API_KEY && process.env.WHODB_IPC_TOKEN) {
|
|
40
|
+
transportOverride = new IpcTransport();
|
|
41
|
+
}
|
|
42
|
+
const resolved = resolveConfig(config);
|
|
43
|
+
this.orgInput = resolved.org;
|
|
44
|
+
this.projectInput = resolved.project;
|
|
45
|
+
this.usingApiKey = resolved.usingApiKey;
|
|
46
|
+
if (transportOverride) {
|
|
47
|
+
// Custom transports (IPC in the functions runtime, mocks in tests) skip
|
|
48
|
+
// slug resolution: org/project inputs are taken as IDs verbatim.
|
|
49
|
+
this.transport = transportOverride;
|
|
50
|
+
this.httpTransport = null;
|
|
51
|
+
this.filesHandle = null;
|
|
52
|
+
this.skipWorkspaceResolution = true;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const host = resolved.host ?? DEFAULT_HOST;
|
|
56
|
+
const httpTransport = new HttpTransport({ host, credentials: resolved.credentials });
|
|
57
|
+
this.transport = httpTransport;
|
|
58
|
+
this.httpTransport = httpTransport;
|
|
59
|
+
this.filesHandle = new FilesHandle({
|
|
60
|
+
host,
|
|
61
|
+
credentials: resolved.credentials,
|
|
62
|
+
orgId: async () => (await this.workspace()).orgId,
|
|
63
|
+
projectId: async () => (await this.workspace()).projectId,
|
|
64
|
+
});
|
|
65
|
+
// Workspace headers must be present before the first scoped call; resolve
|
|
66
|
+
// lazily but wire the transport update into the resolution.
|
|
67
|
+
if (resolved.usingCliCredentials) {
|
|
68
|
+
this.cliDefaults = async () => {
|
|
69
|
+
const defaults = await resolved.credentials.defaults?.();
|
|
70
|
+
return { orgId: defaults?.orgId, projectId: defaults?.projectId };
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
cliDefaults = null;
|
|
75
|
+
skipWorkspaceResolution = false;
|
|
76
|
+
usingApiKey = false;
|
|
77
|
+
/**
|
|
78
|
+
* Resolves org/project slugs or IDs to IDs, once, and stamps the workspace
|
|
79
|
+
* headers onto the transport. IDs pass through without a lookup.
|
|
80
|
+
*/
|
|
81
|
+
workspace() {
|
|
82
|
+
this.workspacePromise ??= (async () => {
|
|
83
|
+
let orgInput = this.orgInput;
|
|
84
|
+
let projectInput = this.projectInput;
|
|
85
|
+
if ((!orgInput || !projectInput) && this.cliDefaults) {
|
|
86
|
+
const defaults = await this.cliDefaults();
|
|
87
|
+
orgInput ??= defaults.orgId;
|
|
88
|
+
projectInput ??= defaults.projectId;
|
|
89
|
+
}
|
|
90
|
+
if ((!orgInput || !projectInput) && this.usingApiKey) {
|
|
91
|
+
// API keys carry their org, and the platform auto-resolves the
|
|
92
|
+
// project when the key has exactly one grant — discover both.
|
|
93
|
+
const mine = await ops.myWorkspace(this.transport, {});
|
|
94
|
+
orgInput ??= mine.orgId ?? undefined;
|
|
95
|
+
projectInput ??= mine.projectId ?? undefined;
|
|
96
|
+
if (!projectInput) {
|
|
97
|
+
throw new ValidationError('this API key has access to multiple (or zero) projects — pass { project } to the WhoDB constructor or set WHODB_PROJECT');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!orgInput || !projectInput) {
|
|
101
|
+
throw new ValidationError('org and project are required — pass { org, project } to the WhoDB constructor, set WHODB_ORG/WHODB_PROJECT, or run: whodb use');
|
|
102
|
+
}
|
|
103
|
+
if (this.skipWorkspaceResolution) {
|
|
104
|
+
return { orgId: orgInput, projectId: projectInput };
|
|
105
|
+
}
|
|
106
|
+
let orgId = orgInput;
|
|
107
|
+
if (!UUID_PATTERN.test(orgInput)) {
|
|
108
|
+
const orgs = await ops.myOrganizations(this.transport, {});
|
|
109
|
+
const match = orgs.find(o => o.slug === orgInput || o.name === orgInput);
|
|
110
|
+
if (!match)
|
|
111
|
+
throw new ValidationError(`organization "${orgInput}" not found for this account`);
|
|
112
|
+
orgId = match.id;
|
|
113
|
+
}
|
|
114
|
+
// Project resolution needs the org header in place.
|
|
115
|
+
this.httpTransport?.setWorkspace(orgId, undefined);
|
|
116
|
+
let projectId = projectInput;
|
|
117
|
+
if (!UUID_PATTERN.test(projectInput)) {
|
|
118
|
+
const projects = await ops.projects(this.transport, { orgId });
|
|
119
|
+
const match = projects.find(p => p.slug === projectInput || p.name === projectInput);
|
|
120
|
+
if (!match)
|
|
121
|
+
throw new ValidationError(`project "${projectInput}" not found in this organization`);
|
|
122
|
+
projectId = match.id;
|
|
123
|
+
}
|
|
124
|
+
this.httpTransport?.setWorkspace(orgId, projectId);
|
|
125
|
+
return { orgId, projectId };
|
|
126
|
+
})();
|
|
127
|
+
return this.workspacePromise;
|
|
128
|
+
}
|
|
129
|
+
projectId = async () => (await this.workspace()).projectId;
|
|
130
|
+
/** Returns a handle for one ontology entity, addressed by apiName. */
|
|
131
|
+
ontology(name) {
|
|
132
|
+
return new OntologyHandle(this.transport, this.projectId, name);
|
|
133
|
+
}
|
|
134
|
+
/** Lists all ontology entities in the project. */
|
|
135
|
+
async ontologyEntities() {
|
|
136
|
+
return ops.ontologyEntities(this.transport, { projectId: await this.projectId() });
|
|
137
|
+
}
|
|
138
|
+
/** Returns a handle for one dataset, addressed by name. */
|
|
139
|
+
dataset(name) {
|
|
140
|
+
return new DatasetHandle(this.transport, this.projectId, name);
|
|
141
|
+
}
|
|
142
|
+
/** Returns a handle for one connected source, addressed by ID. */
|
|
143
|
+
source(id) {
|
|
144
|
+
return new SourceHandle(this.transport, this.projectId, id);
|
|
145
|
+
}
|
|
146
|
+
/** Lists the project's connected sources. */
|
|
147
|
+
async sources() {
|
|
148
|
+
return listSources(this.transport, await this.projectId());
|
|
149
|
+
}
|
|
150
|
+
/** File upload/download over the platform's bulk HTTP endpoints. */
|
|
151
|
+
get files() {
|
|
152
|
+
if (!this.filesHandle) {
|
|
153
|
+
throw new ValidationError('files are not available over a custom transport');
|
|
154
|
+
}
|
|
155
|
+
return this.filesHandle;
|
|
156
|
+
}
|
|
157
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type CredentialProvider } from './auth.js';
|
|
2
|
+
/** Constructor options for the WhoDB client. */
|
|
3
|
+
export interface WhoDBConfig {
|
|
4
|
+
/** Platform API key (whodb_sk_...). Highest-precedence credential. */
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
/** Raw OIDC access token or an async token callback. */
|
|
7
|
+
token?: string | (() => Promise<string>);
|
|
8
|
+
/** Fully custom credential provider. */
|
|
9
|
+
credentials?: CredentialProvider;
|
|
10
|
+
/** Organization slug or ID. */
|
|
11
|
+
org?: string;
|
|
12
|
+
/** Project slug or ID. */
|
|
13
|
+
project?: string;
|
|
14
|
+
/** Platform host. Defaults to https://app.whodb.com. */
|
|
15
|
+
host?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const DEFAULT_HOST = "https://app.whodb.com";
|
|
18
|
+
/** Resolved client configuration after applying the precedence rules. */
|
|
19
|
+
export interface ResolvedConfig {
|
|
20
|
+
credentials: CredentialProvider;
|
|
21
|
+
/** True when credentials came from the CLI helper (workspace defaults apply). */
|
|
22
|
+
usingCliCredentials: boolean;
|
|
23
|
+
/** True for API keys: the key carries its org, and the platform
|
|
24
|
+
* auto-resolves the project when the key has exactly one grant — so
|
|
25
|
+
* org/project config is optional. */
|
|
26
|
+
usingApiKey: boolean;
|
|
27
|
+
host?: string;
|
|
28
|
+
org?: string;
|
|
29
|
+
project?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Applies the credential precedence from SDK_DESIGN.md §5.3:
|
|
33
|
+
* constructor args → WHODB_API_KEY env → CLI helper (local-dev default).
|
|
34
|
+
* Workspace/host: explicit args → WHODB_ORG/WHODB_PROJECT/WHODB_HOST env →
|
|
35
|
+
* CLI helper's saved defaults (only when using CLI credentials).
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveConfig(config: WhoDBConfig, env?: NodeJS.ProcessEnv): ResolvedConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { apiKeyProvider, cliProvider, tokenProvider } from './auth.js';
|
|
2
|
+
export const DEFAULT_HOST = 'https://app.whodb.com';
|
|
3
|
+
/**
|
|
4
|
+
* Applies the credential precedence from SDK_DESIGN.md §5.3:
|
|
5
|
+
* constructor args → WHODB_API_KEY env → CLI helper (local-dev default).
|
|
6
|
+
* Workspace/host: explicit args → WHODB_ORG/WHODB_PROJECT/WHODB_HOST env →
|
|
7
|
+
* CLI helper's saved defaults (only when using CLI credentials).
|
|
8
|
+
*/
|
|
9
|
+
export function resolveConfig(config, env = process.env) {
|
|
10
|
+
let credentials;
|
|
11
|
+
let usingCliCredentials = false;
|
|
12
|
+
let usingApiKey = false;
|
|
13
|
+
if (config.credentials) {
|
|
14
|
+
credentials = config.credentials;
|
|
15
|
+
}
|
|
16
|
+
else if (config.apiKey) {
|
|
17
|
+
credentials = apiKeyProvider(config.apiKey);
|
|
18
|
+
usingApiKey = true;
|
|
19
|
+
}
|
|
20
|
+
else if (config.token) {
|
|
21
|
+
credentials = tokenProvider(config.token);
|
|
22
|
+
}
|
|
23
|
+
else if (env.WHODB_API_KEY) {
|
|
24
|
+
credentials = apiKeyProvider(env.WHODB_API_KEY);
|
|
25
|
+
usingApiKey = true;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
credentials = cliProvider();
|
|
29
|
+
usingCliCredentials = true;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
credentials,
|
|
33
|
+
usingCliCredentials,
|
|
34
|
+
usingApiKey,
|
|
35
|
+
host: config.host ?? env.WHODB_HOST,
|
|
36
|
+
org: config.org ?? env.WHODB_ORG,
|
|
37
|
+
project: config.project ?? env.WHODB_PROJECT,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Transport } from './transport.js';
|
|
2
|
+
import type { Dataset } from './generated/types.js';
|
|
3
|
+
import { type Row } from './hydrate.js';
|
|
4
|
+
/** Options for dataset row reads. */
|
|
5
|
+
export interface DatasetRowsOptions {
|
|
6
|
+
pageSize?: number;
|
|
7
|
+
pageOffset?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* DatasetHandle is the `whodb.dataset("weekly_kpis")` facade, addressed by
|
|
11
|
+
* dataset name.
|
|
12
|
+
*/
|
|
13
|
+
export declare class DatasetHandle {
|
|
14
|
+
private readonly transport;
|
|
15
|
+
private readonly projectId;
|
|
16
|
+
private readonly name;
|
|
17
|
+
private datasetCache;
|
|
18
|
+
constructor(transport: Transport, projectId: () => Promise<string>, name: string);
|
|
19
|
+
/** Resolves and caches the dataset metadata backing this handle. */
|
|
20
|
+
meta(): Promise<Dataset>;
|
|
21
|
+
/** Queries dataset rows with optional filter/sort/paging. */
|
|
22
|
+
rows(options?: DatasetRowsOptions): Promise<{
|
|
23
|
+
rows: Row[];
|
|
24
|
+
totalCount: number | null;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
package/dist/dataset.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as ops from './generated/operations.js';
|
|
2
|
+
import { hydrateRows } from './hydrate.js';
|
|
3
|
+
import { warnIfFlagged } from './manifest-check.js';
|
|
4
|
+
import { NotFoundError } from './errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* DatasetHandle is the `whodb.dataset("weekly_kpis")` facade, addressed by
|
|
7
|
+
* dataset name.
|
|
8
|
+
*/
|
|
9
|
+
export class DatasetHandle {
|
|
10
|
+
transport;
|
|
11
|
+
projectId;
|
|
12
|
+
name;
|
|
13
|
+
datasetCache = null;
|
|
14
|
+
constructor(transport, projectId, name) {
|
|
15
|
+
this.transport = transport;
|
|
16
|
+
this.projectId = projectId;
|
|
17
|
+
this.name = name;
|
|
18
|
+
}
|
|
19
|
+
/** Resolves and caches the dataset metadata backing this handle. */
|
|
20
|
+
async meta() {
|
|
21
|
+
if (this.datasetCache)
|
|
22
|
+
return this.datasetCache;
|
|
23
|
+
warnIfFlagged('ProjectDatasets');
|
|
24
|
+
const datasets = await ops.projectDatasets(this.transport, { projectId: await this.projectId() });
|
|
25
|
+
const dataset = datasets.find(d => d.name === this.name);
|
|
26
|
+
if (!dataset)
|
|
27
|
+
throw new NotFoundError(`dataset "${this.name}" not found in this project`);
|
|
28
|
+
this.datasetCache = dataset;
|
|
29
|
+
return dataset;
|
|
30
|
+
}
|
|
31
|
+
/** Queries dataset rows with optional filter/sort/paging. */
|
|
32
|
+
async rows(options = {}) {
|
|
33
|
+
const dataset = await this.meta();
|
|
34
|
+
warnIfFlagged('QueryDataset');
|
|
35
|
+
const result = await ops.queryDataset(this.transport, {
|
|
36
|
+
input: {
|
|
37
|
+
projectId: await this.projectId(),
|
|
38
|
+
datasetId: dataset.id,
|
|
39
|
+
pageSize: options.pageSize ?? 100,
|
|
40
|
+
pageOffset: options.pageOffset ?? 0,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
return hydrateRows(result);
|
|
44
|
+
}
|
|
45
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Base class for all errors thrown by the WhoDB SDK. */
|
|
2
|
+
export declare class WhoDBError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/** Authentication failed: missing, invalid, expired, or revoked credentials. */
|
|
6
|
+
export declare class AuthError extends WhoDBError {
|
|
7
|
+
}
|
|
8
|
+
/** The requested resource does not exist or the caller cannot see it. */
|
|
9
|
+
export declare class NotFoundError extends WhoDBError {
|
|
10
|
+
}
|
|
11
|
+
/** The request was rejected as invalid before execution. */
|
|
12
|
+
export declare class ValidationError extends WhoDBError {
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* This SDK release was generated against an older platform API and the
|
|
16
|
+
* operation no longer exists. The only fix is upgrading the package.
|
|
17
|
+
*/
|
|
18
|
+
export declare class WhoDBVersionError extends WhoDBError {
|
|
19
|
+
}
|
|
20
|
+
/** The whodb CLI credential helper is unavailable or not logged in. */
|
|
21
|
+
export declare class CliCredentialsError extends WhoDBError {
|
|
22
|
+
}
|
|
23
|
+
/** An operation is not available over the current transport (e.g. IPC). */
|
|
24
|
+
export declare class TransportCapabilityError extends WhoDBError {
|
|
25
|
+
}
|
|
26
|
+
/** Any other platform-reported error, carrying the GraphQL error code. */
|
|
27
|
+
export declare class PlatformError extends WhoDBError {
|
|
28
|
+
readonly code: string;
|
|
29
|
+
constructor(message: string, code: string);
|
|
30
|
+
}
|
|
31
|
+
interface GraphQLErrorShape {
|
|
32
|
+
message: string;
|
|
33
|
+
extensions?: {
|
|
34
|
+
code?: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Maps a GraphQL errors array to the SDK error taxonomy. The first error
|
|
39
|
+
* decides the type; its code is preserved on PlatformError for callers that
|
|
40
|
+
* need to branch on specifics.
|
|
41
|
+
*/
|
|
42
|
+
export declare function mapGraphQLErrors(errors: GraphQLErrorShape[]): WhoDBError;
|
|
43
|
+
export {};
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Base class for all errors thrown by the WhoDB SDK. */
|
|
2
|
+
export class WhoDBError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = new.target.name;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Authentication failed: missing, invalid, expired, or revoked credentials. */
|
|
9
|
+
export class AuthError extends WhoDBError {
|
|
10
|
+
}
|
|
11
|
+
/** The requested resource does not exist or the caller cannot see it. */
|
|
12
|
+
export class NotFoundError extends WhoDBError {
|
|
13
|
+
}
|
|
14
|
+
/** The request was rejected as invalid before execution. */
|
|
15
|
+
export class ValidationError extends WhoDBError {
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* This SDK release was generated against an older platform API and the
|
|
19
|
+
* operation no longer exists. The only fix is upgrading the package.
|
|
20
|
+
*/
|
|
21
|
+
export class WhoDBVersionError extends WhoDBError {
|
|
22
|
+
}
|
|
23
|
+
/** The whodb CLI credential helper is unavailable or not logged in. */
|
|
24
|
+
export class CliCredentialsError extends WhoDBError {
|
|
25
|
+
}
|
|
26
|
+
/** An operation is not available over the current transport (e.g. IPC). */
|
|
27
|
+
export class TransportCapabilityError extends WhoDBError {
|
|
28
|
+
}
|
|
29
|
+
/** Any other platform-reported error, carrying the GraphQL error code. */
|
|
30
|
+
export class PlatformError extends WhoDBError {
|
|
31
|
+
code;
|
|
32
|
+
constructor(message, code) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.code = code;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Maps a GraphQL errors array to the SDK error taxonomy. The first error
|
|
39
|
+
* decides the type; its code is preserved on PlatformError for callers that
|
|
40
|
+
* need to branch on specifics.
|
|
41
|
+
*/
|
|
42
|
+
export function mapGraphQLErrors(errors) {
|
|
43
|
+
const first = errors[0] ?? { message: 'unknown platform error' };
|
|
44
|
+
const code = first.extensions?.code ?? '';
|
|
45
|
+
const message = first.message;
|
|
46
|
+
switch (code) {
|
|
47
|
+
case 'UNAUTHENTICATED':
|
|
48
|
+
return new AuthError(message);
|
|
49
|
+
case 'FORBIDDEN':
|
|
50
|
+
return new AuthError(message);
|
|
51
|
+
case 'NOT_FOUND':
|
|
52
|
+
return new NotFoundError(message);
|
|
53
|
+
case 'BAD_USER_INPUT':
|
|
54
|
+
case 'GRAPHQL_VALIDATION_FAILED':
|
|
55
|
+
return new ValidationError(message);
|
|
56
|
+
default:
|
|
57
|
+
return new PlatformError(message, code);
|
|
58
|
+
}
|
|
59
|
+
}
|
package/dist/files.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CredentialProvider } from './auth.js';
|
|
2
|
+
/** Options for the files facade. */
|
|
3
|
+
export interface FilesOptions {
|
|
4
|
+
host: string;
|
|
5
|
+
credentials: CredentialProvider;
|
|
6
|
+
orgId: () => Promise<string>;
|
|
7
|
+
projectId: () => Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
/** Metadata returned after uploading a file. */
|
|
10
|
+
export interface UploadedFile {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* FilesHandle wraps the platform's file HTTP endpoints — bulk payloads are
|
|
16
|
+
* deliberately not squeezed through GraphQL (SDK_DESIGN.md §4).
|
|
17
|
+
*/
|
|
18
|
+
export declare class FilesHandle {
|
|
19
|
+
private readonly options;
|
|
20
|
+
constructor(options: FilesOptions);
|
|
21
|
+
/** Uploads a file (multipart) into the project's file storage. */
|
|
22
|
+
upload(name: string, content: Blob | Uint8Array | string, folderId?: string): Promise<UploadedFile>;
|
|
23
|
+
/** Downloads a project file's raw bytes. */
|
|
24
|
+
download(fileId: string): Promise<Uint8Array>;
|
|
25
|
+
}
|