@graph8/sdk 0.13.1 → 0.14.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/dist/react.js CHANGED
@@ -1235,10 +1235,282 @@ var createAppsClient = (apiKey, apiUrl) => {
1235
1235
  };
1236
1236
  };
1237
1237
 
1238
- // src/fields.ts
1238
+ // src/appPlatform.ts
1239
1239
  var DEFAULT_API18 = "https://be.graph8.com";
1240
- var createFieldsClient = (apiKey, apiUrl) => {
1240
+ var createAppPlatformClient = (apiKey, apiUrl) => {
1241
1241
  const baseUrl = apiUrl || DEFAULT_API18;
1242
+ const unwrap = (resp) => resp.data ?? resp;
1243
+ return {
1244
+ // ---- source binding -------------------------------------------------
1245
+ /**
1246
+ * Bind the repository an app builds from.
1247
+ *
1248
+ * `repo_url` must be fetchable -- `https://`, `ssh://` or `git@`, with no
1249
+ * whitespace. A `file://` or bare path is refused with 422, because a build
1250
+ * that can read the builder's filesystem is a build that can read ours.
1251
+ *
1252
+ * `credential_ref` is a POINTER into your secret manager, not a token.
1253
+ */
1254
+ async setSource(appId, params) {
1255
+ const resp = await request(
1256
+ baseUrl,
1257
+ `/api/v1/apps/${appId}/source`,
1258
+ apiKey,
1259
+ {
1260
+ method: "PUT",
1261
+ body: {
1262
+ repo_url: params.repo_url,
1263
+ provider: params.provider,
1264
+ default_branch: params.default_branch ?? null,
1265
+ credential_ref: params.credential_ref ?? null
1266
+ }
1267
+ }
1268
+ );
1269
+ return unwrap(resp);
1270
+ },
1271
+ /** Unbind the source. Returns the full app with every source field null. */
1272
+ async clearSource(appId) {
1273
+ const resp = await request(
1274
+ baseUrl,
1275
+ `/api/v1/apps/${appId}/source`,
1276
+ apiKey,
1277
+ { method: "DELETE" }
1278
+ );
1279
+ return unwrap(resp);
1280
+ },
1281
+ // ---- deployments ----------------------------------------------------
1282
+ /** Every deployment for this app, newest first. Never 404s for an app with none. */
1283
+ async listDeployments(appId) {
1284
+ return request(baseUrl, `/api/v1/apps/${appId}/deployments`, apiKey);
1285
+ },
1286
+ /**
1287
+ * Queue a deployment. Returns `201` with `status: "queued"` -- nothing builds
1288
+ * as a side effect of this call; the build controller picks it up.
1289
+ *
1290
+ * NOT idempotent: two identical calls create two deployments.
1291
+ */
1292
+ async deploy(appId, params) {
1293
+ const body = { source_ref: params.source_ref };
1294
+ if (params.schema_version_id) body.schema_version_id = params.schema_version_id;
1295
+ const resp = await request(
1296
+ baseUrl,
1297
+ `/api/v1/apps/${appId}/deployments`,
1298
+ apiKey,
1299
+ { method: "POST", body }
1300
+ );
1301
+ return unwrap(resp);
1302
+ },
1303
+ /** Fetch one deployment. The polling endpoint for a build loop. */
1304
+ async getDeployment(appId, deploymentId) {
1305
+ const resp = await request(
1306
+ baseUrl,
1307
+ `/api/v1/apps/${appId}/deployments/${deploymentId}`,
1308
+ apiKey
1309
+ );
1310
+ return unwrap(resp);
1311
+ },
1312
+ /**
1313
+ * The deployment currently serving traffic, or `null`.
1314
+ *
1315
+ * `null` is a real answer with a 200, not a 404: "this app has never shipped"
1316
+ * is information, while a 404 would read as "no such app".
1317
+ */
1318
+ async activeDeployment(appId) {
1319
+ const resp = await request(
1320
+ baseUrl,
1321
+ `/api/v1/apps/${appId}/deployments/active`,
1322
+ apiKey
1323
+ );
1324
+ return resp.data ?? null;
1325
+ },
1326
+ /**
1327
+ * Promote a built deployment to serve traffic. Anything it displaces moves to
1328
+ * `rolled_back` in the same transaction, so there is never a moment with two
1329
+ * live deployments.
1330
+ *
1331
+ * `409` when the state machine forbids it -- a deployment cannot become
1332
+ * `deployed` without having been built, and a `failed` one cannot be revived.
1333
+ * A retry is a new deployment, not a resurrection.
1334
+ */
1335
+ async promote(appId, deploymentId, imageDigest) {
1336
+ const resp = await request(
1337
+ baseUrl,
1338
+ `/api/v1/apps/${appId}/deployments/${deploymentId}/promote`,
1339
+ apiKey,
1340
+ { method: "POST", body: { image_digest: imageDigest } }
1341
+ );
1342
+ return unwrap(resp);
1343
+ },
1344
+ /** Roll back a deployment that is currently serving. Only a `deployed` one may be. */
1345
+ async rollback(appId, deploymentId) {
1346
+ const resp = await request(
1347
+ baseUrl,
1348
+ `/api/v1/apps/${appId}/deployments/${deploymentId}/rollback`,
1349
+ apiKey,
1350
+ { method: "POST", body: {} }
1351
+ );
1352
+ return unwrap(resp);
1353
+ },
1354
+ // ---- logs -----------------------------------------------------------
1355
+ /**
1356
+ * Why a build failed. Returns every step of the build pod in the order
1357
+ * Kubernetes runs them; a step that has not started yet is omitted rather
1358
+ * than returned empty.
1359
+ *
1360
+ * An empty `containers` list is not an error -- build pods are reaped an hour
1361
+ * after they finish, so logs for an older deployment are genuinely gone.
1362
+ * `last_error_sanitized` on the deployment is what survives.
1363
+ *
1364
+ * `503` means graph8 could not reach the cluster, which is deliberately
1365
+ * different from an empty `200`: one means we could not look, the other means
1366
+ * your build produced no output.
1367
+ */
1368
+ async deploymentLogs(appId, deploymentId, tailLines) {
1369
+ const resp = await request(
1370
+ baseUrl,
1371
+ `/api/v1/apps/${appId}/deployments/${deploymentId}/logs`,
1372
+ apiKey,
1373
+ { query: tailLines === void 0 ? void 0 : { tail_lines: tailLines } }
1374
+ );
1375
+ return unwrap(resp);
1376
+ },
1377
+ /**
1378
+ * What the running app is printing. The app's own pods only -- the per-app
1379
+ * egress proxy shares the namespace and is deliberately excluded.
1380
+ *
1381
+ * Empty until a deployment reaches `deployed`.
1382
+ */
1383
+ async logs(appId, tailLines) {
1384
+ const resp = await request(
1385
+ baseUrl,
1386
+ `/api/v1/apps/${appId}/logs`,
1387
+ apiKey,
1388
+ { query: tailLines === void 0 ? void 0 : { tail_lines: tailLines } }
1389
+ );
1390
+ return unwrap(resp);
1391
+ },
1392
+ // ---- domains --------------------------------------------------------
1393
+ /** Every hostname claimed for this app, whatever its verification state. */
1394
+ async listDomains(appId) {
1395
+ return request(baseUrl, `/api/v1/apps/${appId}/domains`, apiKey);
1396
+ },
1397
+ /**
1398
+ * Claim a hostname and get the TXT record that proves you own it.
1399
+ *
1400
+ * Returns `201`, and the domain is NESTED at `data.domain` -- this is the one
1401
+ * route on the surface whose payload is not the record itself. Hostnames are
1402
+ * globally unique, so a host another app holds is refused.
1403
+ */
1404
+ async claimDomain(appId, hostname) {
1405
+ const resp = await request(
1406
+ baseUrl,
1407
+ `/api/v1/apps/${appId}/domains`,
1408
+ apiKey,
1409
+ { method: "POST", body: { hostname } }
1410
+ );
1411
+ return unwrap(resp);
1412
+ },
1413
+ /**
1414
+ * Check DNS for the TXT record and advance the domain to `verified`.
1415
+ *
1416
+ * Idempotent: verifying an already-verified domain re-checks and stays
1417
+ * verified, so it is safe to re-run after a DNS change. Send no body -- the
1418
+ * record in DNS is the payload.
1419
+ */
1420
+ async verifyDomain(appId, hostname) {
1421
+ const resp = await request(
1422
+ baseUrl,
1423
+ `/api/v1/apps/${appId}/domains/${encodeURIComponent(hostname)}/verify`,
1424
+ apiKey,
1425
+ { method: "POST", body: {} }
1426
+ );
1427
+ return unwrap(resp);
1428
+ },
1429
+ /**
1430
+ * Release a claimed hostname.
1431
+ *
1432
+ * A HARD delete. Hostnames are globally unique, so a row left behind in any
1433
+ * status keeps the host burned for every other builder. Releasing one you
1434
+ * already released is a `404`, because after the first call the claim
1435
+ * genuinely does not exist.
1436
+ *
1437
+ * Returns the NORMALIZED hostname, which may differ from what you passed.
1438
+ */
1439
+ async releaseDomain(appId, hostname) {
1440
+ const resp = await request(
1441
+ baseUrl,
1442
+ `/api/v1/apps/${appId}/domains/${encodeURIComponent(hostname)}`,
1443
+ apiKey,
1444
+ { method: "DELETE" }
1445
+ );
1446
+ return unwrap(resp);
1447
+ },
1448
+ // ---- secrets --------------------------------------------------------
1449
+ /**
1450
+ * Which secrets this app declares, and when each was last rotated.
1451
+ *
1452
+ * NEVER returns a value. graph8 stores a POINTER into your secret manager and
1453
+ * has no column for the secret itself.
1454
+ */
1455
+ async listSecrets(appId) {
1456
+ return request(baseUrl, `/api/v1/apps/${appId}/secrets`, apiKey);
1457
+ },
1458
+ /**
1459
+ * Declare a secret, or rotate the pointer to it.
1460
+ *
1461
+ * `providerRef` is a REFERENCE, and the server rejects anything that looks
1462
+ * like a credential -- a value starting `bearer `, `sk-`, `ghp_`, `xox` and
1463
+ * friends is a 422. That refusal is the feature: it catches the mistake of
1464
+ * pasting the secret where its address belongs.
1465
+ */
1466
+ async putSecret(appId, secretKey, providerRef) {
1467
+ const resp = await request(
1468
+ baseUrl,
1469
+ `/api/v1/apps/${appId}/secrets/${encodeURIComponent(secretKey)}`,
1470
+ apiKey,
1471
+ { method: "PUT", body: { provider_ref: providerRef ?? null } }
1472
+ );
1473
+ return unwrap(resp);
1474
+ },
1475
+ /** Undeclare a secret. A key the app never declared is a 404, so a typo is
1476
+ * never reported as a successful removal. */
1477
+ async deleteSecret(appId, secretKey) {
1478
+ const resp = await request(
1479
+ baseUrl,
1480
+ `/api/v1/apps/${appId}/secrets/${encodeURIComponent(secretKey)}`,
1481
+ apiKey,
1482
+ { method: "DELETE" }
1483
+ );
1484
+ return unwrap(resp);
1485
+ },
1486
+ // ---- schema versions ------------------------------------------------
1487
+ /**
1488
+ * Publish a custom-object schema version. Returns `201`.
1489
+ *
1490
+ * Takes only the `objects` list, not a whole `graph8.app.yaml`: the rest of
1491
+ * that file is app metadata the control plane already holds, and accepting it
1492
+ * here would create a second place for it to disagree.
1493
+ */
1494
+ async publishSchemaVersion(appId, objects) {
1495
+ const resp = await request(
1496
+ baseUrl,
1497
+ `/api/v1/apps/${appId}/schema-versions`,
1498
+ apiKey,
1499
+ { method: "POST", body: { objects } }
1500
+ );
1501
+ return unwrap(resp);
1502
+ },
1503
+ /** Every schema version this app has published. Empty array, never 404. */
1504
+ async listSchemaVersions(appId) {
1505
+ return request(baseUrl, `/api/v1/apps/${appId}/schema-versions`, apiKey);
1506
+ }
1507
+ };
1508
+ };
1509
+
1510
+ // src/fields.ts
1511
+ var DEFAULT_API19 = "https://be.graph8.com";
1512
+ var createFieldsClient = (apiKey, apiUrl) => {
1513
+ const baseUrl = apiUrl || DEFAULT_API19;
1242
1514
  return {
1243
1515
  /** List contact fields (base + custom). Pass listId to include list-specific custom fields. */
1244
1516
  async listContactFields(listId) {
@@ -1280,9 +1552,9 @@ var createFieldsClient = (apiKey, apiUrl) => {
1280
1552
  };
1281
1553
 
1282
1554
  // src/objects.ts
1283
- var DEFAULT_API19 = "https://be.graph8.com";
1555
+ var DEFAULT_API20 = "https://be.graph8.com";
1284
1556
  var createObjectsClient = (apiKey, apiUrl) => {
1285
- const baseUrl = apiUrl || DEFAULT_API19;
1557
+ const baseUrl = apiUrl || DEFAULT_API20;
1286
1558
  const encode = (value) => encodeURIComponent(value);
1287
1559
  return {
1288
1560
  /** List the custom object types in your workspace. */
@@ -1392,9 +1664,9 @@ var createObjectsClient = (apiKey, apiUrl) => {
1392
1664
  };
1393
1665
 
1394
1666
  // src/deals.ts
1395
- var DEFAULT_API20 = "https://be.graph8.com";
1667
+ var DEFAULT_API21 = "https://be.graph8.com";
1396
1668
  var createDealsClient = (apiKey, apiUrl) => {
1397
- const baseUrl = apiUrl || DEFAULT_API20;
1669
+ const baseUrl = apiUrl || DEFAULT_API21;
1398
1670
  return {
1399
1671
  /** List all deal pipelines and their stages. */
1400
1672
  async pipelines() {
@@ -1438,9 +1710,9 @@ var createDealsClient = (apiKey, apiUrl) => {
1438
1710
  };
1439
1711
 
1440
1712
  // src/inbox.ts
1441
- var DEFAULT_API21 = "https://be.graph8.com";
1713
+ var DEFAULT_API22 = "https://be.graph8.com";
1442
1714
  var createInboxClient = (apiKey, apiUrl) => {
1443
- const baseUrl = apiUrl || DEFAULT_API21;
1715
+ const baseUrl = apiUrl || DEFAULT_API22;
1444
1716
  return {
1445
1717
  /** List inbox threads across email, SMS, and LinkedIn. */
1446
1718
  async list(params = {}) {
@@ -1493,9 +1765,9 @@ var createInboxClient = (apiKey, apiUrl) => {
1493
1765
  };
1494
1766
 
1495
1767
  // src/quotes.ts
1496
- var DEFAULT_API22 = "https://be.graph8.com";
1768
+ var DEFAULT_API23 = "https://be.graph8.com";
1497
1769
  var createQuotesClient = (apiKey, apiUrl) => {
1498
- const baseUrl = apiUrl || DEFAULT_API22;
1770
+ const baseUrl = apiUrl || DEFAULT_API23;
1499
1771
  return {
1500
1772
  /** List quotes org-wide with optional filters and pagination. */
1501
1773
  async list(params = {}) {
@@ -1567,9 +1839,9 @@ var createQuotesClient = (apiKey, apiUrl) => {
1567
1839
  };
1568
1840
 
1569
1841
  // src/pipelines.ts
1570
- var DEFAULT_API23 = "https://be.graph8.com";
1842
+ var DEFAULT_API24 = "https://be.graph8.com";
1571
1843
  var createPipelinesClient = (apiKey, apiUrl) => {
1572
- const baseUrl = apiUrl || DEFAULT_API23;
1844
+ const baseUrl = apiUrl || DEFAULT_API24;
1573
1845
  return {
1574
1846
  /** List all stage-checklist pipelines with stages, evidence, scripts. */
1575
1847
  async list() {
@@ -1651,9 +1923,9 @@ var createPipelinesClient = (apiKey, apiUrl) => {
1651
1923
  };
1652
1924
 
1653
1925
  // src/workflows.ts
1654
- var DEFAULT_API24 = "https://be.graph8.com";
1926
+ var DEFAULT_API25 = "https://be.graph8.com";
1655
1927
  var createWorkflowsClient = (apiKey, apiUrl) => {
1656
- const baseUrl = apiUrl || DEFAULT_API24;
1928
+ const baseUrl = apiUrl || DEFAULT_API25;
1657
1929
  return {
1658
1930
  /** List workflows org-wide. */
1659
1931
  async list(params = {}) {
@@ -1769,9 +2041,9 @@ var createWorkflowsClient = (apiKey, apiUrl) => {
1769
2041
  };
1770
2042
 
1771
2043
  // src/skills.ts
1772
- var DEFAULT_API25 = "https://be.graph8.com";
2044
+ var DEFAULT_API26 = "https://be.graph8.com";
1773
2045
  var createSkillsClient = (apiKey, apiUrl) => {
1774
- const baseUrl = apiUrl || DEFAULT_API25;
2046
+ const baseUrl = apiUrl || DEFAULT_API26;
1775
2047
  return {
1776
2048
  /** List skills. */
1777
2049
  async list(params = {}) {
@@ -1858,9 +2130,9 @@ var createSkillsClient = (apiKey, apiUrl) => {
1858
2130
  };
1859
2131
 
1860
2132
  // src/intent.ts
1861
- var DEFAULT_API26 = "https://be.graph8.com";
2133
+ var DEFAULT_API27 = "https://be.graph8.com";
1862
2134
  var createIntentClient = (apiKey, apiUrl) => {
1863
- const baseUrl = apiUrl || DEFAULT_API26;
2135
+ const baseUrl = apiUrl || DEFAULT_API27;
1864
2136
  const get = (path) => request(baseUrl, `/api/v1${path}`, apiKey);
1865
2137
  const post = (path, body = {}) => request(baseUrl, `/api/v1${path}`, apiKey, { method: "POST", body });
1866
2138
  const del = (path) => request(baseUrl, `/api/v1${path}`, apiKey, { method: "DELETE" });
@@ -1935,9 +2207,9 @@ var createIntentClient = (apiKey, apiUrl) => {
1935
2207
  };
1936
2208
 
1937
2209
  // src/studio.ts
1938
- var DEFAULT_API27 = "https://be.graph8.com";
2210
+ var DEFAULT_API28 = "https://be.graph8.com";
1939
2211
  var createStudioClient = (apiKey, apiUrl) => {
1940
- const baseUrl = apiUrl || DEFAULT_API27;
2212
+ const baseUrl = apiUrl || DEFAULT_API28;
1941
2213
  const get = (path, params = {}) => request(baseUrl, `/api/v1${path}`, apiKey, { query: params });
1942
2214
  const post = (path, body = {}) => request(baseUrl, `/api/v1${path}`, apiKey, { method: "POST", body });
1943
2215
  const patch = (path, body = {}) => request(baseUrl, `/api/v1${path}`, apiKey, { method: "PATCH", body });
@@ -1992,9 +2264,9 @@ var createStudioClient = (apiKey, apiUrl) => {
1992
2264
  };
1993
2265
 
1994
2266
  // src/meetings.ts
1995
- var DEFAULT_API28 = "https://be.graph8.com";
2267
+ var DEFAULT_API29 = "https://be.graph8.com";
1996
2268
  var createMeetingsClient = (apiKey, apiUrl) => {
1997
- const baseUrl = apiUrl || DEFAULT_API28;
2269
+ const baseUrl = apiUrl || DEFAULT_API29;
1998
2270
  return {
1999
2271
  /** List meetings with optional filters. Returns summary rows without transcript / analysis. */
2000
2272
  async list(params = {}) {
@@ -2009,9 +2281,9 @@ var createMeetingsClient = (apiKey, apiUrl) => {
2009
2281
  };
2010
2282
 
2011
2283
  // src/audiences.ts
2012
- var DEFAULT_API29 = "https://be.graph8.com";
2284
+ var DEFAULT_API30 = "https://be.graph8.com";
2013
2285
  var createAudiencesClient = (apiKey, apiUrl) => {
2014
- const baseUrl = apiUrl || DEFAULT_API29;
2286
+ const baseUrl = apiUrl || DEFAULT_API30;
2015
2287
  const base = "/api/v1/audience-syncs";
2016
2288
  return {
2017
2289
  /** List all audience syncs for the organization. */
@@ -2059,9 +2331,9 @@ var createAudiencesClient = (apiKey, apiUrl) => {
2059
2331
  };
2060
2332
 
2061
2333
  // src/search.ts
2062
- var DEFAULT_API30 = "https://be.graph8.com";
2334
+ var DEFAULT_API31 = "https://be.graph8.com";
2063
2335
  var createSearchClient = (apiKey, apiUrl) => {
2064
- const baseUrl = apiUrl || DEFAULT_API30;
2336
+ const baseUrl = apiUrl || DEFAULT_API31;
2065
2337
  const body = (p) => ({ filters: [], page: 1, limit: 25, ...p });
2066
2338
  return {
2067
2339
  /** Search open-data contacts by filter. */
@@ -2092,9 +2364,9 @@ var createSearchClient = (apiKey, apiUrl) => {
2092
2364
  };
2093
2365
 
2094
2366
  // src/agency.ts
2095
- var DEFAULT_API31 = "https://be.graph8.com";
2367
+ var DEFAULT_API32 = "https://be.graph8.com";
2096
2368
  var createAgencyClient = (apiKey, apiUrl) => {
2097
- const baseUrl = apiUrl || DEFAULT_API31;
2369
+ const baseUrl = apiUrl || DEFAULT_API32;
2098
2370
  return {
2099
2371
  /** Describe the agency credential: agency org + authorized client count. */
2100
2372
  async me() {
@@ -2109,9 +2381,9 @@ var createAgencyClient = (apiKey, apiUrl) => {
2109
2381
  };
2110
2382
 
2111
2383
  // src/marketplace.ts
2112
- var DEFAULT_API32 = "https://be.graph8.com";
2384
+ var DEFAULT_API33 = "https://be.graph8.com";
2113
2385
  var createMarketplaceClient = (apiKey, apiUrl) => {
2114
- const baseUrl = apiUrl || DEFAULT_API32;
2386
+ const baseUrl = apiUrl || DEFAULT_API33;
2115
2387
  const base = "/api/v1/marketplace";
2116
2388
  return {
2117
2389
  /** Your own marketplace SDR profile. */
@@ -2161,9 +2433,9 @@ var createMarketplaceClient = (apiKey, apiUrl) => {
2161
2433
  };
2162
2434
 
2163
2435
  // src/snippet.ts
2164
- var DEFAULT_API33 = "https://be.graph8.com";
2436
+ var DEFAULT_API34 = "https://be.graph8.com";
2165
2437
  var createSnippetClient = (apiKey, apiUrl) => {
2166
- const baseUrl = apiUrl || DEFAULT_API33;
2438
+ const baseUrl = apiUrl || DEFAULT_API34;
2167
2439
  return {
2168
2440
  /** Get your org's tracking snippet (write key + React/script-tag embeds + config). */
2169
2441
  async get() {
@@ -2175,7 +2447,7 @@ var createSnippetClient = (apiKey, apiUrl) => {
2175
2447
 
2176
2448
  // src/core.ts
2177
2449
  var DEFAULT_HOST = "https://t.graph8.com";
2178
- var DEFAULT_API34 = "https://be.graph8.com";
2450
+ var DEFAULT_API35 = "https://be.graph8.com";
2179
2451
  var G8 = class {
2180
2452
  constructor() {
2181
2453
  /** @internal */
@@ -2219,6 +2491,8 @@ var G8 = class {
2219
2491
  /** @internal */
2220
2492
  this._apps = null;
2221
2493
  /** @internal */
2494
+ this._appPlatform = null;
2495
+ /** @internal */
2222
2496
  this._objects = null;
2223
2497
  /** @internal */
2224
2498
  this._deals = null;
@@ -2262,7 +2536,7 @@ var G8 = class {
2262
2536
  debug: config.debug
2263
2537
  });
2264
2538
  }
2265
- const apiUrl = config.apiUrl || DEFAULT_API34;
2539
+ const apiUrl = config.apiUrl || DEFAULT_API35;
2266
2540
  const writeKey = config.writeKey || "";
2267
2541
  const apiKey = config.apiKey || "";
2268
2542
  if (writeKey) {
@@ -2286,6 +2560,7 @@ var G8 = class {
2286
2560
  this._tasks = createTasksClient(apiKey, apiUrl);
2287
2561
  this._fields = createFieldsClient(apiKey, apiUrl);
2288
2562
  this._apps = createAppsClient(apiKey, apiUrl);
2563
+ this._appPlatform = createAppPlatformClient(apiKey, apiUrl);
2289
2564
  this._objects = createObjectsClient(apiKey, apiUrl);
2290
2565
  this._deals = createDealsClient(apiKey, apiUrl);
2291
2566
  this._inbox = createInboxClient(apiKey, apiUrl);
@@ -2412,6 +2687,18 @@ var G8 = class {
2412
2687
  this._assertKey("apps");
2413
2688
  return this._apps;
2414
2689
  }
2690
+ /**
2691
+ * Ship a hosted app: bind a source, deploy, promote, attach a hostname, read
2692
+ * build logs (requires API key). PREVIEW.
2693
+ *
2694
+ * Separate from `apps` on purpose. `apps` is the app's IDENTITY -- create it,
2695
+ * see who installed it, what it cost. This is its LIFECYCLE, and the two have
2696
+ * different blast radii: a mistake here takes a customer's app down.
2697
+ */
2698
+ get appPlatform() {
2699
+ this._assertKey("appPlatform");
2700
+ return this._appPlatform;
2701
+ }
2415
2702
  /** Custom object types, their schema, and their records (requires API key). PREVIEW. */
2416
2703
  get objects() {
2417
2704
  this._assertKey("objects");