@hyperscale0/sdk 3.0.0 → 3.2.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 CHANGED
@@ -1,25 +1,74 @@
1
1
  # @hyperscale0/sdk
2
2
 
3
3
  One client for every Hyperscale Product. Platform types ship with the package.
4
- Instrument fields and public action inputs come from the admitted Build at runtime.
4
+ Object kinds, fields and action availability come from the admitted Build at runtime.
5
5
 
6
6
  ```js
7
7
  import { createClient } from "@hyperscale0/sdk";
8
8
 
9
+ const productId = process.env.HYPERSCALE_PRODUCT_ID;
9
10
  const client = createClient({
10
11
  apiKey: process.env.HYPERSCALE_API_KEY,
11
- productId: process.env.HYPERSCALE_PRODUCT_ID,
12
+ productId,
12
13
  });
13
- const { instruments, actions } = await client.discover();
14
+ const discovery = await client.call("product.objects.discover", { productId });
15
+ // Choose a kind and supply metadata according to its createSchema.
16
+ const kind = discovery.kinds[0].kind;
17
+ const object = await client.call(
18
+ "product.objects.create",
19
+ { productId, kind },
20
+ {
21
+ idempotencyKey: "object-create-001",
22
+ },
23
+ );
24
+ const available = await client.call("product.objects.actions", {
25
+ productId,
26
+ kind,
27
+ objectId: object.objectId,
28
+ });
29
+ ```
30
+
31
+ Choose the intended action by name. Check `availability.status` and collect its
32
+ `requiredNow` fields and requirements against `fieldsSchema` and `inputSchema`.
33
+ After that review, execute it with the complete context returned by the server:
34
+
35
+ ```js
36
+ const action = available.actions.find((item) => item.name === chosenActionName);
37
+ if (!action || action.availability.status !== "available") {
38
+ throw new Error("The selected action is unavailable");
39
+ }
40
+ const result = await client.call(
41
+ "product.objects.execute",
42
+ {
43
+ productId,
44
+ kind,
45
+ objectId: object.objectId,
46
+ action: action.name,
47
+ expectedRevision: available.revision,
48
+ productBuildId: action.productBuildId,
49
+ digest: action.digest,
50
+ target: action.target,
51
+ fields: collectedFields,
52
+ input: collectedInput,
53
+ },
54
+ { idempotencyKey: "object-action-001" },
55
+ );
14
56
  ```
15
57
 
16
- Use `client.call(operationName, input, { idempotencyKey })` for platform operations.
17
- Their names and types match the operation descriptors.
58
+ `chosenActionName`, `collectedFields` and `collectedInput` are application inputs
59
+ from that review. Object creation does not create an agreement or move money.
60
+ Use `product.objects.list` and `product.objects.retrieve` to read stored objects.
61
+ These six operations use the descriptor-backed generic operation transport in
62
+ `client.call`. Names and types match the operation descriptors.
63
+
64
+ Copy the whole target, including `instanceId` when present. Refresh availability
65
+ after a revision or Build conflict. Reuse the same key and body for an uncertain
66
+ request. The client never retries a mutation automatically.
18
67
 
19
- Call `client.act(name, input, { idempotencyKey })` with an action name and input
20
- from discovery. Reuse the same idempotency key and input when retrying a request.
21
- The client never retries a mutation automatically. Keys stay in your environment.
22
- Set `baseUrl` and `environment` to select an estate and sandbox or live plane.
68
+ Low-level `instruments()`, `actions()` and `act()` remain for admitted inspection
69
+ and operations. Instrument creation stays internal to object attachment execution.
70
+ Keys stay in your environment. Set `baseUrl` and `environment` to select an estate
71
+ and sandbox or live plane.
23
72
 
24
73
  Security: https://hyperscale0.ai/security
25
74
 
package/client.d.ts CHANGED
@@ -5,8 +5,15 @@ import type {
5
5
  } from "./platform.js";
6
6
  export type * from "./platform.js";
7
7
 
