@objectstack/rest 9.2.0 → 9.3.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);
@@ -1578,7 +1595,8 @@ var RestServer = class {
1578
1595
  }
1579
1596
  const isAppType = req.params.type === "app";
1580
1597
  const isDraftRead = typeof req.query?.state === "string" && req.query.state.toLowerCase() === "draft";
1581
- if (metadata.enableCache && p.getMetaItemCached && !isAppType && !isDraftRead) {
1598
+ const previewDrafts = typeof req.query?.preview === "string" && req.query.preview.toLowerCase() === "draft";
1599
+ if (metadata.enableCache && p.getMetaItemCached && !isAppType && !isDraftRead && !previewDrafts) {
1582
1600
  const cacheRequest = {
1583
1601
  ifNoneMatch: req.headers["if-none-match"],
1584
1602
  ifModifiedSince: req.headers["if-modified-since"]
@@ -1617,7 +1635,8 @@ var RestServer = class {
1617
1635
  type: req.params.type,
1618
1636
  name: req.params.name,
1619
1637
  packageId,
1620
- ...stateParam === "draft" ? { state: "draft" } : {}
1638
+ ...stateParam === "draft" ? { state: "draft" } : {},
1639
+ ...previewDrafts ? { previewDrafts: true } : {}
1621
1640
  });
1622
1641
  let visible = item;
1623
1642
  if (isAppType && item) {
@@ -3582,6 +3601,7 @@ var RestServer = class {
3582
3601
  [/^VALIDATION_FAILED/, 400, "VALIDATION_FAILED"],
3583
3602
  [/^DUPLICATE_REQUEST/, 409, "DUPLICATE_REQUEST"],
3584
3603
  [/^INVALID_STATE/, 409, "INVALID_STATE"],
3604
+ [/^THROTTLED/, 429, "THROTTLED"],
3585
3605
  [/^FORBIDDEN/, 403, "FORBIDDEN"],
3586
3606
  [/^REQUEST_NOT_FOUND/, 404, "REQUEST_NOT_FOUND"]
3587
3607
  ];
@@ -3609,13 +3629,24 @@ var RestServer = class {
3609
3629
  const q = req.query ?? {};
3610
3630
  const rawApprover = q.approverId ?? q.approver_id;
3611
3631
  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({
3632
+ const limit = q.limit != null ? Number(q.limit) : void 0;
3633
+ const offset = q.offset != null ? Number(q.offset) : void 0;
3634
+ const listFilter = {
3613
3635
  object: q.object,
3614
3636
  recordId: q.recordId ?? q.record_id,
3615
3637
  status: q.status,
3616
3638
  approverId: approverIds.length ? approverIds : void 0,
3617
- submitterId: q.submitterId ?? q.submitter_id
3618
- }, context ?? {});
3639
+ submitterId: q.submitterId ?? q.submitter_id,
3640
+ q: typeof q.q === "string" ? q.q : void 0,
3641
+ limit: Number.isFinite(limit) ? limit : void 0,
3642
+ offset: Number.isFinite(offset) ? offset : void 0
3643
+ };
3644
+ const rows = await svc.listRequests(listFilter, context ?? {});
3645
+ if (listFilter.limit != null && typeof svc.countRequests === "function") {
3646
+ const total = await svc.countRequests(listFilter, context ?? {});
3647
+ res.json({ data: rows, total });
3648
+ return;
3649
+ }
3619
3650
  res.json({ data: rows });
3620
3651
  } catch (error) {
3621
3652
  logError("[REST] List approval requests error:", error);
@@ -3708,6 +3739,63 @@ var RestServer = class {
3708
3739
  },
3709
3740
  metadata: { summary: "Recall (withdraw) an approval request", tags: ["approvals"] }
3710
3741
  });
3742
+ const threadRoute = (action, invoke) => {
3743
+ this.routeManager.register({
3744
+ method: "POST",
3745
+ path: `${dataPath}/approvals/requests/:id/${action}`,
3746
+ handler: async (req, res) => {
3747
+ try {
3748
+ const environmentId = isScoped ? req.params?.environmentId : void 0;
3749
+ const context = await this.resolveExecCtx(environmentId, req);
3750
+ if (this.enforceAuth(req, res, context)) return;
3751
+ const svc = await resolveService(environmentId);
3752
+ if (!svc) return respond501(res);
3753
+ const body = req.body ?? {};
3754
+ try {
3755
+ const out = await invoke(svc, req.params.id, body, context ?? {});
3756
+ res.json(out);
3757
+ } catch (err) {
3758
+ if (handleApprovalError(res, err)) return;
3759
+ throw err;
3760
+ }
3761
+ } catch (error) {
3762
+ logError(`[REST] ${action} approval error:`, error);
3763
+ res.status(500).json({ code: `APPROVAL_${action.toUpperCase().replace("-", "_")}_FAILED`, error: String(error?.message ?? error).slice(0, 500) });
3764
+ }
3765
+ },
3766
+ metadata: { summary: `${action} on an approval request`, tags: ["approvals"] }
3767
+ });
3768
+ };
3769
+ threadRoute("reassign", (svc, id, body, context) => {
3770
+ if (typeof svc.reassign !== "function") throw new Error("VALIDATION_FAILED: reassign is not supported");
3771
+ return svc.reassign(id, {
3772
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3773
+ to: body.to,
3774
+ from: body.from,
3775
+ comment: body.comment
3776
+ }, context);
3777
+ });
3778
+ threadRoute("remind", (svc, id, body, context) => {
3779
+ if (typeof svc.remind !== "function") throw new Error("VALIDATION_FAILED: remind is not supported");
3780
+ return svc.remind(id, {
3781
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3782
+ comment: body.comment
3783
+ }, context);
3784
+ });
3785
+ threadRoute("request-info", (svc, id, body, context) => {
3786
+ if (typeof svc.requestInfo !== "function") throw new Error("VALIDATION_FAILED: request-info is not supported");
3787
+ return svc.requestInfo(id, {
3788
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3789
+ comment: body.comment
3790
+ }, context);
3791
+ });
3792
+ threadRoute("comment", (svc, id, body, context) => {
3793
+ if (typeof svc.comment !== "function") throw new Error("VALIDATION_FAILED: comment is not supported");
3794
+ return svc.comment(id, {
3795
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3796
+ comment: body.comment
3797
+ }, context);
3798
+ });
3711
3799
  this.routeManager.register({
3712
3800
  method: "GET",
3713
3801
  path: `${dataPath}/approvals/requests/:id/actions`,