@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.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);
@@ -1538,7 +1555,8 @@ var RestServer = class {
1538
1555
  }
1539
1556
  const isAppType = req.params.type === "app";
1540
1557
  const isDraftRead = typeof req.query?.state === "string" && req.query.state.toLowerCase() === "draft";
1541
- if (metadata.enableCache && p.getMetaItemCached && !isAppType && !isDraftRead) {
1558
+ const previewDrafts = typeof req.query?.preview === "string" && req.query.preview.toLowerCase() === "draft";
1559
+ if (metadata.enableCache && p.getMetaItemCached && !isAppType && !isDraftRead && !previewDrafts) {
1542
1560
  const cacheRequest = {
1543
1561
  ifNoneMatch: req.headers["if-none-match"],
1544
1562
  ifModifiedSince: req.headers["if-modified-since"]
@@ -1577,7 +1595,8 @@ var RestServer = class {
1577
1595
  type: req.params.type,
1578
1596
  name: req.params.name,
1579
1597
  packageId,
1580
- ...stateParam === "draft" ? { state: "draft" } : {}
1598
+ ...stateParam === "draft" ? { state: "draft" } : {},
1599
+ ...previewDrafts ? { previewDrafts: true } : {}
1581
1600
  });
1582
1601
  let visible = item;
1583
1602
  if (isAppType && item) {
@@ -3542,6 +3561,7 @@ var RestServer = class {
3542
3561
  [/^VALIDATION_FAILED/, 400, "VALIDATION_FAILED"],
3543
3562
  [/^DUPLICATE_REQUEST/, 409, "DUPLICATE_REQUEST"],
3544
3563
  [/^INVALID_STATE/, 409, "INVALID_STATE"],
3564
+ [/^THROTTLED/, 429, "THROTTLED"],
3545
3565
  [/^FORBIDDEN/, 403, "FORBIDDEN"],
3546
3566
  [/^REQUEST_NOT_FOUND/, 404, "REQUEST_NOT_FOUND"]
3547
3567
  ];
@@ -3569,13 +3589,24 @@ var RestServer = class {
3569
3589
  const q = req.query ?? {};
3570
3590
  const rawApprover = q.approverId ?? q.approver_id;
3571
3591
  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({
3592
+ const limit = q.limit != null ? Number(q.limit) : void 0;
3593
+ const offset = q.offset != null ? Number(q.offset) : void 0;
3594
+ const listFilter = {
3573
3595
  object: q.object,
3574
3596
  recordId: q.recordId ?? q.record_id,
3575
3597
  status: q.status,
3576
3598
  approverId: approverIds.length ? approverIds : void 0,
3577
- submitterId: q.submitterId ?? q.submitter_id
3578
- }, context ?? {});
3599
+ submitterId: q.submitterId ?? q.submitter_id,
3600
+ q: typeof q.q === "string" ? q.q : void 0,
3601
+ limit: Number.isFinite(limit) ? limit : void 0,
3602
+ offset: Number.isFinite(offset) ? offset : void 0
3603
+ };
3604
+ const rows = await svc.listRequests(listFilter, context ?? {});
3605
+ if (listFilter.limit != null && typeof svc.countRequests === "function") {
3606
+ const total = await svc.countRequests(listFilter, context ?? {});
3607
+ res.json({ data: rows, total });
3608
+ return;
3609
+ }
3579
3610
  res.json({ data: rows });
3580
3611
  } catch (error) {
3581
3612
  logError("[REST] List approval requests error:", error);
@@ -3668,6 +3699,63 @@ var RestServer = class {
3668
3699
  },
3669
3700
  metadata: { summary: "Recall (withdraw) an approval request", tags: ["approvals"] }
3670
3701
  });
3702
+ const threadRoute = (action, invoke) => {
3703
+ this.routeManager.register({
3704
+ method: "POST",
3705
+ path: `${dataPath}/approvals/requests/:id/${action}`,
3706
+ handler: async (req, res) => {
3707
+ try {
3708
+ const environmentId = isScoped ? req.params?.environmentId : void 0;
3709
+ const context = await this.resolveExecCtx(environmentId, req);
3710
+ if (this.enforceAuth(req, res, context)) return;
3711
+ const svc = await resolveService(environmentId);
3712
+ if (!svc) return respond501(res);
3713
+ const body = req.body ?? {};
3714
+ try {
3715
+ const out = await invoke(svc, req.params.id, body, context ?? {});
3716
+ res.json(out);
3717
+ } catch (err) {
3718
+ if (handleApprovalError(res, err)) return;
3719
+ throw err;
3720
+ }
3721
+ } catch (error) {
3722
+ logError(`[REST] ${action} approval error:`, error);
3723
+ res.status(500).json({ code: `APPROVAL_${action.toUpperCase().replace("-", "_")}_FAILED`, error: String(error?.message ?? error).slice(0, 500) });
3724
+ }
3725
+ },
3726
+ metadata: { summary: `${action} on an approval request`, tags: ["approvals"] }
3727
+ });
3728
+ };
3729
+ threadRoute("reassign", (svc, id, body, context) => {
3730
+ if (typeof svc.reassign !== "function") throw new Error("VALIDATION_FAILED: reassign is not supported");
3731
+ return svc.reassign(id, {
3732
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3733
+ to: body.to,
3734
+ from: body.from,
3735
+ comment: body.comment
3736
+ }, context);
3737
+ });
3738
+ threadRoute("remind", (svc, id, body, context) => {
3739
+ if (typeof svc.remind !== "function") throw new Error("VALIDATION_FAILED: remind is not supported");
3740
+ return svc.remind(id, {
3741
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3742
+ comment: body.comment
3743
+ }, context);
3744
+ });
3745
+ threadRoute("request-info", (svc, id, body, context) => {
3746
+ if (typeof svc.requestInfo !== "function") throw new Error("VALIDATION_FAILED: request-info is not supported");
3747
+ return svc.requestInfo(id, {
3748
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3749
+ comment: body.comment
3750
+ }, context);
3751
+ });
3752
+ threadRoute("comment", (svc, id, body, context) => {
3753
+ if (typeof svc.comment !== "function") throw new Error("VALIDATION_FAILED: comment is not supported");
3754
+ return svc.comment(id, {
3755
+ actorId: body.actorId ?? body.actor_id ?? context?.userId,
3756
+ comment: body.comment
3757
+ }, context);
3758
+ });
3671
3759
  this.routeManager.register({
3672
3760
  method: "GET",
3673
3761
  path: `${dataPath}/approvals/requests/:id/actions`,