8
+ import type {
9
+ sandbox_rehearsal_createOutput,
10
+ payment_reminder_delivery_retrieveOutput,
11
+ } from "./portal.js";
12
+
8
13
  export interface ClientOptions {
9
- apiKey: string;
14
+ apiKey?: string;
15
+ sessionToken?: string;
16
+ staffTenantId?: string;
10
17
  productId: string;
11
18
  baseUrl?: string;
12
19
  environment?: "sandbox" | "live";
@@ -18,6 +25,13 @@ export interface ActionInput {
18
25
  input?: Record<string, unknown>;
19
26
  }
20
27
  export interface Client {
28
+ rehearse(
29
+ name: string,
30
+ options: { idempotencyKey: string },
31
+ ): Promise<sandbox_rehearsal_createOutput>;
32
+ reminderDelivery(
33
+ operationId: string,
34
+ ): Promise<payment_reminder_delivery_retrieveOutput>;
21
35
  discover(): Promise<{
22
36
  instruments: product_instruments_listOutput;
23
37
  actions: product_actions_listOutput;
package/client.js CHANGED
@@ -1,11 +1,20 @@
1
1
  export function createClient({
2
2
  apiKey,
3
+ sessionToken,
4
+ staffTenantId,
3
5
  productId,
4
6
  baseUrl = "https://hyperscale0.ai",
5
7
  environment = "sandbox",
6
8
  }) {
7
- if (!apiKey || !productId)
8
- throw new Error("apiKey and productId are required");
9
+ if (
10
+ !apiKey === !sessionToken ||
11
+ !productId ||
12
+ (staffTenantId && !sessionToken)
13
+ )
14
+ throw new Error(
15
+ "Choose one API key or session token and a Product; staff requires a session",
16
+ );
17
+ const credential = sessionToken ?? apiKey;
9
18
  const origin = new URL(baseUrl);
10
19
  if (
11
20
  origin.origin !== baseUrl ||
@@ -22,7 +31,7 @@ export function createClient({
22
31
  const response = await fetch(new URL(path, origin), {
23
32
  method: input === undefined ? "GET" : "POST",
24
33
  headers: {
25
- authorization: `Bearer ${apiKey}`,
34
+ authorization: `Bearer ${credential}`,
26
35
  "x-hyperscale-environment": environment,
27
36
  ...(input === undefined ? {} : { "content-type": "application/json" }),
28
37
  ...(idempotencyKey ? { "idempotency-key": idempotencyKey } : {}),
@@ -38,13 +47,34 @@ export function createClient({
38
47
  );
39
48
  error.status = response.status;
40
49
  error.code = result?.error?.code;
50
+ error.details = result?.error?.details;
41
51
  error.requestId = response.headers.get("x-request-id");
42
52
  throw error;
43
53
  }
44
54
  return result;
45
55
  }
46
56
  const productPath = `/v1/products/${encodeURIComponent(productId)}`;
57
+ const actionPath = staffTenantId
58
+ ? `/v1/admin/tenants/${encodeURIComponent(staffTenantId)}/products/${encodeURIComponent(productId)}/operations`
59
+ : sessionToken
60
+ ? `${productPath}/operations`
61
+ : "/v1/operations";
47
62
  return {
63
+ rehearse: (name, { idempotencyKey } = {}) => {
64
+ if (!sessionToken || staffTenantId || !idempotencyKey)
65
+ throw new Error(
66
+ "rehearse requires a tenant session and idempotency key",
67
+ );
68
+ return request(
69
+ "/v1/sandbox/rehearsals",
70
+ { productId, name },
71
+ idempotencyKey,
72
+ );
73
+ },
74
+ reminderDelivery: (operationId) =>
75
+ request(
76
+ `${productPath}/payment-reminders/${encodeURIComponent(operationId)}`,
77
+ ),
48
78
  discover: async () => {
49
79
  const [instruments, actions] = await Promise.all([
50
80
  request(`${productPath}/instruments`),
@@ -71,7 +101,7 @@ export function createClient({
71
101
  if (!idempotencyKey)
72
102
  throw new Error("act requires an idempotencyKey for safe retries");
73
103
  return request(
74
- `/v1/operations/${encodeURIComponent(name)}`,
104
+ `${actionPath}/${encodeURIComponent(name)}`,
75
105
  input,
76
106
  idempotencyKey,
77
107
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperscale0/sdk",
3
- "version": "3.0.0",
3
+ "version": "3.2.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "LicenseRef-Hyperscale-Proprietary",
@@ -22,5 +22,5 @@
22
22
  "publishConfig": {
23
23
  "access": "public"
24
24
  },
25
- "gitHead": "ceeb9999f9724709720171ecbd457ac180941901"
25
+ "gitHead": "a238da0dbb6ed4e454852cf7f8dbdf1015520d18"
26
26
  }