oneclient 0.1.0 → 0.1.2
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 +52 -22
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +15 -0
- package/dist/index.js +100 -17
- package/dist/platform-auth.d.ts.map +1 -1
- package/dist/platform-auth.js +2 -0
- package/llms.txt +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,44 +1,74 @@
|
|
|
1
1
|
# oneclient
|
|
2
2
|
|
|
3
|
-
One package for the complete OneClient TypeScript SDK and
|
|
3
|
+
One package for the complete OneClient TypeScript SDK and developer CLI.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install oneclient
|
|
7
7
|
npx oneclient login --email you@company.com
|
|
8
|
-
npx oneclient init
|
|
8
|
+
npx oneclient init --project-name "My app"
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The
|
|
11
|
+
The hosted CLI already knows the production control API. Set `ONECLIENT_API_URL` only when a command
|
|
12
|
+
targets a project environment or a self-hosted/local control plane.
|
|
13
|
+
|
|
14
|
+
## Browser application
|
|
15
|
+
|
|
16
|
+
`oneclient init` shows the development API URL, environment ID, and initial `pk_*`/`sk_*` values
|
|
17
|
+
once. A publishable key is safe to embed in browser code; server and deploy keys are not.
|
|
12
18
|
|
|
13
19
|
```ts
|
|
14
20
|
import { createClient } from "oneclient";
|
|
15
21
|
|
|
16
22
|
const one = createClient({
|
|
17
|
-
baseUrl:
|
|
18
|
-
|
|
23
|
+
baseUrl: import.meta.env.VITE_ONECLIENT_API_URL,
|
|
24
|
+
publishableKey: import.meta.env.VITE_ONECLIENT_PUBLISHABLE_KEY,
|
|
19
25
|
});
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
await one.auth.sendOtp({ email: "developer@example.com" });
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Schema, policy, and local auth origin
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
export ONECLIENT_API_URL=https://dev_REFERENCE.api.one-client.com
|
|
34
|
+
export ONECLIENT_SERVER_KEY=sk_REDACTED
|
|
35
|
+
|
|
36
|
+
npx oneclient sql --file migrations/001_create_feedback.sql
|
|
37
|
+
npx oneclient policy:publish --table feedback --file oneclient.policy.json
|
|
38
|
+
npx oneclient auth-origin:add --environment env_DEVELOPMENT --origin http://localhost:5173
|
|
22
39
|
```
|
|
23
40
|
|
|
24
|
-
|
|
41
|
+
Each SQL file contains one statement so its read, write, and retained-storage bounds are explicit.
|
|
42
|
+
|
|
43
|
+
## Development deployment
|
|
25
44
|
|
|
26
45
|
```bash
|
|
27
|
-
|
|
28
|
-
oneclient
|
|
29
|
-
|
|
30
|
-
oneclient
|
|
31
|
-
oneclient
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
npm run build
|
|
47
|
+
npx oneclient artifact:create \
|
|
48
|
+
--directory . \
|
|
49
|
+
--manifest .oneclient/manifest.json \
|
|
50
|
+
--archive .oneclient/app.tar \
|
|
51
|
+
--framework vite \
|
|
52
|
+
--build-command "npm run build" \
|
|
53
|
+
--output-directory dist \
|
|
54
|
+
--lockfile npm
|
|
55
|
+
|
|
56
|
+
npx oneclient deploy-token:create --environment env_DEVELOPMENT --name local-cli
|
|
57
|
+
export ONECLIENT_DEPLOY_TOKEN=dp_VALUE_SHOWN_ONCE
|
|
58
|
+
npx oneclient deploy \
|
|
59
|
+
--manifest .oneclient/manifest.json \
|
|
60
|
+
--archive .oneclient/app.tar \
|
|
61
|
+
--project prj_PROJECT \
|
|
62
|
+
--environment env_DEVELOPMENT \
|
|
63
|
+
--wait
|
|
64
|
+
|
|
65
|
+
# The deploy token is an environment key; revoke it by the id returned at creation.
|
|
66
|
+
npx oneclient key:revoke --environment env_DEVELOPMENT --key key_DEPLOY_TOKEN
|
|
36
67
|
```
|
|
37
68
|
|
|
38
|
-
Interactive terminals receive a compact
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
persisted by the CLI.
|
|
69
|
+
Interactive terminals receive a compact interface. Pipes and CI receive stable JSON automatically;
|
|
70
|
+
`--json` makes that behavior explicit. Developer sessions are stored in an owner-only local file.
|
|
71
|
+
`sk_*` and `dp_*` values stay in environment variables and are never persisted by the CLI.
|
|
42
72
|
|
|
43
|
-
|
|
44
|
-
[one-client.com/llms.txt](https://one-client.com/llms.txt)
|
|
73
|
+
Full quickstart: [one-client.com/docs/quickstart](https://one-client.com/docs/quickstart) · Agent
|
|
74
|
+
context: [one-client.com/llms.txt](https://one-client.com/llms.txt)
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const DEFAULT_CONTROL_API_URL = "https://control.one-client.com";
|
|
2
|
+
export declare const DEFAULT_CONSOLE_ORIGIN = "https://console.one-client.com";
|
|
3
|
+
export declare function developerAuthOrigin(apiUrl: string): string;
|
|
4
|
+
export declare function inferOrganizationId(explicitId: string | undefined, organizations: Array<{
|
|
5
|
+
id: string;
|
|
6
|
+
}>): string;
|
|
7
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,mCAAmC,CAAC;AACxE,eAAO,MAAM,sBAAsB,mCAAmC,CAAC;AAEvE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,aAAa,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,GACnC,MAAM,CAMR"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const DEFAULT_CONTROL_API_URL = "https://control.one-client.com";
|
|
2
|
+
export const DEFAULT_CONSOLE_ORIGIN = "https://console.one-client.com";
|
|
3
|
+
export function developerAuthOrigin(apiUrl) {
|
|
4
|
+
const origin = new URL(apiUrl).origin;
|
|
5
|
+
return origin === DEFAULT_CONTROL_API_URL ? DEFAULT_CONSOLE_ORIGIN : origin;
|
|
6
|
+
}
|
|
7
|
+
export function inferOrganizationId(explicitId, organizations) {
|
|
8
|
+
if (explicitId)
|
|
9
|
+
return explicitId;
|
|
10
|
+
if (organizations.length === 1)
|
|
11
|
+
return organizations[0].id;
|
|
12
|
+
if (organizations.length === 0)
|
|
13
|
+
throw new Error("Create an organization with `oneclient organization:create` first");
|
|
14
|
+
throw new Error("This account has multiple organizations; pass --organization <id>");
|
|
15
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -14,11 +14,12 @@ import { deployTokenFromEnvironment, parseServerKeyScopes, serverKeyFromEnvironm
|
|
|
14
14
|
import { secretValueFromOptions } from "./secret-input.js";
|
|
15
15
|
import { brand, formatOutput, statusLine } from "./presenter.js";
|
|
16
16
|
import { slugify } from "./slug.js";
|
|
17
|
+
import { DEFAULT_CONTROL_API_URL, inferOrganizationId } from "./config.js";
|
|
17
18
|
const program = new Command();
|
|
18
19
|
program
|
|
19
20
|
.name("oneclient")
|
|
20
21
|
.description("Deploy and manage OneClient projects")
|
|
21
|
-
.version("0.1.
|
|
22
|
+
.version("0.1.2")
|
|
22
23
|
.option("--api-url <url>", "Control or environment API URL", process.env.ONECLIENT_API_URL)
|
|
23
24
|
.option("--organization <id>", "Organization ID", process.env.ONECLIENT_ORGANIZATION_ID)
|
|
24
25
|
.option("--json", "Print stable JSON for scripts and agents", false)
|
|
@@ -29,7 +30,7 @@ program
|
|
|
29
30
|
.description("Sign in as a platform developer with an email OTP")
|
|
30
31
|
.requiredOption("--email <email>")
|
|
31
32
|
.action(async (options) => {
|
|
32
|
-
const apiUrl = await
|
|
33
|
+
const apiUrl = await resolveControlApiUrl();
|
|
33
34
|
await runStep(`Sending a private sign-in code to ${options.email.trim()}`, () => sendDeveloperOtp(apiUrl, options.email));
|
|
34
35
|
const otp = process.env.ONECLIENT_OTP ?? (await promptForOtp());
|
|
35
36
|
const sessionToken = await runStep("Verifying your code", () => verifyDeveloperOtp(apiUrl, options.email, otp));
|
|
@@ -114,7 +115,7 @@ program
|
|
|
114
115
|
program
|
|
115
116
|
.command("projects")
|
|
116
117
|
.description("List projects")
|
|
117
|
-
.action(async () => print(await
|
|
118
|
+
.action(async () => print(await organizationSessionClient().then((api) => api.projects.list()), "Projects"));
|
|
118
119
|
program
|
|
119
120
|
.command("project:create")
|
|
120
121
|
.description("Create a project and its development and production environments")
|
|
@@ -154,7 +155,7 @@ program
|
|
|
154
155
|
program
|
|
155
156
|
.command("usage")
|
|
156
157
|
.description("Show the prepaid wallet and retention reserve")
|
|
157
|
-
.action(async () => print(await
|
|
158
|
+
.action(async () => print(await organizationSessionClient().then((api) => api.usage.summary()), "Usage & balance"));
|
|
158
159
|
program
|
|
159
160
|
.command("status")
|
|
160
161
|
.description("Show account, organization, project, and spend status in one view")
|
|
@@ -198,7 +199,7 @@ program
|
|
|
198
199
|
const limit = Number(options.limit);
|
|
199
200
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
200
201
|
throw new Error("limit must be an integer from 1 through 100");
|
|
201
|
-
print(await
|
|
202
|
+
print(await organizationSessionClient().then((api) => api.usage.activity(limit)), "Recent activity");
|
|
202
203
|
});
|
|
203
204
|
program
|
|
204
205
|
.command("deployments")
|
|
@@ -213,7 +214,9 @@ program
|
|
|
213
214
|
.command("doctor")
|
|
214
215
|
.description("Check local credentials and live OneClient connectivity")
|
|
215
216
|
.action(async () => {
|
|
217
|
+
const options = program.opts();
|
|
216
218
|
const credentials = await resolvedDeveloperCredentials();
|
|
219
|
+
const controlApi = options.apiUrl ?? credentials?.apiUrl ?? DEFAULT_CONTROL_API_URL;
|
|
217
220
|
let account = null;
|
|
218
221
|
let controlReachable = false;
|
|
219
222
|
if (credentials) {
|
|
@@ -221,9 +224,20 @@ program
|
|
|
221
224
|
account = response.user.email;
|
|
222
225
|
controlReachable = true;
|
|
223
226
|
}
|
|
227
|
+
else {
|
|
228
|
+
try {
|
|
229
|
+
const response = await fetch(new URL("/v1/me", `${controlApi}/`), {
|
|
230
|
+
headers: { Accept: "application/json" },
|
|
231
|
+
});
|
|
232
|
+
controlReachable = response.status < 500;
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
controlReachable = false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
224
238
|
print({
|
|
225
239
|
node: process.version,
|
|
226
|
-
controlApi
|
|
240
|
+
controlApi,
|
|
227
241
|
signedIn: Boolean(credentials),
|
|
228
242
|
account,
|
|
229
243
|
controlReachable,
|
|
@@ -255,11 +269,11 @@ program
|
|
|
255
269
|
program
|
|
256
270
|
.command("billing:portal")
|
|
257
271
|
.description("Create a secure Stripe billing-portal session")
|
|
258
|
-
.action(async () => print(await
|
|
272
|
+
.action(async () => print(await organizationSessionClient().then((api) => api.billing.portal()), "Billing portal"));
|
|
259
273
|
program
|
|
260
274
|
.command("billing:subscribe")
|
|
261
275
|
.description("Create a subscription Checkout session")
|
|
262
|
-
.action(async () => print(await
|
|
276
|
+
.action(async () => print(await organizationSessionClient().then((api) => api.billing.subscriptionCheckout()), "Subscription checkout"));
|
|
263
277
|
program
|
|
264
278
|
.command("billing:topup")
|
|
265
279
|
.description("Create a prepaid credit Checkout session")
|
|
@@ -269,12 +283,12 @@ program
|
|
|
269
283
|
if (!Number.isFinite(dollars) || dollars < 25 || Math.round(dollars * 100) !== dollars * 100)
|
|
270
284
|
throw new Error("usd must be at least 25 with no more than two decimal places");
|
|
271
285
|
const amountMicros = String(Math.round(dollars * 1_000_000));
|
|
272
|
-
print(await
|
|
286
|
+
print(await organizationSessionClient().then((api) => api.billing.topupCheckout(amountMicros)), "Credit checkout");
|
|
273
287
|
});
|
|
274
288
|
program
|
|
275
289
|
.command("domain:list")
|
|
276
290
|
.description("List application, API, and sending domains")
|
|
277
|
-
.action(async () => print(await
|
|
291
|
+
.action(async () => print(await organizationSessionClient().then((api) => api.domains.list()), "Domains"));
|
|
278
292
|
program
|
|
279
293
|
.command("domain:add")
|
|
280
294
|
.description("Attach a custom hostname")
|
|
@@ -372,6 +386,53 @@ program
|
|
|
372
386
|
.limit(Number(options.limit))
|
|
373
387
|
.execute()));
|
|
374
388
|
});
|
|
389
|
+
program
|
|
390
|
+
.command("sql")
|
|
391
|
+
.description("Execute one bounded SQL statement or trusted server query from a file")
|
|
392
|
+
.requiredOption("--file <path>")
|
|
393
|
+
.option("--max-rows-read <rows>", "Maximum rows the statement may read", "1000")
|
|
394
|
+
.option("--max-rows-written <rows>", "Maximum rows the statement may write", "100")
|
|
395
|
+
.option("--max-storage-delta-bytes <bytes>", "Maximum retained storage increase", "65536")
|
|
396
|
+
.action(async (options) => {
|
|
397
|
+
const maxRowsRead = positiveInteger(options.maxRowsRead, "max-rows-read");
|
|
398
|
+
const maxRowsWritten = positiveInteger(options.maxRowsWritten, "max-rows-written");
|
|
399
|
+
const maxStorageDeltaBytes = nonNegativeInteger(options.maxStorageDeltaBytes, "max-storage-delta-bytes");
|
|
400
|
+
const sql = (await readFile(options.file, "utf8")).trim();
|
|
401
|
+
if (!sql)
|
|
402
|
+
throw new Error("SQL file cannot be empty");
|
|
403
|
+
print(await serverClient().then((api) => api.sql.execute({
|
|
404
|
+
sql,
|
|
405
|
+
maxRowsRead,
|
|
406
|
+
maxRowsWritten,
|
|
407
|
+
maxStorageDeltaBytes,
|
|
408
|
+
})), "SQL completed");
|
|
409
|
+
});
|
|
410
|
+
program
|
|
411
|
+
.command("policy:publish")
|
|
412
|
+
.description("Validate and activate a deny-by-default data policy from a JSON file")
|
|
413
|
+
.requiredOption("--table <table>")
|
|
414
|
+
.requiredOption("--file <path>")
|
|
415
|
+
.action(async (options) => {
|
|
416
|
+
const policy = JSON.parse(await readFile(options.file, "utf8"));
|
|
417
|
+
print(await serverClient().then((api) => api.data.publishPolicy(options.table, policy)), "Policy activated");
|
|
418
|
+
});
|
|
419
|
+
program
|
|
420
|
+
.command("auth-origin:list")
|
|
421
|
+
.description("List trusted browser and native authentication origins")
|
|
422
|
+
.requiredOption("--environment <id>")
|
|
423
|
+
.action(async (options) => print(await sessionClient().then((api) => api.authOrigins.list(options.environment))));
|
|
424
|
+
program
|
|
425
|
+
.command("auth-origin:add")
|
|
426
|
+
.description("Trust a browser origin or native application scheme for authentication")
|
|
427
|
+
.requiredOption("--environment <id>")
|
|
428
|
+
.requiredOption("--origin <origin>")
|
|
429
|
+
.action(async (options) => print(await sessionClient().then((api) => api.authOrigins.create(options.environment, options.origin)), "Authentication origin added"));
|
|
430
|
+
program
|
|
431
|
+
.command("auth-origin:delete")
|
|
432
|
+
.description("Remove a trusted authentication origin")
|
|
433
|
+
.requiredOption("--environment <id>")
|
|
434
|
+
.requiredOption("--origin-id <id>")
|
|
435
|
+
.action(async (options) => print(await sessionClient().then((api) => api.authOrigins.delete(options.environment, options.originId))));
|
|
375
436
|
program
|
|
376
437
|
.command("artifact:create")
|
|
377
438
|
.description("Create a validated manifest and tar archive from a project directory")
|
|
@@ -511,13 +572,21 @@ async function sessionClient(organizationId) {
|
|
|
511
572
|
: {}),
|
|
512
573
|
});
|
|
513
574
|
}
|
|
575
|
+
async function organizationSessionClient() {
|
|
576
|
+
const explicitId = program.opts().organization;
|
|
577
|
+
if (explicitId)
|
|
578
|
+
return sessionClient(explicitId);
|
|
579
|
+
const base = await sessionClient();
|
|
580
|
+
const organizations = await base.organizations.list();
|
|
581
|
+
return sessionClient(inferOrganizationId(undefined, organizations));
|
|
582
|
+
}
|
|
514
583
|
async function deployClient() {
|
|
515
584
|
const options = program.opts();
|
|
516
585
|
const deployToken = deployTokenFromEnvironment();
|
|
517
586
|
if (!deployToken?.startsWith("dp_"))
|
|
518
587
|
throw new Error("This command requires ONECLIENT_DEPLOY_TOKEN with a dp_* token");
|
|
519
588
|
return createClient({
|
|
520
|
-
baseUrl: await
|
|
589
|
+
baseUrl: await resolveControlApiUrl(),
|
|
521
590
|
deployToken,
|
|
522
591
|
...(options.organization ? { organizationId: options.organization } : {}),
|
|
523
592
|
});
|
|
@@ -528,7 +597,7 @@ async function serverClient() {
|
|
|
528
597
|
if (!serverKey?.startsWith("sk_"))
|
|
529
598
|
throw new Error("This command requires ONECLIENT_SERVER_KEY with an sk_* key");
|
|
530
599
|
return createClient({
|
|
531
|
-
baseUrl:
|
|
600
|
+
baseUrl: resolveEnvironmentApiUrl(),
|
|
532
601
|
serverKey,
|
|
533
602
|
...(options.organization ? { organizationId: options.organization } : {}),
|
|
534
603
|
});
|
|
@@ -539,18 +608,32 @@ async function resolvedDeveloperCredentials() {
|
|
|
539
608
|
const sessionToken = process.env.ONECLIENT_SESSION_TOKEN ?? stored?.sessionToken;
|
|
540
609
|
if (!sessionToken)
|
|
541
610
|
return null;
|
|
542
|
-
const apiUrl = options.apiUrl ?? stored?.apiUrl;
|
|
543
|
-
if (!apiUrl)
|
|
544
|
-
throw new Error("Set ONECLIENT_API_URL or pass --api-url");
|
|
611
|
+
const apiUrl = options.apiUrl ?? stored?.apiUrl ?? DEFAULT_CONTROL_API_URL;
|
|
545
612
|
return { apiUrl, sessionToken };
|
|
546
613
|
}
|
|
547
|
-
async function
|
|
614
|
+
async function resolveControlApiUrl() {
|
|
548
615
|
const options = program.opts();
|
|
549
616
|
const apiUrl = options.apiUrl ?? (await readDeveloperCredentials())?.apiUrl;
|
|
617
|
+
return apiUrl ?? DEFAULT_CONTROL_API_URL;
|
|
618
|
+
}
|
|
619
|
+
function resolveEnvironmentApiUrl() {
|
|
620
|
+
const apiUrl = program.opts().apiUrl;
|
|
550
621
|
if (!apiUrl)
|
|
551
|
-
throw new Error("Set ONECLIENT_API_URL or pass --api-url");
|
|
622
|
+
throw new Error("Set ONECLIENT_API_URL to the environment API URL or pass --api-url https://<environment>.api.one-client.com");
|
|
552
623
|
return apiUrl;
|
|
553
624
|
}
|
|
625
|
+
function positiveInteger(value, name) {
|
|
626
|
+
const parsed = Number(value);
|
|
627
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1)
|
|
628
|
+
throw new Error(`${name} must be a positive integer`);
|
|
629
|
+
return parsed;
|
|
630
|
+
}
|
|
631
|
+
function nonNegativeInteger(value, name) {
|
|
632
|
+
const parsed = Number(value);
|
|
633
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0)
|
|
634
|
+
throw new Error(`${name} must be a non-negative integer`);
|
|
635
|
+
return parsed;
|
|
636
|
+
}
|
|
554
637
|
async function promptForOtp() {
|
|
555
638
|
if (!process.stdin.isTTY)
|
|
556
639
|
throw new Error("Set ONECLIENT_OTP for a non-interactive login");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-auth.d.ts","sourceRoot":"","sources":["../src/platform-auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"platform-auth.d.ts","sourceRoot":"","sources":["../src/platform-auth.ts"],"names":[],"mappings":"AAQA,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,GAClD,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,GAClD,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,GAClD,OAAO,CAAC,IAAI,CAAC,CAEf"}
|
package/dist/platform-auth.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { validateApiUrl } from "./credentials.js";
|
|
2
|
+
import { developerAuthOrigin } from "./config.js";
|
|
2
3
|
export async function sendDeveloperOtp(apiUrl, email, fetcher = globalThis.fetch) {
|
|
3
4
|
await authRequest(fetcher, apiUrl, "/v1/platform/auth/email-otp/send-verification-otp", {
|
|
4
5
|
email: normalizeEmail(email),
|
|
@@ -24,6 +25,7 @@ async function authRequest(fetcher, apiUrl, path, body, sessionToken) {
|
|
|
24
25
|
headers: {
|
|
25
26
|
Accept: "application/json",
|
|
26
27
|
"Content-Type": "application/json",
|
|
28
|
+
Origin: developerAuthOrigin(apiUrl),
|
|
27
29
|
...(sessionToken ? { Authorization: `Bearer ${sessionToken}` } : {}),
|
|
28
30
|
},
|
|
29
31
|
body: JSON.stringify(body),
|
package/llms.txt
CHANGED
|
@@ -11,6 +11,14 @@ MCP: https://control.one-client.com/mcp
|
|
|
11
11
|
|
|
12
12
|
Install: npm install oneclient
|
|
13
13
|
CLI login: npx oneclient login --email you@company.com
|
|
14
|
+
Control API configuration is automatic for the hosted service.
|
|
15
|
+
|
|
16
|
+
First project flow:
|
|
17
|
+
1. npx oneclient init --project-name "My app"
|
|
18
|
+
2. Capture the shown-once development pk_* and sk_* values.
|
|
19
|
+
3. Apply SQL with `oneclient sql` and policy with `oneclient policy:publish`.
|
|
20
|
+
4. Add local/custom auth origins with `oneclient auth-origin:add`.
|
|
21
|
+
5. Build, run `oneclient artifact:create`, create a dp_* token, then run `oneclient deploy --wait`.
|
|
14
22
|
|
|
15
23
|
Use pk_* only in browser/mobile clients, sk_* only on trusted servers, and dp_* only for deploys.
|
|
16
24
|
Never expose sk_* or dp_* values in client bundles or model output. Every mutation is idempotent and
|