@objectstack/rest 9.2.0 → 9.4.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/index.js CHANGED
@@ -831,6 +831,9 @@ var RestServer = class {
831
831
  */
832
832
  filterAppForUser(item, sysPerms) {
833
833
  if (!item || typeof item !== "object") return item;
834
+ if (item.hidden === true && !sysPerms.has("studio.access") && !sysPerms.has("setup.access")) {
835
+ return null;
836
+ }
834
837
  const reqApp = Array.isArray(item.requiredPermissions) ? item.requiredPermissions : [];
835
838
  if (reqApp.length > 0 && !reqApp.every((p) => sysPerms.has(p))) {
836
839
  return null;
@@ -1448,9 +1451,11 @@ var RestServer = class {
1448
1451
  const packageId = req.query?.package || void 0;
1449
1452
  const environmentId = isScoped ? req.params?.environmentId : void 0;
1450
1453
  const p = await this.resolveProtocol(environmentId, req);
1454
+ const previewDrafts = typeof req.query?.preview === "string" && req.query.preview.toLowerCase() === "draft";
1451
1455
  const items = await p.getMetaItems({
1452
1456
  type: req.params.type,
1453
1457
  packageId,
1458
+ ...previewDrafts ? { previewDrafts: true } : {},
1454
1459
  ...environmentId ? { environmentId } : {}
1455
1460
  });
1456
1461
  let visible = items;
@@ -1477,6 +1482,18 @@ var RestServer = class {
1477
1482
  visible = Array.isArray(raw) ? filtered : { ...raw, items: filtered };
1478
1483
  }
1479
1484
  }
1485
+ if (req.params.type === "doc" && req.query?.include !== "content") {
1486
+ const raw = visible;
1487
+ const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.items) ? raw.items : null;
1488
+ if (list) {
1489
+ const slim = list.map((it) => {
1490
+ if (!it || typeof it !== "object") return it;
1491
+ const { content: _content, ...rest } = it;
1492
+ return rest;
1493
+ });
1494
+ visible = Array.isArray(raw) ? slim : { ...raw, items: slim };
1495
+ }
1496
+ }
1480
1497
  const translated = await this.translateMetaItems(req, req.params.type, environmentId, visible);
1481
1498
  res.header("Vary", "Accept-Language");
1482
1499
  res.json(translated);
@@ -1528,9 +1545,11 @@ var RestServer = class {
1528
1545
  const p = await this.resolveProtocol(environmentId, req);
1529
1546
  const wantLayered = req.query?.layers !== void 0 && req.query?.layers !== "";
1530
1547
  if (wantLayered && typeof p.getMetaItemLayered === "function") {
1548
+ const layeredPackageId = req.query?.package || void 0;
1531
1549
  const layered = await p.getMetaItemLayered({
1532
1550
  type: req.params.type,
1533
1551
  name: req.params.name,
1552
+ ...layeredPackageId ? { packageId: layeredPackageId } : {},
1534
1553
  ...environmentId ? { environmentId } : {}
1535
1554
  });
1536
1555
  res.json(layered);
@@ -1538,7 +1557,9 @@ var RestServer = class {
1538
1557
  }
1539
1558
  const isAppType = req.params.type === "app";
1540
1559
  const isDraftRead = typeof req.query?.state === "string" && req.query.state.toLowerCase() === "draft";
1541
- if (metadata.enableCache && p.getMetaItemCached && !isAppType && !isDraftRead) {
1560
+ const previewDrafts = typeof req.query?.preview === "string" && req.query.preview.toLowerCase() === "draft";
1561
+ const packageScoped = typeof req.query?.package === "string" && req.query.package.length > 0;
1562
+ if (metadata.enableCache && p.getMetaItemCached && !isAppType && !isDraftRead && !previewDrafts && !packageScoped) {
1542
1563
  const cacheRequest = {
1543
1564
  ifNoneMatch: req.headers["if-none-match"],
1544
1565
  ifModifiedSince: req.headers["if-modified-since"]
@@ -1577,7 +1598,8 @@ var RestServer = class {
1577
1598
  type: req.params.type,
1578
1599
  name: req.params.name,
1579
1600
  packageId,
1580
- ...stateParam === "draft" ? { state: "draft" } : {}
1601
+ ...stateParam === "draft" ? { state: "draft" } : {},
1602
+ ...previewDrafts ? { previewDrafts: true } : {}
1581
1603
  });
1582
1604
  let visible = item;
1583
1605
  if (isAppType && item) {
@@ -3542,6 +3564,7 @@ var RestServer = class {
3542
3564
  [/^VALIDATION_FAILED/, 400, "VALIDATION_FAILED"],
3543
3565
  [/^DUPLICATE_REQUEST/, 409, "DUPLICATE_REQUEST"],
3544
3566
  [/^INVALID_STATE/, 409, "INVALID_STATE"],
3567
+ [/^THROTTLED/, 429, "THROTTLED"],
3545
3568
  [/^FORBIDDEN/, 403, "FORBIDDEN"],
3546
3569
  [/^REQUEST_NOT_FOUND/, 404, "REQUEST_NOT_FOUND"]
3547
3570
  ];
@@ -3569,13 +3592,24 @@ var RestServer = class {
3569
3592
  const q = req.query ?? {};
3570
3593
  const rawApprover = q.approverId ?? q.approver_id;
3571
3594
  const approverIds = (Array.isArray(rawApprover) ? rawApprover : rawApprover != null ? [rawApprover] : []).flatMap((s) => String(s).split(",")).map((s) => s.trim()).filter(Boolean);
3572
- const rows = await svc.listRequests({
3595
+ const limit = q.limit != null ? Number(q.limit) : void 0;
3596
+ const offset = q.offset != null ? Number(q.offset) : void 0;
3597
+ const listFilter = {
3573
3598
  object: q.object,
3574
3599
  recordId: q.recordId ?? q.record_id,
3575
3600
  status: q.status,
3576
3601
  approverId: approverIds.length ? approverIds : void 0,
3577
- submitterId: q.submitterId ?? q.submitter_id
3578
- }, context ?? {});
3602
+ submitterId: q.submitterId ?? q.submitter_id,
3603
+ q: typeof q.q === "string" ? q.q : void 0,
3604
+ limit: Number.isFinite(limit) ? limit : void 0,
3605
+ offset: Number.isFinite(offset) ? offset : void 0
3606
+ };
3607
+ const rows = await svc.listRequests(listFilter, context ?? {});
3608
+ if (listFilter.limit != null && typeof svc.countRequests === "function") {
3609
+ const total = await svc.countRequests(listFilter, context ?? {});
3610
+ res.json({ data: rows, total });
3611
+ return;
3612
+ }
3579
3613
  res.json({ data: rows });
3580
3614
  } catch (error) {
3581
3615
  logError("[REST] List approval requests error:", error);
@@ -3668,6 +3702,63 @@ var RestServer = class {
3668
3702
  },
3669
3703
  metadata: { summary: "Recall (withdraw) an approval request", tags: ["approvals"] }
3670
3704
  });
3705
+ const threadRoute = (action, invoke) => {
3706
+ this.routeManager.register({
3707
+ method: "POST",
3708
+ path: `${dataPath}/approvals/requests/:id/${action}`,
3709
+ handler: async (req, res) => {
3710
+ try {
3711
+ const environmentId = isScoped ? req.params?.environmentId : void 0;
3712
+ const context = await this.resolveExecCtx(environmentId, req);
3713
+ if (this.enforceAuth(req, res, context)) return;
3714
+ const svc = await resolveService(environmentId);
3715
+ if (!svc) return respond501(res);
3716
+ const body = req.body ?? {};
3717
+ try {
3718
+ const out = await invoke(svc, req.params.id, body, context ?? {});
3719
+ res.json(out);
3720
+ } catch (err) {
3721
+ if (handleApprovalError(res, err)) return;
3722
+ throw err;
3723
+ }
3724
+ } catch (error) {
3725
+ logError(`[REST] ${action} approval error:`, error);
3726
+ res.status(500).json({ code: `APPROVAL_${action.toUpperCase().replace("-", "_")}_FAILED`, error: String(error?.message ?? error).slice(0, 500) });
3727
+ }
3728
+ },
3729
+ metadata: { summary: `${action} on an approval request`, tags: ["approvals"] }
3730
+ });
3731
+ };
3732
+ threadRoute("reassign", (svc, id, body, context) => {
3733
+ if (typeof svc.reassign !== "function") throw new Error("VALIDATION_FAILED: reassign is not supported");
3734
+ return svc.reassign(id, {
3735
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3736
+ to: body.to,
3737
+ from: body.from,
3738
+ comment: body.comment
3739
+ }, context);
3740
+ });
3741
+ threadRoute("remind", (svc, id, body, context) => {
3742
+ if (typeof svc.remind !== "function") throw new Error("VALIDATION_FAILED: remind is not supported");
3743
+ return svc.remind(id, {
3744
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3745
+ comment: body.comment
3746
+ }, context);
3747
+ });
3748
+ threadRoute("request-info", (svc, id, body, context) => {
3749
+ if (typeof svc.requestInfo !== "function") throw new Error("VALIDATION_FAILED: request-info is not supported");
3750
+ return svc.requestInfo(id, {
3751
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3752
+ comment: body.comment
3753
+ }, context);
3754
+ });
3755
+ threadRoute("comment", (svc, id, body, context) => {
3756
+ if (typeof svc.comment !== "function") throw new Error("VALIDATION_FAILED: comment is not supported");
3757
+ return svc.comment(id, {
3758
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3759
+ comment: body.comment
3760
+ }, context);
3761
+ });
3671
3762
  this.routeManager.register({
3672
3763
  method: "GET",
3673
3764
  path: `${dataPath}/approvals/requests/:id/actions`,