@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.cjs CHANGED
@@ -871,6 +871,9 @@ var RestServer = class {
871
871
  */
872
872
  filterAppForUser(item, sysPerms) {
873
873
  if (!item || typeof item !== "object") return item;
874
+ if (item.hidden === true && !sysPerms.has("studio.access") && !sysPerms.has("setup.access")) {
875
+ return null;
876
+ }
874
877
  const reqApp = Array.isArray(item.requiredPermissions) ? item.requiredPermissions : [];
875
878
  if (reqApp.length > 0 && !reqApp.every((p) => sysPerms.has(p))) {
876
879
  return null;
@@ -1488,9 +1491,11 @@ var RestServer = class {
1488
1491
  const packageId = req.query?.package || void 0;
1489
1492
  const environmentId = isScoped ? req.params?.environmentId : void 0;
1490
1493
  const p = await this.resolveProtocol(environmentId, req);
1494
+ const previewDrafts = typeof req.query?.preview === "string" && req.query.preview.toLowerCase() === "draft";
1491
1495
  const items = await p.getMetaItems({
1492
1496
  type: req.params.type,
1493
1497
  packageId,
1498
+ ...previewDrafts ? { previewDrafts: true } : {},
1494
1499
  ...environmentId ? { environmentId } : {}
1495
1500
  });
1496
1501
  let visible = items;
@@ -1517,6 +1522,18 @@ var RestServer = class {
1517
1522
  visible = Array.isArray(raw) ? filtered : { ...raw, items: filtered };
1518
1523
  }
1519
1524
  }
1525
+ if (req.params.type === "doc" && req.query?.include !== "content") {
1526
+ const raw = visible;
1527
+ const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.items) ? raw.items : null;
1528
+ if (list) {
1529
+ const slim = list.map((it) => {
1530
+ if (!it || typeof it !== "object") return it;
1531
+ const { content: _content, ...rest } = it;
1532
+ return rest;
1533
+ });
1534
+ visible = Array.isArray(raw) ? slim : { ...raw, items: slim };
1535
+ }
1536
+ }
1520
1537
  const translated = await this.translateMetaItems(req, req.params.type, environmentId, visible);
1521
1538
  res.header("Vary", "Accept-Language");
1522
1539
  res.json(translated);
@@ -1568,9 +1585,11 @@ var RestServer = class {
1568
1585
  const p = await this.resolveProtocol(environmentId, req);
1569
1586
  const wantLayered = req.query?.layers !== void 0 && req.query?.layers !== "";
1570
1587
  if (wantLayered && typeof p.getMetaItemLayered === "function") {
1588
+ const layeredPackageId = req.query?.package || void 0;
1571
1589
  const layered = await p.getMetaItemLayered({
1572
1590
  type: req.params.type,
1573
1591
  name: req.params.name,
1592
+ ...layeredPackageId ? { packageId: layeredPackageId } : {},
1574
1593
  ...environmentId ? { environmentId } : {}
1575
1594
  });
1576
1595
  res.json(layered);
@@ -1578,7 +1597,9 @@ var RestServer = class {
1578
1597
  }
1579
1598
  const isAppType = req.params.type === "app";
1580
1599
  const isDraftRead = typeof req.query?.state === "string" && req.query.state.toLowerCase() === "draft";
1581
- if (metadata.enableCache && p.getMetaItemCached && !isAppType && !isDraftRead) {
1600
+ const previewDrafts = typeof req.query?.preview === "string" && req.query.preview.toLowerCase() === "draft";
1601
+ const packageScoped = typeof req.query?.package === "string" && req.query.package.length > 0;
1602
+ if (metadata.enableCache && p.getMetaItemCached && !isAppType && !isDraftRead && !previewDrafts && !packageScoped) {
1582
1603
  const cacheRequest = {
1583
1604
  ifNoneMatch: req.headers["if-none-match"],
1584
1605
  ifModifiedSince: req.headers["if-modified-since"]
@@ -1617,7 +1638,8 @@ var RestServer = class {
1617
1638
  type: req.params.type,
1618
1639
  name: req.params.name,
1619
1640
  packageId,
1620
- ...stateParam === "draft" ? { state: "draft" } : {}
1641
+ ...stateParam === "draft" ? { state: "draft" } : {},
1642
+ ...previewDrafts ? { previewDrafts: true } : {}
1621
1643
  });
1622
1644
  let visible = item;
1623
1645
  if (isAppType && item) {
@@ -3582,6 +3604,7 @@ var RestServer = class {
3582
3604
  [/^VALIDATION_FAILED/, 400, "VALIDATION_FAILED"],
3583
3605
  [/^DUPLICATE_REQUEST/, 409, "DUPLICATE_REQUEST"],
3584
3606
  [/^INVALID_STATE/, 409, "INVALID_STATE"],
3607
+ [/^THROTTLED/, 429, "THROTTLED"],
3585
3608
  [/^FORBIDDEN/, 403, "FORBIDDEN"],
3586
3609
  [/^REQUEST_NOT_FOUND/, 404, "REQUEST_NOT_FOUND"]
3587
3610
  ];
@@ -3609,13 +3632,24 @@ var RestServer = class {
3609
3632
  const q = req.query ?? {};
3610
3633
  const rawApprover = q.approverId ?? q.approver_id;
3611
3634
  const approverIds = (Array.isArray(rawApprover) ? rawApprover : rawApprover != null ? [rawApprover] : []).flatMap((s) => String(s).split(",")).map((s) => s.trim()).filter(Boolean);
3612
- const rows = await svc.listRequests({
3635
+ const limit = q.limit != null ? Number(q.limit) : void 0;
3636
+ const offset = q.offset != null ? Number(q.offset) : void 0;
3637
+ const listFilter = {
3613
3638
  object: q.object,
3614
3639
  recordId: q.recordId ?? q.record_id,
3615
3640
  status: q.status,
3616
3641
  approverId: approverIds.length ? approverIds : void 0,
3617
- submitterId: q.submitterId ?? q.submitter_id
3618
- }, context ?? {});
3642
+ submitterId: q.submitterId ?? q.submitter_id,
3643
+ q: typeof q.q === "string" ? q.q : void 0,
3644
+ limit: Number.isFinite(limit) ? limit : void 0,
3645
+ offset: Number.isFinite(offset) ? offset : void 0
3646
+ };
3647
+ const rows = await svc.listRequests(listFilter, context ?? {});
3648
+ if (listFilter.limit != null && typeof svc.countRequests === "function") {
3649
+ const total = await svc.countRequests(listFilter, context ?? {});
3650
+ res.json({ data: rows, total });
3651
+ return;
3652
+ }
3619
3653
  res.json({ data: rows });
3620
3654
  } catch (error) {
3621
3655
  logError("[REST] List approval requests error:", error);
@@ -3708,6 +3742,63 @@ var RestServer = class {
3708
3742
  },
3709
3743
  metadata: { summary: "Recall (withdraw) an approval request", tags: ["approvals"] }
3710
3744
  });
3745
+ const threadRoute = (action, invoke) => {
3746
+ this.routeManager.register({
3747
+ method: "POST",
3748
+ path: `${dataPath}/approvals/requests/:id/${action}`,
3749
+ handler: async (req, res) => {
3750
+ try {
3751
+ const environmentId = isScoped ? req.params?.environmentId : void 0;
3752
+ const context = await this.resolveExecCtx(environmentId, req);
3753
+ if (this.enforceAuth(req, res, context)) return;
3754
+ const svc = await resolveService(environmentId);
3755
+ if (!svc) return respond501(res);
3756
+ const body = req.body ?? {};
3757
+ try {
3758
+ const out = await invoke(svc, req.params.id, body, context ?? {});
3759
+ res.json(out);
3760
+ } catch (err) {
3761
+ if (handleApprovalError(res, err)) return;
3762
+ throw err;
3763
+ }
3764
+ } catch (error) {
3765
+ logError(`[REST] ${action} approval error:`, error);
3766
+ res.status(500).json({ code: `APPROVAL_${action.toUpperCase().replace("-", "_")}_FAILED`, error: String(error?.message ?? error).slice(0, 500) });
3767
+ }
3768
+ },
3769
+ metadata: { summary: `${action} on an approval request`, tags: ["approvals"] }
3770
+ });
3771
+ };
3772
+ threadRoute("reassign", (svc, id, body, context) => {
3773
+ if (typeof svc.reassign !== "function") throw new Error("VALIDATION_FAILED: reassign is not supported");
3774
+ return svc.reassign(id, {
3775
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3776
+ to: body.to,
3777
+ from: body.from,
3778
+ comment: body.comment
3779
+ }, context);
3780
+ });
3781
+ threadRoute("remind", (svc, id, body, context) => {
3782
+ if (typeof svc.remind !== "function") throw new Error("VALIDATION_FAILED: remind is not supported");
3783
+ return svc.remind(id, {
3784
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3785
+ comment: body.comment
3786
+ }, context);
3787
+ });
3788
+ threadRoute("request-info", (svc, id, body, context) => {
3789
+ if (typeof svc.requestInfo !== "function") throw new Error("VALIDATION_FAILED: request-info is not supported");
3790
+ return svc.requestInfo(id, {
3791
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3792
+ comment: body.comment
3793
+ }, context);
3794
+ });
3795
+ threadRoute("comment", (svc, id, body, context) => {
3796
+ if (typeof svc.comment !== "function") throw new Error("VALIDATION_FAILED: comment is not supported");
3797
+ return svc.comment(id, {
3798
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3799
+ comment: body.comment
3800
+ }, context);
3801
+ });
3711
3802
  this.routeManager.register({
3712
3803
  method: "GET",
3713
3804
  path: `${dataPath}/approvals/requests/:id/actions`,