@ptkl/sdk 1.13.0 → 1.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.
@@ -1293,6 +1293,59 @@ var ProtokolSDK010 = (function (exports, axios) {
1293
1293
  }
1294
1294
  }
1295
1295
 
1296
+ /**
1297
+ * Resolve the current app's UUID from the ambient platform context.
1298
+ * The platform injects it per-installation: FORGE_APP_UUID in __ENV_VARIABLES__
1299
+ * for public views, and forge_app_uuid in sessionStorage for platform views.
1300
+ * Returns null outside the browser (e.g. Node/CLI), where the caller must pass
1301
+ * an explicit appUuid.
1302
+ */
1303
+ function resolveCurrentAppUuid() {
1304
+ var _a;
1305
+ if (!isBrowser)
1306
+ return null;
1307
+ // @ts-ignore
1308
+ const fromEnv = (_a = window.__ENV_VARIABLES__) === null || _a === void 0 ? void 0 : _a.FORGE_APP_UUID;
1309
+ if (fromEnv)
1310
+ return fromEnv;
1311
+ try {
1312
+ return sessionStorage.getItem("forge_app_uuid");
1313
+ }
1314
+ catch {
1315
+ return null;
1316
+ }
1317
+ }
1318
+ /**
1319
+ * Resolve a service target into { ref, serviceName }.
1320
+ *
1321
+ * Two forms, cleanly split:
1322
+ * - a bare service name (no "prn:" prefix) → the CURRENT app's service (the ref
1323
+ * is the current app's uuid, resolved from the platform context); or
1324
+ * - a service PRN `prn:forge:{ref}:service/{serviceName}` → ANOTHER app's service
1325
+ * (canonical PRN grammar: kind + name in the path, url-encoded).
1326
+ *
1327
+ * A PRN's `ref` may be an app **name** OR a uuid. Names aren't unique within a
1328
+ * project (a marketplace install and a custom app can share one), so the runtime
1329
+ * resolves a name deterministically **marketplace → custom**. Pass the uuid when
1330
+ * you need a *specific* app.
1331
+ */
1332
+ function parseServiceTarget(target) {
1333
+ if (!target.startsWith("prn:")) {
1334
+ // bare service name → the current app
1335
+ return { ref: resolveCurrentAppUuid(), serviceName: target };
1336
+ }
1337
+ // PRN → another app. Path form: prn:forge:{ref}:service/{serviceName}
1338
+ // (the PRN path segment is "service/{name}", with the name url-encoded).
1339
+ const [, type, ref, ...rest] = target.split(":");
1340
+ const path = rest.join(":"); // the PRN path, e.g. "service/{name}"
1341
+ const [kind, ...nameParts] = path.split("/");
1342
+ const serviceName = decodeURIComponent(nameParts.join("/"));
1343
+ if (type !== "forge" || kind !== "service" || !ref || !serviceName) {
1344
+ throw new Error(`runService: invalid service PRN "${target}" ` +
1345
+ `(expected prn:forge:{ref}:service/{serviceName}, where ref is an app name or uuid)`);
1346
+ }
1347
+ return { ref, serviceName };
1348
+ }
1296
1349
  class Forge extends PlatformBaseClient {
1297
1350
  // --- Management (appservice) ---
1298
1351
  async bundleUpload(buffer) {
@@ -1330,17 +1383,49 @@ var ProtokolSDK010 = (function (exports, axios) {
1330
1383
  return await this.client.patch(`/luma/appservice/v1/forge/${ref}/variables`, current);
1331
1384
  }
1332
1385
  // --- Service execution (forge-runtime) ---
1333
- async callService(appUuid, serviceName, options) {
1334
- var _a, _b, _c;
1386
+ /**
1387
+ * Run a Forge service: `runService(target, body?, { query?, headers? })`.
1388
+ * Mirrors `axios.post(url, data, config)` — the 2nd arg is the request payload.
1389
+ *
1390
+ * `target` is either:
1391
+ * - a bare service name — runs that service on the CURRENT app; or
1392
+ * - a service PRN `prn:forge:{ref}:service/{name}` — runs it on ANOTHER app,
1393
+ * where `ref` is the app's **name** or uuid. A name is resolved by the
1394
+ * runtime deterministically (marketplace → custom); use the uuid to pin a
1395
+ * specific app. This is the addressing to use where there's no ambient
1396
+ * "current app" — e.g. a workflow, which has no per-install uuid to hardcode.
1397
+ *
1398
+ * `body` is sent as the POST body; `options.query` / `options.headers` are optional.
1399
+ *
1400
+ * The current app's uuid (bare-name form) is resolved automatically from the
1401
+ * platform context (FORGE_APP_UUID for public views, forge_app_uuid in
1402
+ * sessionStorage for platform views), so app code never needs its own uuid.
1403
+ *
1404
+ * Resolving the app does NOT grant access. Execution is still authorized against
1405
+ * the caller's permissions — for a `platform`-access service the caller must hold
1406
+ * `execute forge::service::{appUuid}::{name}`; `public`-access services require none.
1407
+ */
1408
+ async runService(target, body, options) {
1409
+ var _a;
1410
+ const { ref, serviceName } = parseServiceTarget(target);
1335
1411
  const queryString = (options === null || options === void 0 ? void 0 : options.query)
1336
1412
  ? '?' + new URLSearchParams(options.query).toString()
1337
1413
  : '';
1338
1414
  // @ts-ignore
1339
1415
  const devServiceUrl = isBrowser && ((_a = window.__ENV_VARIABLES__) === null || _a === void 0 ? void 0 : _a.FORGE_DEV_SERVICE_URL);
1340
1416
  if (devServiceUrl) {
1341
- return axios.post(`${devServiceUrl}/${serviceName}${queryString}`, (_b = options === null || options === void 0 ? void 0 : options.body) !== null && _b !== void 0 ? _b : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
1417
+ // The dev service server routes by name; the ref is ignored.
1418
+ return axios.post(`${devServiceUrl}/${serviceName}${queryString}`, body !== null && body !== void 0 ? body : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
1419
+ }
1420
+ if (!ref) {
1421
+ throw new Error("runService: could not resolve the current app from the platform context. " +
1422
+ "Use a service PRN with an explicit ref: prn:forge:{name|uuid}:service/{serviceName}.");
1342
1423
  }
1343
- return await this.client.post(`/luma/forge-runtime/api/services/${appUuid}/${serviceName}${queryString}`, (_c = options === null || options === void 0 ? void 0 : options.body) !== null && _c !== void 0 ? _c : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
1424
+ // Service execution is owned by the forge runtime (forge-runtime gateway ->
1425
+ // platform-forge), which resolves the ref (name → uuid, marketplace → custom)
1426
+ // and executes the service, enforcing `execute forge::service::{uuid}::{name}`
1427
+ // for platform-access services before running.
1428
+ return await this.client.post(`/luma/forge-runtime/api/services/${ref}/${serviceName}${queryString}`, body !== null && body !== void 0 ? body : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
1344
1429
  }
1345
1430
  }
1346
1431
 
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ptkl/sdk",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "scripts": {
5
5
  "build": "rollup -c",
6
6
  "build:monaco": "npm run build && node scripts/generate-monaco-types.cjs",
@@ -8,8 +8,29 @@ export default class Forge extends PlatformBaseClient {
8
8
  getVariables(ref: string): Promise<any>;
9
9
  updateVariables(ref: string, variables: Record<string, any>): Promise<any>;
10
10
  addVariable(ref: string, key: string, value: any): Promise<any>;
11
- callService(appUuid: string, serviceName: string, options?: {
12
- body?: any;
11
+ /**
12
+ * Run a Forge service: `runService(target, body?, { query?, headers? })`.
13
+ * Mirrors `axios.post(url, data, config)` — the 2nd arg is the request payload.
14
+ *
15
+ * `target` is either:
16
+ * - a bare service name — runs that service on the CURRENT app; or
17
+ * - a service PRN `prn:forge:{ref}:service/{name}` — runs it on ANOTHER app,
18
+ * where `ref` is the app's **name** or uuid. A name is resolved by the
19
+ * runtime deterministically (marketplace → custom); use the uuid to pin a
20
+ * specific app. This is the addressing to use where there's no ambient
21
+ * "current app" — e.g. a workflow, which has no per-install uuid to hardcode.
22
+ *
23
+ * `body` is sent as the POST body; `options.query` / `options.headers` are optional.
24
+ *
25
+ * The current app's uuid (bare-name form) is resolved automatically from the
26
+ * platform context (FORGE_APP_UUID for public views, forge_app_uuid in
27
+ * sessionStorage for platform views), so app code never needs its own uuid.
28
+ *
29
+ * Resolving the app does NOT grant access. Execution is still authorized against
30
+ * the caller's permissions — for a `platform`-access service the caller must hold
31
+ * `execute forge::service::{appUuid}::{name}`; `public`-access services require none.
32
+ */
33
+ runService(target: string, body?: any, options?: {
13
34
  query?: Record<string, string>;
14
35
  headers?: Record<string, string>;
15
36
  }): Promise<any>;
@@ -20259,6 +20259,59 @@ class Workflow extends PlatformBaseClient {
20259
20259
  }
20260
20260
  }
20261
20261
 
20262
+ /**
20263
+ * Resolve the current app's UUID from the ambient platform context.
20264
+ * The platform injects it per-installation: FORGE_APP_UUID in __ENV_VARIABLES__
20265
+ * for public views, and forge_app_uuid in sessionStorage for platform views.
20266
+ * Returns null outside the browser (e.g. Node/CLI), where the caller must pass
20267
+ * an explicit appUuid.
20268
+ */
20269
+ function resolveCurrentAppUuid() {
20270
+ var _a;
20271
+ if (!isBrowser)
20272
+ return null;
20273
+ // @ts-ignore
20274
+ const fromEnv = (_a = window.__ENV_VARIABLES__) === null || _a === void 0 ? void 0 : _a.FORGE_APP_UUID;
20275
+ if (fromEnv)
20276
+ return fromEnv;
20277
+ try {
20278
+ return sessionStorage.getItem("forge_app_uuid");
20279
+ }
20280
+ catch {
20281
+ return null;
20282
+ }
20283
+ }
20284
+ /**
20285
+ * Resolve a service target into { ref, serviceName }.
20286
+ *
20287
+ * Two forms, cleanly split:
20288
+ * - a bare service name (no "prn:" prefix) → the CURRENT app's service (the ref
20289
+ * is the current app's uuid, resolved from the platform context); or
20290
+ * - a service PRN `prn:forge:{ref}:service/{serviceName}` → ANOTHER app's service
20291
+ * (canonical PRN grammar: kind + name in the path, url-encoded).
20292
+ *
20293
+ * A PRN's `ref` may be an app **name** OR a uuid. Names aren't unique within a
20294
+ * project (a marketplace install and a custom app can share one), so the runtime
20295
+ * resolves a name deterministically **marketplace → custom**. Pass the uuid when
20296
+ * you need a *specific* app.
20297
+ */
20298
+ function parseServiceTarget(target) {
20299
+ if (!target.startsWith("prn:")) {
20300
+ // bare service name → the current app
20301
+ return { ref: resolveCurrentAppUuid(), serviceName: target };
20302
+ }
20303
+ // PRN → another app. Path form: prn:forge:{ref}:service/{serviceName}
20304
+ // (the PRN path segment is "service/{name}", with the name url-encoded).
20305
+ const [, type, ref, ...rest] = target.split(":");
20306
+ const path = rest.join(":"); // the PRN path, e.g. "service/{name}"
20307
+ const [kind, ...nameParts] = path.split("/");
20308
+ const serviceName = decodeURIComponent(nameParts.join("/"));
20309
+ if (type !== "forge" || kind !== "service" || !ref || !serviceName) {
20310
+ throw new Error(`runService: invalid service PRN "${target}" ` +
20311
+ `(expected prn:forge:{ref}:service/{serviceName}, where ref is an app name or uuid)`);
20312
+ }
20313
+ return { ref, serviceName };
20314
+ }
20262
20315
  class Forge extends PlatformBaseClient {
20263
20316
  // --- Management (appservice) ---
20264
20317
  async bundleUpload(buffer) {
@@ -20296,17 +20349,49 @@ class Forge extends PlatformBaseClient {
20296
20349
  return await this.client.patch(`/luma/appservice/v1/forge/${ref}/variables`, current);
20297
20350
  }
20298
20351
  // --- Service execution (forge-runtime) ---
20299
- async callService(appUuid, serviceName, options) {
20300
- var _a, _b, _c;
20352
+ /**
20353
+ * Run a Forge service: `runService(target, body?, { query?, headers? })`.
20354
+ * Mirrors `axios.post(url, data, config)` — the 2nd arg is the request payload.
20355
+ *
20356
+ * `target` is either:
20357
+ * - a bare service name — runs that service on the CURRENT app; or
20358
+ * - a service PRN `prn:forge:{ref}:service/{name}` — runs it on ANOTHER app,
20359
+ * where `ref` is the app's **name** or uuid. A name is resolved by the
20360
+ * runtime deterministically (marketplace → custom); use the uuid to pin a
20361
+ * specific app. This is the addressing to use where there's no ambient
20362
+ * "current app" — e.g. a workflow, which has no per-install uuid to hardcode.
20363
+ *
20364
+ * `body` is sent as the POST body; `options.query` / `options.headers` are optional.
20365
+ *
20366
+ * The current app's uuid (bare-name form) is resolved automatically from the
20367
+ * platform context (FORGE_APP_UUID for public views, forge_app_uuid in
20368
+ * sessionStorage for platform views), so app code never needs its own uuid.
20369
+ *
20370
+ * Resolving the app does NOT grant access. Execution is still authorized against
20371
+ * the caller's permissions — for a `platform`-access service the caller must hold
20372
+ * `execute forge::service::{appUuid}::{name}`; `public`-access services require none.
20373
+ */
20374
+ async runService(target, body, options) {
20375
+ var _a;
20376
+ const { ref, serviceName } = parseServiceTarget(target);
20301
20377
  const queryString = (options === null || options === void 0 ? void 0 : options.query)
20302
20378
  ? '?' + new URLSearchParams(options.query).toString()
20303
20379
  : '';
20304
20380
  // @ts-ignore
20305
20381
  const devServiceUrl = isBrowser && ((_a = window.__ENV_VARIABLES__) === null || _a === void 0 ? void 0 : _a.FORGE_DEV_SERVICE_URL);
20306
20382
  if (devServiceUrl) {
20307
- return axios.post(`${devServiceUrl}/${serviceName}${queryString}`, (_b = options === null || options === void 0 ? void 0 : options.body) !== null && _b !== void 0 ? _b : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
20383
+ // The dev service server routes by name; the ref is ignored.
20384
+ return axios.post(`${devServiceUrl}/${serviceName}${queryString}`, body !== null && body !== void 0 ? body : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
20385
+ }
20386
+ if (!ref) {
20387
+ throw new Error("runService: could not resolve the current app from the platform context. " +
20388
+ "Use a service PRN with an explicit ref: prn:forge:{name|uuid}:service/{serviceName}.");
20308
20389
  }
20309
- return await this.client.post(`/luma/forge-runtime/api/services/${appUuid}/${serviceName}${queryString}`, (_c = options === null || options === void 0 ? void 0 : options.body) !== null && _c !== void 0 ? _c : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
20390
+ // Service execution is owned by the forge runtime (forge-runtime gateway ->
20391
+ // platform-forge), which resolves the ref (name → uuid, marketplace → custom)
20392
+ // and executes the service, enforcing `execute forge::service::{uuid}::{name}`
20393
+ // for platform-access services before running.
20394
+ return await this.client.post(`/luma/forge-runtime/api/services/${ref}/${serviceName}${queryString}`, body !== null && body !== void 0 ? body : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
20310
20395
  }
20311
20396
  }
20312
20397
 
@@ -1292,6 +1292,59 @@ class Workflow extends PlatformBaseClient {
1292
1292
  }
1293
1293
  }
1294
1294
 
1295
+ /**
1296
+ * Resolve the current app's UUID from the ambient platform context.
1297
+ * The platform injects it per-installation: FORGE_APP_UUID in __ENV_VARIABLES__
1298
+ * for public views, and forge_app_uuid in sessionStorage for platform views.
1299
+ * Returns null outside the browser (e.g. Node/CLI), where the caller must pass
1300
+ * an explicit appUuid.
1301
+ */
1302
+ function resolveCurrentAppUuid() {
1303
+ var _a;
1304
+ if (!isBrowser)
1305
+ return null;
1306
+ // @ts-ignore
1307
+ const fromEnv = (_a = window.__ENV_VARIABLES__) === null || _a === void 0 ? void 0 : _a.FORGE_APP_UUID;
1308
+ if (fromEnv)
1309
+ return fromEnv;
1310
+ try {
1311
+ return sessionStorage.getItem("forge_app_uuid");
1312
+ }
1313
+ catch {
1314
+ return null;
1315
+ }
1316
+ }
1317
+ /**
1318
+ * Resolve a service target into { ref, serviceName }.
1319
+ *
1320
+ * Two forms, cleanly split:
1321
+ * - a bare service name (no "prn:" prefix) → the CURRENT app's service (the ref
1322
+ * is the current app's uuid, resolved from the platform context); or
1323
+ * - a service PRN `prn:forge:{ref}:service/{serviceName}` → ANOTHER app's service
1324
+ * (canonical PRN grammar: kind + name in the path, url-encoded).
1325
+ *
1326
+ * A PRN's `ref` may be an app **name** OR a uuid. Names aren't unique within a
1327
+ * project (a marketplace install and a custom app can share one), so the runtime
1328
+ * resolves a name deterministically **marketplace → custom**. Pass the uuid when
1329
+ * you need a *specific* app.
1330
+ */
1331
+ function parseServiceTarget(target) {
1332
+ if (!target.startsWith("prn:")) {
1333
+ // bare service name → the current app
1334
+ return { ref: resolveCurrentAppUuid(), serviceName: target };
1335
+ }
1336
+ // PRN → another app. Path form: prn:forge:{ref}:service/{serviceName}
1337
+ // (the PRN path segment is "service/{name}", with the name url-encoded).
1338
+ const [, type, ref, ...rest] = target.split(":");
1339
+ const path = rest.join(":"); // the PRN path, e.g. "service/{name}"
1340
+ const [kind, ...nameParts] = path.split("/");
1341
+ const serviceName = decodeURIComponent(nameParts.join("/"));
1342
+ if (type !== "forge" || kind !== "service" || !ref || !serviceName) {
1343
+ throw new Error(`runService: invalid service PRN "${target}" ` +
1344
+ `(expected prn:forge:{ref}:service/{serviceName}, where ref is an app name or uuid)`);
1345
+ }
1346
+ return { ref, serviceName };
1347
+ }
1295
1348
  class Forge extends PlatformBaseClient {
1296
1349
  // --- Management (appservice) ---
1297
1350
  async bundleUpload(buffer) {
@@ -1329,17 +1382,49 @@ class Forge extends PlatformBaseClient {
1329
1382
  return await this.client.patch(`/luma/appservice/v1/forge/${ref}/variables`, current);
1330
1383
  }
1331
1384
  // --- Service execution (forge-runtime) ---
1332
- async callService(appUuid, serviceName, options) {
1333
- var _a, _b, _c;
1385
+ /**
1386
+ * Run a Forge service: `runService(target, body?, { query?, headers? })`.
1387
+ * Mirrors `axios.post(url, data, config)` — the 2nd arg is the request payload.
1388
+ *
1389
+ * `target` is either:
1390
+ * - a bare service name — runs that service on the CURRENT app; or
1391
+ * - a service PRN `prn:forge:{ref}:service/{name}` — runs it on ANOTHER app,
1392
+ * where `ref` is the app's **name** or uuid. A name is resolved by the
1393
+ * runtime deterministically (marketplace → custom); use the uuid to pin a
1394
+ * specific app. This is the addressing to use where there's no ambient
1395
+ * "current app" — e.g. a workflow, which has no per-install uuid to hardcode.
1396
+ *
1397
+ * `body` is sent as the POST body; `options.query` / `options.headers` are optional.
1398
+ *
1399
+ * The current app's uuid (bare-name form) is resolved automatically from the
1400
+ * platform context (FORGE_APP_UUID for public views, forge_app_uuid in
1401
+ * sessionStorage for platform views), so app code never needs its own uuid.
1402
+ *
1403
+ * Resolving the app does NOT grant access. Execution is still authorized against
1404
+ * the caller's permissions — for a `platform`-access service the caller must hold
1405
+ * `execute forge::service::{appUuid}::{name}`; `public`-access services require none.
1406
+ */
1407
+ async runService(target, body, options) {
1408
+ var _a;
1409
+ const { ref, serviceName } = parseServiceTarget(target);
1334
1410
  const queryString = (options === null || options === void 0 ? void 0 : options.query)
1335
1411
  ? '?' + new URLSearchParams(options.query).toString()
1336
1412
  : '';
1337
1413
  // @ts-ignore
1338
1414
  const devServiceUrl = isBrowser && ((_a = window.__ENV_VARIABLES__) === null || _a === void 0 ? void 0 : _a.FORGE_DEV_SERVICE_URL);
1339
1415
  if (devServiceUrl) {
1340
- return axios.post(`${devServiceUrl}/${serviceName}${queryString}`, (_b = options === null || options === void 0 ? void 0 : options.body) !== null && _b !== void 0 ? _b : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
1416
+ // The dev service server routes by name; the ref is ignored.
1417
+ return axios.post(`${devServiceUrl}/${serviceName}${queryString}`, body !== null && body !== void 0 ? body : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
1418
+ }
1419
+ if (!ref) {
1420
+ throw new Error("runService: could not resolve the current app from the platform context. " +
1421
+ "Use a service PRN with an explicit ref: prn:forge:{name|uuid}:service/{serviceName}.");
1341
1422
  }
1342
- return await this.client.post(`/luma/forge-runtime/api/services/${appUuid}/${serviceName}${queryString}`, (_c = options === null || options === void 0 ? void 0 : options.body) !== null && _c !== void 0 ? _c : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
1423
+ // Service execution is owned by the forge runtime (forge-runtime gateway ->
1424
+ // platform-forge), which resolves the ref (name → uuid, marketplace → custom)
1425
+ // and executes the service, enforcing `execute forge::service::{uuid}::{name}`
1426
+ // for platform-access services before running.
1427
+ return await this.client.post(`/luma/forge-runtime/api/services/${ref}/${serviceName}${queryString}`, body !== null && body !== void 0 ? body : {}, (options === null || options === void 0 ? void 0 : options.headers) ? { headers: options.headers } : undefined);
1343
1428
  }
1344
1429
  }
1345
1430
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ptkl/sdk",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "scripts": {
5
5
  "build": "rollup -c",
6
6
  "build:monaco": "npm run build && node scripts/generate-monaco-types.cjs",