@objectstack/rest 5.1.0 → 6.0.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 +439 -271
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -19
- package/dist/index.d.ts +44 -19
- package/dist/index.js +438 -271
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -248,6 +248,7 @@ var RouteGroupBuilder = class {
|
|
|
248
248
|
};
|
|
249
249
|
|
|
250
250
|
// src/rest-server.ts
|
|
251
|
+
var import_meta = {};
|
|
251
252
|
var logError = (...args) => globalThis.console?.error(...args);
|
|
252
253
|
function mapDataError(error, object) {
|
|
253
254
|
if (error?.code === "CONCURRENT_UPDATE" || error?.name === "ConcurrentUpdateError") {
|
|
@@ -285,7 +286,7 @@ function mapDataError(error, object) {
|
|
|
285
286
|
}
|
|
286
287
|
const raw = String(error?.message ?? error ?? "");
|
|
287
288
|
const lower = raw.toLowerCase();
|
|
288
|
-
if (raw.includes("[
|
|
289
|
+
if (raw.includes("[EnvironmentKernelFactory]") && (lower.includes("missing database_url") || lower.includes("not found"))) {
|
|
289
290
|
const isProvisioning = lower.includes("status='provisioning'") || lower.includes("status='pending'");
|
|
290
291
|
const isFailed = lower.includes("status='failed'");
|
|
291
292
|
return {
|
|
@@ -442,13 +443,19 @@ function rowsToCsv(fields, rows, includeHeader) {
|
|
|
442
443
|
return lines.join("\r\n") + (lines.length > 0 ? "\r\n" : "");
|
|
443
444
|
}
|
|
444
445
|
var RestServer = class {
|
|
445
|
-
constructor(server, protocol, config = {}, kernelManager, envRegistry,
|
|
446
|
+
constructor(server, protocol, config = {}, kernelManager, envRegistry, defaultEnvironmentIdProvider, authServiceProvider, objectQLProvider, emailServiceProvider, sharingServiceProvider, reportsServiceProvider, approvalsServiceProvider, sharingRulesServiceProvider, i18nServiceProvider) {
|
|
447
|
+
/**
|
|
448
|
+
* Lazily load the OpenAPI spec JSON shipped by @objectstack/spec.
|
|
449
|
+
* Cached after first read. Resilient to missing files / parse errors
|
|
450
|
+
* so a degraded environment still boots.
|
|
451
|
+
*/
|
|
452
|
+
this._openApiSpecCache = void 0;
|
|
446
453
|
this.protocol = protocol;
|
|
447
454
|
this.config = this.normalizeConfig(config);
|
|
448
455
|
this.routeManager = new RouteManager(server);
|
|
449
456
|
this.kernelManager = kernelManager;
|
|
450
457
|
this.envRegistry = envRegistry;
|
|
451
|
-
this.
|
|
458
|
+
this.defaultEnvironmentIdProvider = defaultEnvironmentIdProvider;
|
|
452
459
|
this.authServiceProvider = authServiceProvider;
|
|
453
460
|
this.objectQLProvider = objectQLProvider;
|
|
454
461
|
this.emailServiceProvider = emailServiceProvider;
|
|
@@ -459,20 +466,20 @@ var RestServer = class {
|
|
|
459
466
|
this.i18nServiceProvider = i18nServiceProvider;
|
|
460
467
|
}
|
|
461
468
|
/**
|
|
462
|
-
* Resolve the protocol for a given request. When `
|
|
469
|
+
* Resolve the protocol for a given request. When `environmentId` is present
|
|
463
470
|
* and a KernelManager is wired, fetch the per-project kernel's
|
|
464
471
|
* `protocol` service so metadata / data / UI reads hit the project's
|
|
465
472
|
* own registry and datastore.
|
|
466
473
|
*
|
|
467
|
-
* When `
|
|
474
|
+
* When `environmentId` is absent on an unscoped route and an `envRegistry`
|
|
468
475
|
* is wired (runtime mode), the resolution chain is:
|
|
469
|
-
* 1. Hostname →
|
|
470
|
-
* 2. `X-
|
|
471
|
-
* 3. Default-project fallback (`
|
|
472
|
-
* `
|
|
476
|
+
* 1. Hostname → environmentId (`envRegistry.resolveByHostname`)
|
|
477
|
+
* 2. `X-Environment-Id` header → environmentId (`envRegistry.resolveById`)
|
|
478
|
+
* 3. Default-project fallback (`defaultEnvironmentIdProvider`, set by
|
|
479
|
+
* `createSingleEnvironmentPlugin`)
|
|
473
480
|
* 4. Control-plane protocol captured at boot.
|
|
474
481
|
*
|
|
475
|
-
* Special case: `
|
|
482
|
+
* Special case: `environmentId === 'platform'` is a reserved virtual id used
|
|
476
483
|
* by Studio to address the control plane through the regular project
|
|
477
484
|
* URL shape (`/projects/platform/...`). It is NOT a row in the projects
|
|
478
485
|
* table, so we must never call `KernelManager.getOrCreate('platform')`.
|
|
@@ -480,37 +487,37 @@ var RestServer = class {
|
|
|
480
487
|
* (and any other client) speak a single, uniform URL family without
|
|
481
488
|
* duplicating route logic for the platform surface.
|
|
482
489
|
*/
|
|
483
|
-
async resolveProtocol(
|
|
484
|
-
if (
|
|
485
|
-
if (!
|
|
490
|
+
async resolveProtocol(environmentId, req) {
|
|
491
|
+
if (environmentId === "platform") return this.protocol;
|
|
492
|
+
if (!environmentId && req && this.envRegistry && this.kernelManager) {
|
|
486
493
|
const host = this.extractHostname(req);
|
|
487
494
|
if (host) {
|
|
488
495
|
try {
|
|
489
496
|
const result = await this.envRegistry.resolveByHostname(host);
|
|
490
|
-
if (result?.
|
|
497
|
+
if (result?.environmentId) environmentId = result.environmentId;
|
|
491
498
|
} catch {
|
|
492
499
|
}
|
|
493
500
|
}
|
|
494
|
-
if (!
|
|
501
|
+
if (!environmentId && typeof this.envRegistry.resolveById === "function") {
|
|
495
502
|
const headerVal = this.extractProjectIdHeader(req);
|
|
496
503
|
if (headerVal) {
|
|
497
504
|
try {
|
|
498
505
|
const driver = await this.envRegistry.resolveById(headerVal);
|
|
499
|
-
if (driver)
|
|
506
|
+
if (driver) environmentId = headerVal;
|
|
500
507
|
} catch {
|
|
501
508
|
}
|
|
502
509
|
}
|
|
503
510
|
}
|
|
504
511
|
}
|
|
505
|
-
if (!
|
|
512
|
+
if (!environmentId && this.defaultEnvironmentIdProvider) {
|
|
506
513
|
try {
|
|
507
|
-
const def = this.
|
|
508
|
-
if (def)
|
|
514
|
+
const def = this.defaultEnvironmentIdProvider();
|
|
515
|
+
if (def) environmentId = def;
|
|
509
516
|
} catch {
|
|
510
517
|
}
|
|
511
518
|
}
|
|
512
|
-
if (!
|
|
513
|
-
const kernel = await this.kernelManager.getOrCreate(
|
|
519
|
+
if (!environmentId || !this.kernelManager) return this.protocol;
|
|
520
|
+
const kernel = await this.kernelManager.getOrCreate(environmentId);
|
|
514
521
|
return kernel.getServiceAsync("protocol");
|
|
515
522
|
}
|
|
516
523
|
/**
|
|
@@ -519,43 +526,43 @@ var RestServer = class {
|
|
|
519
526
|
* registered, so callers can short-circuit and skip translation rather
|
|
520
527
|
* than failing.
|
|
521
528
|
*
|
|
522
|
-
* Mirrors `resolveProtocol`'s lookup chain: explicit `
|
|
529
|
+
* Mirrors `resolveProtocol`'s lookup chain: explicit `environmentId` from the
|
|
523
530
|
* route → kernel-managed `i18n` service. Control-plane / unscoped
|
|
524
531
|
* requests intentionally return `undefined` because the platform kernel
|
|
525
532
|
* does not own per-app translation bundles.
|
|
526
533
|
*/
|
|
527
|
-
async resolveI18nService(
|
|
528
|
-
if (
|
|
529
|
-
if (!
|
|
534
|
+
async resolveI18nService(environmentId, req) {
|
|
535
|
+
if (environmentId === "platform") return void 0;
|
|
536
|
+
if (!environmentId && req && this.envRegistry && this.kernelManager) {
|
|
530
537
|
const host = this.extractHostname(req);
|
|
531
538
|
if (host) {
|
|
532
539
|
try {
|
|
533
540
|
const result = await this.envRegistry.resolveByHostname(host);
|
|
534
|
-
if (result?.
|
|
541
|
+
if (result?.environmentId) environmentId = result.environmentId;
|
|
535
542
|
} catch {
|
|
536
543
|
}
|
|
537
544
|
}
|
|
538
|
-
if (!
|
|
545
|
+
if (!environmentId && typeof this.envRegistry.resolveById === "function") {
|
|
539
546
|
const headerVal = this.extractProjectIdHeader(req);
|
|
540
547
|
if (headerVal) {
|
|
541
548
|
try {
|
|
542
549
|
const driver = await this.envRegistry.resolveById(headerVal);
|
|
543
|
-
if (driver)
|
|
550
|
+
if (driver) environmentId = headerVal;
|
|
544
551
|
} catch {
|
|
545
552
|
}
|
|
546
553
|
}
|
|
547
554
|
}
|
|
548
555
|
}
|
|
549
|
-
if (!
|
|
556
|
+
if (!environmentId && this.defaultEnvironmentIdProvider) {
|
|
550
557
|
try {
|
|
551
|
-
const def = this.
|
|
552
|
-
if (def)
|
|
558
|
+
const def = this.defaultEnvironmentIdProvider();
|
|
559
|
+
if (def) environmentId = def;
|
|
553
560
|
} catch {
|
|
554
561
|
}
|
|
555
562
|
}
|
|
556
|
-
if (
|
|
563
|
+
if (environmentId && this.kernelManager) {
|
|
557
564
|
try {
|
|
558
|
-
const kernel = await this.kernelManager.getOrCreate(
|
|
565
|
+
const kernel = await this.kernelManager.getOrCreate(environmentId);
|
|
559
566
|
const svc = await kernel.getServiceAsync("i18n");
|
|
560
567
|
if (svc) return svc;
|
|
561
568
|
} catch {
|
|
@@ -563,7 +570,7 @@ var RestServer = class {
|
|
|
563
570
|
}
|
|
564
571
|
if (this.i18nServiceProvider) {
|
|
565
572
|
try {
|
|
566
|
-
return await this.i18nServiceProvider(
|
|
573
|
+
return await this.i18nServiceProvider(environmentId);
|
|
567
574
|
} catch {
|
|
568
575
|
return void 0;
|
|
569
576
|
}
|
|
@@ -595,23 +602,23 @@ var RestServer = class {
|
|
|
595
602
|
* `undefined` for anonymous requests so callers can pass `context` as-is
|
|
596
603
|
* to the protocol layer (the SecurityPlugin treats undefined as anon).
|
|
597
604
|
*/
|
|
598
|
-
async resolveExecCtx(
|
|
605
|
+
async resolveExecCtx(environmentId, req) {
|
|
599
606
|
try {
|
|
600
|
-
if (!
|
|
607
|
+
if (!environmentId && req && this.envRegistry && this.kernelManager) {
|
|
601
608
|
const host = this.extractHostname(req);
|
|
602
609
|
if (host) {
|
|
603
610
|
try {
|
|
604
611
|
const result = await this.envRegistry.resolveByHostname(host);
|
|
605
|
-
if (result?.
|
|
612
|
+
if (result?.environmentId) environmentId = result.environmentId;
|
|
606
613
|
} catch {
|
|
607
614
|
}
|
|
608
615
|
}
|
|
609
|
-
if (!
|
|
616
|
+
if (!environmentId && typeof this.envRegistry.resolveById === "function") {
|
|
610
617
|
const headerVal = this.extractProjectIdHeader(req);
|
|
611
618
|
if (headerVal) {
|
|
612
619
|
try {
|
|
613
620
|
const driver = await this.envRegistry.resolveById(headerVal);
|
|
614
|
-
if (driver)
|
|
621
|
+
if (driver) environmentId = headerVal;
|
|
615
622
|
} catch {
|
|
616
623
|
}
|
|
617
624
|
}
|
|
@@ -619,13 +626,13 @@ var RestServer = class {
|
|
|
619
626
|
}
|
|
620
627
|
let authService;
|
|
621
628
|
let kernel;
|
|
622
|
-
if (
|
|
623
|
-
kernel = await this.kernelManager.getOrCreate(
|
|
629
|
+
if (environmentId && environmentId !== "platform" && this.kernelManager) {
|
|
630
|
+
kernel = await this.kernelManager.getOrCreate(environmentId);
|
|
624
631
|
authService = await kernel.getServiceAsync("auth").catch(() => void 0);
|
|
625
632
|
}
|
|
626
|
-
if (!authService && this.
|
|
633
|
+
if (!authService && this.defaultEnvironmentIdProvider && this.kernelManager) {
|
|
627
634
|
try {
|
|
628
|
-
const def = this.
|
|
635
|
+
const def = this.defaultEnvironmentIdProvider();
|
|
629
636
|
if (def) {
|
|
630
637
|
kernel = await this.kernelManager.getOrCreate(def);
|
|
631
638
|
authService = await kernel.getServiceAsync("auth").catch(() => void 0);
|
|
@@ -634,7 +641,7 @@ var RestServer = class {
|
|
|
634
641
|
}
|
|
635
642
|
}
|
|
636
643
|
if (!authService && this.authServiceProvider) {
|
|
637
|
-
authService = await this.authServiceProvider(
|
|
644
|
+
authService = await this.authServiceProvider(environmentId).catch(() => void 0);
|
|
638
645
|
}
|
|
639
646
|
if (!authService) return void 0;
|
|
640
647
|
let api = authService.api;
|
|
@@ -667,7 +674,7 @@ var RestServer = class {
|
|
|
667
674
|
ql = await kernel.getServiceAsync("objectql").catch(() => void 0);
|
|
668
675
|
}
|
|
669
676
|
if (!ql && this.objectQLProvider) {
|
|
670
|
-
ql = await this.objectQLProvider(
|
|
677
|
+
ql = await this.objectQLProvider(environmentId).catch(() => void 0);
|
|
671
678
|
}
|
|
672
679
|
if (ql && typeof ql.find === "function") {
|
|
673
680
|
const sysOpts = { context: { isSystem: true } };
|
|
@@ -709,12 +716,40 @@ var RestServer = class {
|
|
|
709
716
|
}
|
|
710
717
|
} catch {
|
|
711
718
|
}
|
|
719
|
+
let org_user_ids = [userId];
|
|
720
|
+
if (tenantId) {
|
|
721
|
+
try {
|
|
722
|
+
let ql;
|
|
723
|
+
if (kernel) {
|
|
724
|
+
ql = await kernel.getServiceAsync("objectql").catch(() => void 0);
|
|
725
|
+
}
|
|
726
|
+
if (!ql && this.objectQLProvider) {
|
|
727
|
+
ql = await this.objectQLProvider(environmentId).catch(() => void 0);
|
|
728
|
+
}
|
|
729
|
+
if (ql && typeof ql.find === "function") {
|
|
730
|
+
const sysOpts = { context: { isSystem: true } };
|
|
731
|
+
const memberRows = await ql.find("sys_member", {
|
|
732
|
+
where: { organization_id: tenantId },
|
|
733
|
+
limit: 1e3,
|
|
734
|
+
...sysOpts
|
|
735
|
+
}).catch(() => []);
|
|
736
|
+
const ids = /* @__PURE__ */ new Set([userId]);
|
|
737
|
+
for (const m of memberRows ?? []) {
|
|
738
|
+
const uid = m.user_id ?? m.userId;
|
|
739
|
+
if (typeof uid === "string" && uid.length > 0) ids.add(uid);
|
|
740
|
+
}
|
|
741
|
+
org_user_ids = Array.from(ids);
|
|
742
|
+
}
|
|
743
|
+
} catch {
|
|
744
|
+
}
|
|
745
|
+
}
|
|
712
746
|
return {
|
|
713
747
|
userId,
|
|
714
748
|
tenantId,
|
|
715
749
|
roles,
|
|
716
750
|
permissions,
|
|
717
|
-
isSystem: false
|
|
751
|
+
isSystem: false,
|
|
752
|
+
org_user_ids
|
|
718
753
|
};
|
|
719
754
|
} catch {
|
|
720
755
|
return void 0;
|
|
@@ -768,10 +803,10 @@ var RestServer = class {
|
|
|
768
803
|
* locale yields a match. Falls through unchanged for unsupported types
|
|
769
804
|
* or missing translations.
|
|
770
805
|
*/
|
|
771
|
-
async translateMetaItem(req, type,
|
|
806
|
+
async translateMetaItem(req, type, environmentId, item) {
|
|
772
807
|
if (!item || typeof item !== "object") return item;
|
|
773
808
|
if (type !== "view" && type !== "action" && type !== "object") return item;
|
|
774
|
-
const i18n = await this.resolveI18nService(
|
|
809
|
+
const i18n = await this.resolveI18nService(environmentId, req);
|
|
775
810
|
const bundle = this.buildTranslationBundle(i18n);
|
|
776
811
|
if (!bundle) return item;
|
|
777
812
|
const locale = this.extractLocale(req, i18n);
|
|
@@ -782,10 +817,10 @@ var RestServer = class {
|
|
|
782
817
|
/**
|
|
783
818
|
* Translate a list of metadata documents using `translateMetaItem`.
|
|
784
819
|
*/
|
|
785
|
-
async translateMetaItems(req, type,
|
|
820
|
+
async translateMetaItems(req, type, environmentId, items) {
|
|
786
821
|
if (!Array.isArray(items)) return items;
|
|
787
822
|
if (type !== "view" && type !== "action" && type !== "object") return items;
|
|
788
|
-
const i18n = await this.resolveI18nService(
|
|
823
|
+
const i18n = await this.resolveI18nService(environmentId, req);
|
|
789
824
|
const bundle = this.buildTranslationBundle(i18n);
|
|
790
825
|
if (!bundle) return items;
|
|
791
826
|
const locale = this.extractLocale(req, i18n);
|
|
@@ -819,7 +854,7 @@ var RestServer = class {
|
|
|
819
854
|
return String(host).split(":")[0].toLowerCase();
|
|
820
855
|
}
|
|
821
856
|
/**
|
|
822
|
-
* Pull the `X-
|
|
857
|
+
* Pull the `X-Environment-Id` header from a Node- or Fetch-style request.
|
|
823
858
|
* Header names are case-insensitive; we probe both casings to cover
|
|
824
859
|
* adapters that don't normalize headers (e.g. raw Node http).
|
|
825
860
|
*/
|
|
@@ -828,9 +863,9 @@ var RestServer = class {
|
|
|
828
863
|
if (!headers) return void 0;
|
|
829
864
|
let val;
|
|
830
865
|
if (typeof headers.get === "function") {
|
|
831
|
-
val = headers.get("x-
|
|
866
|
+
val = headers.get("x-environment-id") ?? headers.get("X-Environment-Id");
|
|
832
867
|
} else {
|
|
833
|
-
val = headers["x-
|
|
868
|
+
val = headers["x-environment-id"] ?? headers["X-Environment-Id"];
|
|
834
869
|
}
|
|
835
870
|
if (Array.isArray(val)) val = val[0];
|
|
836
871
|
if (typeof val !== "string") return void 0;
|
|
@@ -856,6 +891,7 @@ var RestServer = class {
|
|
|
856
891
|
enableUi: api.enableUi ?? true,
|
|
857
892
|
enableBatch: api.enableBatch ?? true,
|
|
858
893
|
enableDiscovery: api.enableDiscovery ?? true,
|
|
894
|
+
enableOpenApi: api.enableOpenApi ?? true,
|
|
859
895
|
enableSearch: api.enableSearch ?? true,
|
|
860
896
|
enableProjectScoping: api.enableProjectScoping ?? false,
|
|
861
897
|
projectResolution: api.projectResolution ?? "auto",
|
|
@@ -914,16 +950,16 @@ var RestServer = class {
|
|
|
914
950
|
}
|
|
915
951
|
/**
|
|
916
952
|
* Get the project-scoped base path for a given unscoped base.
|
|
917
|
-
* Example: `/api/v1` → `/api/v1/
|
|
953
|
+
* Example: `/api/v1` → `/api/v1/environments/:environmentId`.
|
|
918
954
|
*/
|
|
919
955
|
getScopedBasePath(basePath) {
|
|
920
|
-
return `${basePath}/
|
|
956
|
+
return `${basePath}/environments/:environmentId`;
|
|
921
957
|
}
|
|
922
958
|
/**
|
|
923
959
|
* Register all REST API routes
|
|
924
960
|
*
|
|
925
961
|
* When `enableProjectScoping` is true, routes are registered under
|
|
926
|
-
* `/api/v1/
|
|
962
|
+
* `/api/v1/environments/:environmentId/...`. The `projectResolution` strategy
|
|
927
963
|
* controls whether unscoped legacy routes remain available:
|
|
928
964
|
* - `required` → only scoped routes registered.
|
|
929
965
|
* - `optional` / `auto` → both scoped and unscoped routes registered.
|
|
@@ -935,6 +971,9 @@ var RestServer = class {
|
|
|
935
971
|
if (this.config.api.enableDiscovery) {
|
|
936
972
|
this.registerDiscoveryEndpoints(bp);
|
|
937
973
|
}
|
|
974
|
+
if (this.config.api.enableOpenApi ?? true) {
|
|
975
|
+
this.registerOpenApiEndpoints(bp);
|
|
976
|
+
}
|
|
938
977
|
if (this.config.api.enableMetadata) {
|
|
939
978
|
this.registerMetadataEndpoints(bp);
|
|
940
979
|
}
|
|
@@ -974,12 +1013,12 @@ var RestServer = class {
|
|
|
974
1013
|
* Register discovery endpoints
|
|
975
1014
|
*/
|
|
976
1015
|
registerDiscoveryEndpoints(basePath) {
|
|
977
|
-
const isScoped = basePath.includes("/
|
|
1016
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
978
1017
|
const discoveryHandler = async (req, res) => {
|
|
979
1018
|
try {
|
|
980
1019
|
const discovery = await this.protocol.getDiscovery();
|
|
981
1020
|
discovery.version = this.config.api.version;
|
|
982
|
-
const realBase = isScoped ? basePath.replace(":
|
|
1021
|
+
const realBase = isScoped ? basePath.replace(":environmentId", req.params?.environmentId ?? ":environmentId") : basePath;
|
|
983
1022
|
if (discovery.routes) {
|
|
984
1023
|
if (this.config.api.enableCrud) {
|
|
985
1024
|
discovery.routes.data = `${realBase}${this.config.crud.dataPrefix}`;
|
|
@@ -991,7 +1030,7 @@ var RestServer = class {
|
|
|
991
1030
|
discovery.routes.ui = `${realBase}/ui`;
|
|
992
1031
|
}
|
|
993
1032
|
if (discovery.routes.auth) {
|
|
994
|
-
const unscopedBase = isScoped ? basePath.replace(/\/projects\/:
|
|
1033
|
+
const unscopedBase = isScoped ? basePath.replace(/\/projects\/:environmentId$/, "") : basePath;
|
|
995
1034
|
discovery.routes.auth = `${unscopedBase}/auth`;
|
|
996
1035
|
}
|
|
997
1036
|
}
|
|
@@ -999,7 +1038,7 @@ var RestServer = class {
|
|
|
999
1038
|
enabled: this.config.api.enableProjectScoping,
|
|
1000
1039
|
resolution: this.config.api.projectResolution,
|
|
1001
1040
|
scoped: isScoped,
|
|
1002
|
-
|
|
1041
|
+
environmentId: isScoped ? req.params?.environmentId : void 0
|
|
1003
1042
|
};
|
|
1004
1043
|
res.json(discovery);
|
|
1005
1044
|
} catch (error) {
|
|
@@ -1026,21 +1065,150 @@ var RestServer = class {
|
|
|
1026
1065
|
}
|
|
1027
1066
|
});
|
|
1028
1067
|
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Register OpenAPI 3.1 spec + interactive docs viewer.
|
|
1070
|
+
*
|
|
1071
|
+
* GET <basePath>/openapi.json → enriched OpenAPI document
|
|
1072
|
+
* GET <basePath>/docs → Scalar-rendered HTML (CDN, no dep)
|
|
1073
|
+
*
|
|
1074
|
+
* Enrichment at request time:
|
|
1075
|
+
* - servers[0].url — derived from the request's Host header
|
|
1076
|
+
* - paths — `{object}` placeholders expanded into
|
|
1077
|
+
* one concrete path per registered object
|
|
1078
|
+
* from the protocol's discovery metadata
|
|
1079
|
+
*
|
|
1080
|
+
* The base spec is loaded lazily from @objectstack/spec/openapi.json
|
|
1081
|
+
* (shipped pre-generated by spec's build pipeline) so we don't pay
|
|
1082
|
+
* the cost of regenerating on every request, and a missing or
|
|
1083
|
+
* malformed file degrades to a stub instead of crashing.
|
|
1084
|
+
*/
|
|
1085
|
+
registerOpenApiEndpoints(basePath) {
|
|
1086
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1087
|
+
const openApiHandler = async (req, res) => {
|
|
1088
|
+
try {
|
|
1089
|
+
const spec = await this.loadOpenApiSpec();
|
|
1090
|
+
if (!spec) {
|
|
1091
|
+
res.status?.(503);
|
|
1092
|
+
res.json({
|
|
1093
|
+
error: "openapi_unavailable",
|
|
1094
|
+
message: "OpenAPI spec is not bundled with this runtime."
|
|
1095
|
+
});
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
const enriched = { ...spec, servers: [...spec.servers ?? []] };
|
|
1099
|
+
const host = req.headers?.host ?? req.headers?.["host"];
|
|
1100
|
+
const proto = req.headers?.["x-forwarded-proto"] || req.protocol || "http";
|
|
1101
|
+
if (host) {
|
|
1102
|
+
enriched.servers = [
|
|
1103
|
+
{ url: `${proto}://${host}`, description: "Current server" },
|
|
1104
|
+
...spec.servers ?? []
|
|
1105
|
+
];
|
|
1106
|
+
}
|
|
1107
|
+
try {
|
|
1108
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1109
|
+
const protocol = await this.resolveProtocol(environmentId, req);
|
|
1110
|
+
const items = await protocol?.getMetaItems?.({ type: "object" }).catch(() => null);
|
|
1111
|
+
const objects = Array.isArray(items?.items) ? items.items.map((i) => i?.name).filter(Boolean) : Array.isArray(items) ? items.map((i) => i?.name).filter(Boolean) : [];
|
|
1112
|
+
if (objects.length > 0 && enriched.paths) {
|
|
1113
|
+
const expanded = {};
|
|
1114
|
+
for (const [p, def] of Object.entries(enriched.paths)) {
|
|
1115
|
+
if (p.includes("{object}")) {
|
|
1116
|
+
expanded[p] = { ...def, "x-template": true };
|
|
1117
|
+
for (const obj of objects) {
|
|
1118
|
+
expanded[p.replace("{object}", obj)] = def;
|
|
1119
|
+
}
|
|
1120
|
+
} else {
|
|
1121
|
+
expanded[p] = def;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
enriched.paths = expanded;
|
|
1125
|
+
}
|
|
1126
|
+
} catch {
|
|
1127
|
+
}
|
|
1128
|
+
if (enriched.info) {
|
|
1129
|
+
enriched.info = {
|
|
1130
|
+
...enriched.info,
|
|
1131
|
+
version: this.config.api.version || enriched.info.version
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
res.json(enriched);
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
logError("[REST] openapi.json error:", error);
|
|
1137
|
+
sendError(res, error);
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
this.routeManager.register({
|
|
1141
|
+
method: "GET",
|
|
1142
|
+
path: `${basePath}/openapi.json`,
|
|
1143
|
+
handler: openApiHandler,
|
|
1144
|
+
metadata: {
|
|
1145
|
+
summary: "OpenAPI 3.1 specification (machine-readable)",
|
|
1146
|
+
tags: ["openapi"]
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
this.routeManager.register({
|
|
1150
|
+
method: "GET",
|
|
1151
|
+
path: `${basePath}/docs`,
|
|
1152
|
+
handler: async (req, res) => {
|
|
1153
|
+
const reqPath = req.path || req.url || `${basePath}/docs`;
|
|
1154
|
+
const apiBase = reqPath.replace(/\/docs\/?$/, "");
|
|
1155
|
+
const specUrl = `${apiBase}/openapi.json`;
|
|
1156
|
+
const html = `<!doctype html>
|
|
1157
|
+
<html>
|
|
1158
|
+
<head>
|
|
1159
|
+
<meta charset="utf-8" />
|
|
1160
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1161
|
+
<title>ObjectStack API Docs</title>
|
|
1162
|
+
</head>
|
|
1163
|
+
<body>
|
|
1164
|
+
<script id="api-reference" data-url="${specUrl}"></script>
|
|
1165
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
1166
|
+
</body>
|
|
1167
|
+
</html>`;
|
|
1168
|
+
if (res.setHeader) res.setHeader("content-type", "text/html; charset=utf-8");
|
|
1169
|
+
if (res.send) res.send(html);
|
|
1170
|
+
else if (res.body) res.body = html;
|
|
1171
|
+
else res.json?.(html);
|
|
1172
|
+
},
|
|
1173
|
+
metadata: {
|
|
1174
|
+
summary: "Interactive API docs (Scalar viewer)",
|
|
1175
|
+
tags: ["openapi"]
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
async loadOpenApiSpec() {
|
|
1180
|
+
if (this._openApiSpecCache !== void 0) return this._openApiSpecCache;
|
|
1181
|
+
try {
|
|
1182
|
+
const mod = await import("module");
|
|
1183
|
+
const requireFn = mod.createRequire(import_meta.url);
|
|
1184
|
+
const pkgJsonPath = requireFn.resolve("@objectstack/spec/package.json");
|
|
1185
|
+
const pathMod = await import("path");
|
|
1186
|
+
const fsMod = await import("fs");
|
|
1187
|
+
const specPath = pathMod.join(pathMod.dirname(pkgJsonPath), "json-schema", "openapi.json");
|
|
1188
|
+
const raw = await fsMod.promises.readFile(specPath, "utf-8");
|
|
1189
|
+
this._openApiSpecCache = JSON.parse(raw);
|
|
1190
|
+
return this._openApiSpecCache;
|
|
1191
|
+
} catch (err) {
|
|
1192
|
+
logError("[REST] Failed to load OpenAPI spec:", err?.message ?? err);
|
|
1193
|
+
this._openApiSpecCache = null;
|
|
1194
|
+
return null;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1029
1197
|
/**
|
|
1030
1198
|
* Register metadata endpoints
|
|
1031
1199
|
*/
|
|
1032
1200
|
registerMetadataEndpoints(basePath) {
|
|
1033
1201
|
const { metadata } = this.config;
|
|
1034
1202
|
const metaPath = `${basePath}${metadata.prefix}`;
|
|
1035
|
-
const isScoped = basePath.includes("/
|
|
1203
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1036
1204
|
if (metadata.endpoints.types !== false) {
|
|
1037
1205
|
this.routeManager.register({
|
|
1038
1206
|
method: "GET",
|
|
1039
1207
|
path: metaPath,
|
|
1040
1208
|
handler: async (req, res) => {
|
|
1041
1209
|
try {
|
|
1042
|
-
const
|
|
1043
|
-
const p = await this.resolveProtocol(
|
|
1210
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1211
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1044
1212
|
const types = await p.getMetaTypes();
|
|
1045
1213
|
res.json(types);
|
|
1046
1214
|
} catch (error) {
|
|
@@ -1061,14 +1229,14 @@ var RestServer = class {
|
|
|
1061
1229
|
handler: async (req, res) => {
|
|
1062
1230
|
try {
|
|
1063
1231
|
const packageId = req.query?.package || void 0;
|
|
1064
|
-
const
|
|
1065
|
-
const p = await this.resolveProtocol(
|
|
1232
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1233
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1066
1234
|
const items = await p.getMetaItems({
|
|
1067
1235
|
type: req.params.type,
|
|
1068
1236
|
packageId,
|
|
1069
|
-
...
|
|
1237
|
+
...environmentId ? { environmentId } : {}
|
|
1070
1238
|
});
|
|
1071
|
-
const translated = await this.translateMetaItems(req, req.params.type,
|
|
1239
|
+
const translated = await this.translateMetaItems(req, req.params.type, environmentId, items);
|
|
1072
1240
|
res.header("Vary", "Accept-Language");
|
|
1073
1241
|
res.json(translated);
|
|
1074
1242
|
} catch (error) {
|
|
@@ -1088,8 +1256,8 @@ var RestServer = class {
|
|
|
1088
1256
|
path: `${metaPath}/:type/:name`,
|
|
1089
1257
|
handler: async (req, res) => {
|
|
1090
1258
|
try {
|
|
1091
|
-
const
|
|
1092
|
-
const p = await this.resolveProtocol(
|
|
1259
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1260
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1093
1261
|
if (metadata.enableCache && p.getMetaItemCached) {
|
|
1094
1262
|
const cacheRequest = {
|
|
1095
1263
|
ifNoneMatch: req.headers["if-none-match"],
|
|
@@ -1099,7 +1267,7 @@ var RestServer = class {
|
|
|
1099
1267
|
type: req.params.type,
|
|
1100
1268
|
name: req.params.name,
|
|
1101
1269
|
cacheRequest,
|
|
1102
|
-
...
|
|
1270
|
+
...environmentId ? { environmentId } : {}
|
|
1103
1271
|
});
|
|
1104
1272
|
if (result.notModified) {
|
|
1105
1273
|
res.status(304).send();
|
|
@@ -1118,7 +1286,7 @@ var RestServer = class {
|
|
|
1118
1286
|
res.header("Cache-Control", directives + maxAge);
|
|
1119
1287
|
}
|
|
1120
1288
|
res.header("Vary", "Accept-Language");
|
|
1121
|
-
res.json(await this.translateMetaItem(req, req.params.type,
|
|
1289
|
+
res.json(await this.translateMetaItem(req, req.params.type, environmentId, result.data));
|
|
1122
1290
|
} else {
|
|
1123
1291
|
const packageId = req.query?.package || void 0;
|
|
1124
1292
|
const item = await p.getMetaItem({
|
|
@@ -1127,7 +1295,7 @@ var RestServer = class {
|
|
|
1127
1295
|
packageId
|
|
1128
1296
|
});
|
|
1129
1297
|
res.header("Vary", "Accept-Language");
|
|
1130
|
-
res.json(await this.translateMetaItem(req, req.params.type,
|
|
1298
|
+
res.json(await this.translateMetaItem(req, req.params.type, environmentId, item));
|
|
1131
1299
|
}
|
|
1132
1300
|
} catch (error) {
|
|
1133
1301
|
logError("[REST] Unhandled error:", error);
|
|
@@ -1145,8 +1313,8 @@ var RestServer = class {
|
|
|
1145
1313
|
path: `${metaPath}/:type/:name`,
|
|
1146
1314
|
handler: async (req, res) => {
|
|
1147
1315
|
try {
|
|
1148
|
-
const
|
|
1149
|
-
const p = await this.resolveProtocol(
|
|
1316
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1317
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1150
1318
|
if (!p.saveMetaItem) {
|
|
1151
1319
|
res.status(501).json({ error: "Save operation not supported by protocol implementation" });
|
|
1152
1320
|
return;
|
|
@@ -1161,7 +1329,7 @@ var RestServer = class {
|
|
|
1161
1329
|
type: req.params.type,
|
|
1162
1330
|
name: req.params.name,
|
|
1163
1331
|
item,
|
|
1164
|
-
...
|
|
1332
|
+
...environmentId ? { environmentId } : {},
|
|
1165
1333
|
...parentVersion !== void 0 ? { parentVersion } : {},
|
|
1166
1334
|
...actor ? { actor } : {}
|
|
1167
1335
|
});
|
|
@@ -1181,8 +1349,8 @@ var RestServer = class {
|
|
|
1181
1349
|
path: `${metaPath}/:type/:name`,
|
|
1182
1350
|
handler: async (req, res) => {
|
|
1183
1351
|
try {
|
|
1184
|
-
const
|
|
1185
|
-
const p = await this.resolveProtocol(
|
|
1352
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1353
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1186
1354
|
if (!p.deleteMetaItem) {
|
|
1187
1355
|
res.status(501).json({
|
|
1188
1356
|
error: "Reset operation not supported by protocol implementation"
|
|
@@ -1196,7 +1364,7 @@ var RestServer = class {
|
|
|
1196
1364
|
const result = await p.deleteMetaItem({
|
|
1197
1365
|
type: req.params.type,
|
|
1198
1366
|
name: req.params.name,
|
|
1199
|
-
...
|
|
1367
|
+
...environmentId ? { environmentId } : {},
|
|
1200
1368
|
...parentVersion !== void 0 ? { parentVersion } : {},
|
|
1201
1369
|
...actor ? { actor } : {}
|
|
1202
1370
|
});
|
|
@@ -1216,8 +1384,8 @@ var RestServer = class {
|
|
|
1216
1384
|
path: `${metaPath}/:type/:name/history`,
|
|
1217
1385
|
handler: async (req, res) => {
|
|
1218
1386
|
try {
|
|
1219
|
-
const
|
|
1220
|
-
const p = await this.resolveProtocol(
|
|
1387
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1388
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1221
1389
|
if (!p.historyMetaItem) {
|
|
1222
1390
|
res.status(501).json({
|
|
1223
1391
|
error: "History query not supported by protocol implementation"
|
|
@@ -1229,7 +1397,7 @@ var RestServer = class {
|
|
|
1229
1397
|
const result = await p.historyMetaItem({
|
|
1230
1398
|
type: req.params.type,
|
|
1231
1399
|
name: req.params.name,
|
|
1232
|
-
...
|
|
1400
|
+
...environmentId ? { environmentId } : {},
|
|
1233
1401
|
...sinceSeq !== void 0 && Number.isFinite(sinceSeq) ? { sinceSeq } : {},
|
|
1234
1402
|
...limit !== void 0 && Number.isFinite(limit) ? { limit } : {}
|
|
1235
1403
|
});
|
|
@@ -1250,8 +1418,8 @@ var RestServer = class {
|
|
|
1250
1418
|
path: `${metaPath}/:type/:section/:name`,
|
|
1251
1419
|
handler: async (req, res) => {
|
|
1252
1420
|
try {
|
|
1253
|
-
const
|
|
1254
|
-
const p = await this.resolveProtocol(
|
|
1421
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1422
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1255
1423
|
const compoundName = `${req.params.section}/${req.params.name}`;
|
|
1256
1424
|
const packageId = req.query?.package || void 0;
|
|
1257
1425
|
const item = await p.getMetaItem({
|
|
@@ -1260,7 +1428,7 @@ var RestServer = class {
|
|
|
1260
1428
|
packageId
|
|
1261
1429
|
});
|
|
1262
1430
|
res.header("Vary", "Accept-Language");
|
|
1263
|
-
res.json(await this.translateMetaItem(req, req.params.type,
|
|
1431
|
+
res.json(await this.translateMetaItem(req, req.params.type, environmentId, item));
|
|
1264
1432
|
} catch (error) {
|
|
1265
1433
|
logError("[REST] Unhandled error:", error);
|
|
1266
1434
|
sendError(res, error);
|
|
@@ -1277,8 +1445,8 @@ var RestServer = class {
|
|
|
1277
1445
|
path: `${metaPath}/:type/:section/:name`,
|
|
1278
1446
|
handler: async (req, res) => {
|
|
1279
1447
|
try {
|
|
1280
|
-
const
|
|
1281
|
-
const p = await this.resolveProtocol(
|
|
1448
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1449
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1282
1450
|
if (!p.saveMetaItem) {
|
|
1283
1451
|
res.status(501).json({ error: "Save operation not supported by protocol implementation" });
|
|
1284
1452
|
return;
|
|
@@ -1292,7 +1460,7 @@ var RestServer = class {
|
|
|
1292
1460
|
type: req.params.type,
|
|
1293
1461
|
name: compoundName,
|
|
1294
1462
|
item: req.body,
|
|
1295
|
-
...
|
|
1463
|
+
...environmentId ? { environmentId } : {},
|
|
1296
1464
|
...parentVersion !== void 0 ? { parentVersion } : {},
|
|
1297
1465
|
...actor ? { actor } : {}
|
|
1298
1466
|
});
|
|
@@ -1313,19 +1481,19 @@ var RestServer = class {
|
|
|
1313
1481
|
*/
|
|
1314
1482
|
registerUiEndpoints(basePath) {
|
|
1315
1483
|
const uiPath = `${basePath}/ui`;
|
|
1316
|
-
const isScoped = basePath.includes("/
|
|
1484
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1317
1485
|
this.routeManager.register({
|
|
1318
1486
|
method: "GET",
|
|
1319
1487
|
path: `${uiPath}/view/:object/:type`,
|
|
1320
1488
|
handler: async (req, res) => {
|
|
1321
1489
|
try {
|
|
1322
|
-
const
|
|
1323
|
-
const p = await this.resolveProtocol(
|
|
1490
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1491
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1324
1492
|
if (p.getUiView) {
|
|
1325
1493
|
const view = await p.getUiView({
|
|
1326
1494
|
object: req.params.object,
|
|
1327
1495
|
type: req.params.type,
|
|
1328
|
-
...
|
|
1496
|
+
...environmentId ? { environmentId } : {}
|
|
1329
1497
|
});
|
|
1330
1498
|
res.json(view);
|
|
1331
1499
|
} else {
|
|
@@ -1348,7 +1516,7 @@ var RestServer = class {
|
|
|
1348
1516
|
registerCrudEndpoints(basePath) {
|
|
1349
1517
|
const { crud } = this.config;
|
|
1350
1518
|
const dataPath = `${basePath}${crud.dataPrefix}`;
|
|
1351
|
-
const isScoped = basePath.includes("/
|
|
1519
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1352
1520
|
const operations = crud.operations;
|
|
1353
1521
|
if (operations.list) {
|
|
1354
1522
|
this.routeManager.register({
|
|
@@ -1356,14 +1524,14 @@ var RestServer = class {
|
|
|
1356
1524
|
path: `${dataPath}/:object`,
|
|
1357
1525
|
handler: async (req, res) => {
|
|
1358
1526
|
try {
|
|
1359
|
-
const
|
|
1360
|
-
const p = await this.resolveProtocol(
|
|
1361
|
-
const context = await this.resolveExecCtx(
|
|
1527
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1528
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1529
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1362
1530
|
if (this.enforceAuth(req, res, context)) return;
|
|
1363
1531
|
const result = await p.findData({
|
|
1364
1532
|
object: req.params.object,
|
|
1365
1533
|
query: req.query,
|
|
1366
|
-
...
|
|
1534
|
+
...environmentId ? { environmentId } : {},
|
|
1367
1535
|
...context ? { context } : {}
|
|
1368
1536
|
});
|
|
1369
1537
|
res.json(result);
|
|
@@ -1389,17 +1557,17 @@ var RestServer = class {
|
|
|
1389
1557
|
path: `${dataPath}/:object/:id`,
|
|
1390
1558
|
handler: async (req, res) => {
|
|
1391
1559
|
try {
|
|
1392
|
-
const
|
|
1393
|
-
const p = await this.resolveProtocol(
|
|
1560
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1561
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1394
1562
|
const { select, expand } = req.query || {};
|
|
1395
|
-
const context = await this.resolveExecCtx(
|
|
1563
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1396
1564
|
if (this.enforceAuth(req, res, context)) return;
|
|
1397
1565
|
const result = await p.getData({
|
|
1398
1566
|
object: req.params.object,
|
|
1399
1567
|
id: req.params.id,
|
|
1400
1568
|
...select != null ? { select } : {},
|
|
1401
1569
|
...expand != null ? { expand } : {},
|
|
1402
|
-
...
|
|
1570
|
+
...environmentId ? { environmentId } : {},
|
|
1403
1571
|
...context ? { context } : {}
|
|
1404
1572
|
});
|
|
1405
1573
|
res.json(result);
|
|
@@ -1421,14 +1589,14 @@ var RestServer = class {
|
|
|
1421
1589
|
path: `${dataPath}/:object`,
|
|
1422
1590
|
handler: async (req, res) => {
|
|
1423
1591
|
try {
|
|
1424
|
-
const
|
|
1425
|
-
const p = await this.resolveProtocol(
|
|
1426
|
-
const context = await this.resolveExecCtx(
|
|
1592
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1593
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1594
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1427
1595
|
if (this.enforceAuth(req, res, context)) return;
|
|
1428
1596
|
const result = await p.createData({
|
|
1429
1597
|
object: req.params.object,
|
|
1430
1598
|
data: req.body,
|
|
1431
|
-
...
|
|
1599
|
+
...environmentId ? { environmentId } : {},
|
|
1432
1600
|
...context ? { context } : {}
|
|
1433
1601
|
});
|
|
1434
1602
|
res.status(201).json(result);
|
|
@@ -1450,14 +1618,14 @@ var RestServer = class {
|
|
|
1450
1618
|
path: `${dataPath}/:object/query`,
|
|
1451
1619
|
handler: async (req, res) => {
|
|
1452
1620
|
try {
|
|
1453
|
-
const
|
|
1454
|
-
const p = await this.resolveProtocol(
|
|
1455
|
-
const context = await this.resolveExecCtx(
|
|
1621
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1622
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1623
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1456
1624
|
if (this.enforceAuth(req, res, context)) return;
|
|
1457
1625
|
const result = await p.findData({
|
|
1458
1626
|
object: req.params.object,
|
|
1459
1627
|
query: req.body || {},
|
|
1460
|
-
...
|
|
1628
|
+
...environmentId ? { environmentId } : {},
|
|
1461
1629
|
...context ? { context } : {}
|
|
1462
1630
|
});
|
|
1463
1631
|
res.json(result);
|
|
@@ -1479,9 +1647,9 @@ var RestServer = class {
|
|
|
1479
1647
|
path: `${dataPath}/:object/:id`,
|
|
1480
1648
|
handler: async (req, res) => {
|
|
1481
1649
|
try {
|
|
1482
|
-
const
|
|
1483
|
-
const p = await this.resolveProtocol(
|
|
1484
|
-
const context = await this.resolveExecCtx(
|
|
1650
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1651
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1652
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1485
1653
|
if (this.enforceAuth(req, res, context)) return;
|
|
1486
1654
|
const ifMatchHeader = req.headers?.["if-match"] ?? req.headers?.["If-Match"];
|
|
1487
1655
|
const bodyVersion = req.body && typeof req.body === "object" ? req.body.expectedVersion : void 0;
|
|
@@ -1496,7 +1664,7 @@ var RestServer = class {
|
|
|
1496
1664
|
id: req.params.id,
|
|
1497
1665
|
data,
|
|
1498
1666
|
...expectedVersion ? { expectedVersion: String(expectedVersion) } : {},
|
|
1499
|
-
...
|
|
1667
|
+
...environmentId ? { environmentId } : {},
|
|
1500
1668
|
...context ? { context } : {}
|
|
1501
1669
|
});
|
|
1502
1670
|
res.json(result);
|
|
@@ -1518,9 +1686,9 @@ var RestServer = class {
|
|
|
1518
1686
|
path: `${dataPath}/:object/:id`,
|
|
1519
1687
|
handler: async (req, res) => {
|
|
1520
1688
|
try {
|
|
1521
|
-
const
|
|
1522
|
-
const p = await this.resolveProtocol(
|
|
1523
|
-
const context = await this.resolveExecCtx(
|
|
1689
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1690
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1691
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1524
1692
|
if (this.enforceAuth(req, res, context)) return;
|
|
1525
1693
|
const ifMatchHeader = req.headers?.["if-match"] ?? req.headers?.["If-Match"];
|
|
1526
1694
|
const queryVersion = req.query && typeof req.query === "object" ? req.query.expectedVersion : void 0;
|
|
@@ -1529,7 +1697,7 @@ var RestServer = class {
|
|
|
1529
1697
|
object: req.params.object,
|
|
1530
1698
|
id: req.params.id,
|
|
1531
1699
|
...expectedVersion ? { expectedVersion: String(expectedVersion) } : {},
|
|
1532
|
-
...
|
|
1700
|
+
...environmentId ? { environmentId } : {},
|
|
1533
1701
|
...context ? { context } : {}
|
|
1534
1702
|
});
|
|
1535
1703
|
res.json(result);
|
|
@@ -1555,7 +1723,7 @@ var RestServer = class {
|
|
|
1555
1723
|
* POST {basePath}/data/lead/:id/convert — M10.6 lead conversion.
|
|
1556
1724
|
*/
|
|
1557
1725
|
registerDataActionEndpoints(basePath) {
|
|
1558
|
-
const isScoped = basePath.includes("/
|
|
1726
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1559
1727
|
const { crud } = this.config;
|
|
1560
1728
|
const dataPath = `${basePath}${crud.dataPrefix}`;
|
|
1561
1729
|
this.routeManager.register({
|
|
@@ -1563,9 +1731,9 @@ var RestServer = class {
|
|
|
1563
1731
|
path: `${dataPath}/lead/:id/convert`,
|
|
1564
1732
|
handler: async (req, res) => {
|
|
1565
1733
|
try {
|
|
1566
|
-
const
|
|
1567
|
-
const p = await this.resolveProtocol(
|
|
1568
|
-
const context = await this.resolveExecCtx(
|
|
1734
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1735
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1736
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1569
1737
|
if (this.enforceAuth(req, res, context)) return;
|
|
1570
1738
|
const convertLead = p.convertLead;
|
|
1571
1739
|
if (typeof convertLead !== "function") {
|
|
@@ -1598,9 +1766,9 @@ var RestServer = class {
|
|
|
1598
1766
|
path: `${dataPath}/:object/import`,
|
|
1599
1767
|
handler: async (req, res) => {
|
|
1600
1768
|
try {
|
|
1601
|
-
const
|
|
1602
|
-
const p = await this.resolveProtocol(
|
|
1603
|
-
const context = await this.resolveExecCtx(
|
|
1769
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1770
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1771
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1604
1772
|
if (this.enforceAuth(req, res, context)) return;
|
|
1605
1773
|
const objectName = String(req.params.object || "");
|
|
1606
1774
|
if (!objectName) {
|
|
@@ -1681,9 +1849,9 @@ var RestServer = class {
|
|
|
1681
1849
|
path: `${dataPath}/:object/export`,
|
|
1682
1850
|
handler: async (req, res) => {
|
|
1683
1851
|
try {
|
|
1684
|
-
const
|
|
1685
|
-
const p = await this.resolveProtocol(
|
|
1686
|
-
const context = await this.resolveExecCtx(
|
|
1852
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1853
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1854
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1687
1855
|
if (this.enforceAuth(req, res, context)) return;
|
|
1688
1856
|
const objectName = String(req.params.object || "");
|
|
1689
1857
|
if (!objectName) {
|
|
@@ -1732,7 +1900,7 @@ var RestServer = class {
|
|
|
1732
1900
|
}
|
|
1733
1901
|
if (!fields || fields.length === 0) {
|
|
1734
1902
|
try {
|
|
1735
|
-
const schema = await p.getObjectSchema?.(objectName,
|
|
1903
|
+
const schema = await p.getObjectSchema?.(objectName, environmentId);
|
|
1736
1904
|
const schemaFields = schema?.fields;
|
|
1737
1905
|
if (Array.isArray(schemaFields)) {
|
|
1738
1906
|
fields = schemaFields.map((f) => f.name).filter((n) => typeof n === "string");
|
|
@@ -1766,7 +1934,7 @@ var RestServer = class {
|
|
|
1766
1934
|
$top: take,
|
|
1767
1935
|
$skip: skip
|
|
1768
1936
|
},
|
|
1769
|
-
...
|
|
1937
|
+
...environmentId ? { environmentId } : {},
|
|
1770
1938
|
...context ? { context } : {}
|
|
1771
1939
|
};
|
|
1772
1940
|
const result = await p.findData(findArgs);
|
|
@@ -1814,15 +1982,15 @@ var RestServer = class {
|
|
|
1814
1982
|
* GET {basePath}/search?q=acme&objects=lead,account&limit=20&perObject=5
|
|
1815
1983
|
*/
|
|
1816
1984
|
registerSearchEndpoints(basePath) {
|
|
1817
|
-
const isScoped = basePath.includes("/
|
|
1985
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1818
1986
|
this.routeManager.register({
|
|
1819
1987
|
method: "GET",
|
|
1820
1988
|
path: `${basePath}/search`,
|
|
1821
1989
|
handler: async (req, res) => {
|
|
1822
1990
|
try {
|
|
1823
|
-
const
|
|
1824
|
-
const p = await this.resolveProtocol(
|
|
1825
|
-
const context = await this.resolveExecCtx(
|
|
1991
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1992
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1993
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1826
1994
|
if (this.enforceAuth(req, res, context)) return;
|
|
1827
1995
|
const searchAll = p.searchAll;
|
|
1828
1996
|
if (typeof searchAll !== "function") {
|
|
@@ -1874,14 +2042,14 @@ var RestServer = class {
|
|
|
1874
2042
|
* }
|
|
1875
2043
|
*/
|
|
1876
2044
|
registerEmailEndpoints(basePath) {
|
|
1877
|
-
const isScoped = basePath.includes("/
|
|
2045
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1878
2046
|
this.routeManager.register({
|
|
1879
2047
|
method: "POST",
|
|
1880
2048
|
path: `${basePath}/email/send`,
|
|
1881
2049
|
handler: async (req, res) => {
|
|
1882
2050
|
try {
|
|
1883
|
-
const
|
|
1884
|
-
const context = await this.resolveExecCtx(
|
|
2051
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2052
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1885
2053
|
if (this.enforceAuth(req, res, context)) return;
|
|
1886
2054
|
if (!this.emailServiceProvider) {
|
|
1887
2055
|
res.status(501).json({
|
|
@@ -1890,7 +2058,7 @@ var RestServer = class {
|
|
|
1890
2058
|
});
|
|
1891
2059
|
return;
|
|
1892
2060
|
}
|
|
1893
|
-
const emailService = await this.emailServiceProvider(
|
|
2061
|
+
const emailService = await this.emailServiceProvider(environmentId).catch(() => void 0);
|
|
1894
2062
|
if (!emailService || typeof emailService.send !== "function") {
|
|
1895
2063
|
res.status(501).json({
|
|
1896
2064
|
code: "NOT_IMPLEMENTED",
|
|
@@ -1969,7 +2137,7 @@ var RestServer = class {
|
|
|
1969
2137
|
* `mapViewSpecToEmbeddableConfig` expects.
|
|
1970
2138
|
*/
|
|
1971
2139
|
registerFormEndpoints(basePath) {
|
|
1972
|
-
const isScoped = basePath.includes("/
|
|
2140
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1973
2141
|
const slugMatchesPublicLink = (publicLink, slug) => {
|
|
1974
2142
|
if (!publicLink || typeof publicLink !== "string") return false;
|
|
1975
2143
|
const normalized = publicLink.replace(/^\/+/, "").replace(/^forms\//, "");
|
|
@@ -1999,12 +2167,12 @@ var RestServer = class {
|
|
|
1999
2167
|
}
|
|
2000
2168
|
return null;
|
|
2001
2169
|
};
|
|
2002
|
-
const resolveFormBySlug = async (
|
|
2003
|
-
const p = await this.resolveProtocol(
|
|
2170
|
+
const resolveFormBySlug = async (environmentId, req, slug) => {
|
|
2171
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
2004
2172
|
if (typeof p.getMetaItems !== "function") return null;
|
|
2005
2173
|
const result = await p.getMetaItems({
|
|
2006
2174
|
type: "view",
|
|
2007
|
-
...
|
|
2175
|
+
...environmentId ? { environmentId } : {}
|
|
2008
2176
|
});
|
|
2009
2177
|
const items = Array.isArray(result?.items) ? result.items : Array.isArray(result) ? result : [];
|
|
2010
2178
|
return findPublicFormView(items, slug);
|
|
@@ -2014,13 +2182,13 @@ var RestServer = class {
|
|
|
2014
2182
|
path: `${basePath}/forms/:slug`,
|
|
2015
2183
|
handler: async (req, res) => {
|
|
2016
2184
|
try {
|
|
2017
|
-
const
|
|
2185
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2018
2186
|
const slug = String(req.params?.slug ?? "").trim();
|
|
2019
2187
|
if (!slug) {
|
|
2020
2188
|
res.status(400).json({ code: "INVALID_REQUEST", error: "slug is required" });
|
|
2021
2189
|
return;
|
|
2022
2190
|
}
|
|
2023
|
-
const match = await resolveFormBySlug(
|
|
2191
|
+
const match = await resolveFormBySlug(environmentId, req, slug);
|
|
2024
2192
|
if (!match) {
|
|
2025
2193
|
res.status(404).json({
|
|
2026
2194
|
code: "FORM_NOT_FOUND",
|
|
@@ -2030,11 +2198,11 @@ var RestServer = class {
|
|
|
2030
2198
|
}
|
|
2031
2199
|
let objectSchema = null;
|
|
2032
2200
|
try {
|
|
2033
|
-
const p = await this.resolveProtocol(
|
|
2201
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
2034
2202
|
if (typeof p.getMetaItems === "function") {
|
|
2035
2203
|
const r = await p.getMetaItems({
|
|
2036
2204
|
type: "object",
|
|
2037
|
-
...
|
|
2205
|
+
...environmentId ? { environmentId } : {}
|
|
2038
2206
|
});
|
|
2039
2207
|
const items = Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];
|
|
2040
2208
|
const obj = items.find((o) => o?.name === match.object);
|
|
@@ -2054,7 +2222,7 @@ var RestServer = class {
|
|
|
2054
2222
|
}
|
|
2055
2223
|
objectSchema = { name: obj.name, label: obj.label, fields };
|
|
2056
2224
|
try {
|
|
2057
|
-
const i18n = await this.resolveI18nService(
|
|
2225
|
+
const i18n = await this.resolveI18nService(environmentId, req);
|
|
2058
2226
|
const bundle = this.buildTranslationBundle(i18n);
|
|
2059
2227
|
const locale = this.extractLocale(req, i18n);
|
|
2060
2228
|
if (bundle && locale) {
|
|
@@ -2114,13 +2282,13 @@ var RestServer = class {
|
|
|
2114
2282
|
path: `${basePath}/forms/:slug/submit`,
|
|
2115
2283
|
handler: async (req, res) => {
|
|
2116
2284
|
try {
|
|
2117
|
-
const
|
|
2285
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2118
2286
|
const slug = String(req.params?.slug ?? "").trim();
|
|
2119
2287
|
if (!slug) {
|
|
2120
2288
|
res.status(400).json({ code: "INVALID_REQUEST", error: "slug is required" });
|
|
2121
2289
|
return;
|
|
2122
2290
|
}
|
|
2123
|
-
const match = await resolveFormBySlug(
|
|
2291
|
+
const match = await resolveFormBySlug(environmentId, req, slug);
|
|
2124
2292
|
if (!match) {
|
|
2125
2293
|
res.status(404).json({
|
|
2126
2294
|
code: "FORM_NOT_FOUND",
|
|
@@ -2148,11 +2316,11 @@ var RestServer = class {
|
|
|
2148
2316
|
permissions: ["guest_portal"],
|
|
2149
2317
|
anonymous: true
|
|
2150
2318
|
};
|
|
2151
|
-
const p = await this.resolveProtocol(
|
|
2319
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
2152
2320
|
const result = await p.createData({
|
|
2153
2321
|
object: match.object,
|
|
2154
2322
|
data: filteredData,
|
|
2155
|
-
...
|
|
2323
|
+
...environmentId ? { environmentId } : {},
|
|
2156
2324
|
context
|
|
2157
2325
|
});
|
|
2158
2326
|
res.status(201).json(result);
|
|
@@ -2174,14 +2342,14 @@ var RestServer = class {
|
|
|
2174
2342
|
path: `${basePath}/forms/:slug/lookup/:field`,
|
|
2175
2343
|
handler: async (req, res) => {
|
|
2176
2344
|
try {
|
|
2177
|
-
const
|
|
2345
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2178
2346
|
const slug = String(req.params?.slug ?? "").trim();
|
|
2179
2347
|
const fieldName = String(req.params?.field ?? "").trim();
|
|
2180
2348
|
if (!slug || !fieldName) {
|
|
2181
2349
|
res.status(400).json({ code: "INVALID_REQUEST", error: "slug and field are required" });
|
|
2182
2350
|
return;
|
|
2183
2351
|
}
|
|
2184
|
-
const match = await resolveFormBySlug(
|
|
2352
|
+
const match = await resolveFormBySlug(environmentId, req, slug);
|
|
2185
2353
|
if (!match) {
|
|
2186
2354
|
res.status(404).json({
|
|
2187
2355
|
code: "FORM_NOT_FOUND",
|
|
@@ -2208,13 +2376,13 @@ var RestServer = class {
|
|
|
2208
2376
|
});
|
|
2209
2377
|
return;
|
|
2210
2378
|
}
|
|
2211
|
-
const p = await this.resolveProtocol(
|
|
2379
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
2212
2380
|
let referenceTo = picker.object;
|
|
2213
2381
|
if (!referenceTo && typeof p.getMetaItems === "function") {
|
|
2214
2382
|
try {
|
|
2215
2383
|
const r = await p.getMetaItems({
|
|
2216
2384
|
type: "object",
|
|
2217
|
-
...
|
|
2385
|
+
...environmentId ? { environmentId } : {}
|
|
2218
2386
|
});
|
|
2219
2387
|
const items = Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];
|
|
2220
2388
|
const obj = items.find((o) => o?.name === match.object);
|
|
@@ -2250,7 +2418,7 @@ var RestServer = class {
|
|
|
2250
2418
|
select: ["id", ...displayFields],
|
|
2251
2419
|
sort: picker.sort ?? [{ field: displayFields[0], order: "asc" }]
|
|
2252
2420
|
},
|
|
2253
|
-
...
|
|
2421
|
+
...environmentId ? { environmentId } : {},
|
|
2254
2422
|
context
|
|
2255
2423
|
});
|
|
2256
2424
|
const rows = Array.isArray(result?.data) ? result.data : Array.isArray(result?.items) ? result.items : [];
|
|
@@ -2300,11 +2468,11 @@ var RestServer = class {
|
|
|
2300
2468
|
registerSharingEndpoints(basePath) {
|
|
2301
2469
|
const { crud } = this.config;
|
|
2302
2470
|
const dataPath = `${basePath}${crud.dataPrefix}`;
|
|
2303
|
-
const isScoped = basePath.includes("/
|
|
2304
|
-
const resolveService = async (
|
|
2471
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
2472
|
+
const resolveService = async (environmentId) => {
|
|
2305
2473
|
if (!this.sharingServiceProvider) return void 0;
|
|
2306
2474
|
try {
|
|
2307
|
-
return await this.sharingServiceProvider(
|
|
2475
|
+
return await this.sharingServiceProvider(environmentId);
|
|
2308
2476
|
} catch {
|
|
2309
2477
|
return void 0;
|
|
2310
2478
|
}
|
|
@@ -2318,10 +2486,10 @@ var RestServer = class {
|
|
|
2318
2486
|
path: `${dataPath}/:object/:id/shares`,
|
|
2319
2487
|
handler: async (req, res) => {
|
|
2320
2488
|
try {
|
|
2321
|
-
const
|
|
2322
|
-
const context = await this.resolveExecCtx(
|
|
2489
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2490
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2323
2491
|
if (this.enforceAuth(req, res, context)) return;
|
|
2324
|
-
const svc = await resolveService(
|
|
2492
|
+
const svc = await resolveService(environmentId);
|
|
2325
2493
|
if (!svc) return respond501(res);
|
|
2326
2494
|
const rows = await svc.listShares(req.params.object, req.params.id, context ?? {});
|
|
2327
2495
|
res.json({ data: rows });
|
|
@@ -2337,10 +2505,10 @@ var RestServer = class {
|
|
|
2337
2505
|
path: `${dataPath}/:object/:id/shares`,
|
|
2338
2506
|
handler: async (req, res) => {
|
|
2339
2507
|
try {
|
|
2340
|
-
const
|
|
2341
|
-
const context = await this.resolveExecCtx(
|
|
2508
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2509
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2342
2510
|
if (this.enforceAuth(req, res, context)) return;
|
|
2343
|
-
const svc = await resolveService(
|
|
2511
|
+
const svc = await resolveService(environmentId);
|
|
2344
2512
|
if (!svc) return respond501(res);
|
|
2345
2513
|
const body = req.body ?? {};
|
|
2346
2514
|
const input = {
|
|
@@ -2379,10 +2547,10 @@ var RestServer = class {
|
|
|
2379
2547
|
path: `${dataPath}/:object/:id/shares/:shareId`,
|
|
2380
2548
|
handler: async (req, res) => {
|
|
2381
2549
|
try {
|
|
2382
|
-
const
|
|
2383
|
-
const context = await this.resolveExecCtx(
|
|
2550
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2551
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2384
2552
|
if (this.enforceAuth(req, res, context)) return;
|
|
2385
|
-
const svc = await resolveService(
|
|
2553
|
+
const svc = await resolveService(environmentId);
|
|
2386
2554
|
if (!svc) return respond501(res);
|
|
2387
2555
|
await svc.revoke(req.params.shareId, context ?? {});
|
|
2388
2556
|
res.status(204).end();
|
|
@@ -2408,11 +2576,11 @@ var RestServer = class {
|
|
|
2408
2576
|
*/
|
|
2409
2577
|
registerSharingRuleEndpoints(basePath) {
|
|
2410
2578
|
const dataPath = basePath;
|
|
2411
|
-
const isScoped = basePath.includes("/
|
|
2412
|
-
const resolveService = async (
|
|
2579
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
2580
|
+
const resolveService = async (environmentId) => {
|
|
2413
2581
|
if (!this.sharingRulesServiceProvider) return void 0;
|
|
2414
2582
|
try {
|
|
2415
|
-
return await this.sharingRulesServiceProvider(
|
|
2583
|
+
return await this.sharingRulesServiceProvider(environmentId);
|
|
2416
2584
|
} catch {
|
|
2417
2585
|
return void 0;
|
|
2418
2586
|
}
|
|
@@ -2437,10 +2605,10 @@ var RestServer = class {
|
|
|
2437
2605
|
path: `${dataPath}/sharing/rules`,
|
|
2438
2606
|
handler: async (req, res) => {
|
|
2439
2607
|
try {
|
|
2440
|
-
const
|
|
2441
|
-
const context = await this.resolveExecCtx(
|
|
2608
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2609
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2442
2610
|
if (this.enforceAuth(req, res, context)) return;
|
|
2443
|
-
const svc = await resolveService(
|
|
2611
|
+
const svc = await resolveService(environmentId);
|
|
2444
2612
|
if (!svc) return respond501(res);
|
|
2445
2613
|
const rows = await svc.listRules({
|
|
2446
2614
|
object: req.query?.object,
|
|
@@ -2458,10 +2626,10 @@ var RestServer = class {
|
|
|
2458
2626
|
path: `${dataPath}/sharing/rules`,
|
|
2459
2627
|
handler: async (req, res) => {
|
|
2460
2628
|
try {
|
|
2461
|
-
const
|
|
2462
|
-
const context = await this.resolveExecCtx(
|
|
2629
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2630
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2463
2631
|
if (this.enforceAuth(req, res, context)) return;
|
|
2464
|
-
const svc = await resolveService(
|
|
2632
|
+
const svc = await resolveService(environmentId);
|
|
2465
2633
|
if (!svc) return respond501(res);
|
|
2466
2634
|
const body = req.body ?? {};
|
|
2467
2635
|
const input = {
|
|
@@ -2488,10 +2656,10 @@ var RestServer = class {
|
|
|
2488
2656
|
path: `${dataPath}/sharing/rules/:idOrName`,
|
|
2489
2657
|
handler: async (req, res) => {
|
|
2490
2658
|
try {
|
|
2491
|
-
const
|
|
2492
|
-
const context = await this.resolveExecCtx(
|
|
2659
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2660
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2493
2661
|
if (this.enforceAuth(req, res, context)) return;
|
|
2494
|
-
const svc = await resolveService(
|
|
2662
|
+
const svc = await resolveService(environmentId);
|
|
2495
2663
|
if (!svc) return respond501(res);
|
|
2496
2664
|
const row = await svc.getRule(req.params.idOrName, context ?? {});
|
|
2497
2665
|
if (!row) return res.status(404).json({ code: "RULE_NOT_FOUND" });
|
|
@@ -2507,10 +2675,10 @@ var RestServer = class {
|
|
|
2507
2675
|
path: `${dataPath}/sharing/rules/:idOrName`,
|
|
2508
2676
|
handler: async (req, res) => {
|
|
2509
2677
|
try {
|
|
2510
|
-
const
|
|
2511
|
-
const context = await this.resolveExecCtx(
|
|
2678
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2679
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2512
2680
|
if (this.enforceAuth(req, res, context)) return;
|
|
2513
|
-
const svc = await resolveService(
|
|
2681
|
+
const svc = await resolveService(environmentId);
|
|
2514
2682
|
if (!svc) return respond501(res);
|
|
2515
2683
|
await svc.deleteRule(req.params.idOrName, context ?? {});
|
|
2516
2684
|
res.status(204).end();
|
|
@@ -2525,10 +2693,10 @@ var RestServer = class {
|
|
|
2525
2693
|
path: `${dataPath}/sharing/rules/:idOrName/evaluate`,
|
|
2526
2694
|
handler: async (req, res) => {
|
|
2527
2695
|
try {
|
|
2528
|
-
const
|
|
2529
|
-
const context = await this.resolveExecCtx(
|
|
2696
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2697
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2530
2698
|
if (this.enforceAuth(req, res, context)) return;
|
|
2531
|
-
const svc = await resolveService(
|
|
2699
|
+
const svc = await resolveService(environmentId);
|
|
2532
2700
|
if (!svc) return respond501(res);
|
|
2533
2701
|
const result = await svc.evaluateRule(req.params.idOrName, context ?? {});
|
|
2534
2702
|
res.json(result);
|
|
@@ -2562,11 +2730,11 @@ var RestServer = class {
|
|
|
2562
2730
|
*/
|
|
2563
2731
|
registerReportsEndpoints(basePath) {
|
|
2564
2732
|
const dataPath = basePath;
|
|
2565
|
-
const isScoped = basePath.includes("/
|
|
2566
|
-
const resolveService = async (
|
|
2733
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
2734
|
+
const resolveService = async (environmentId) => {
|
|
2567
2735
|
if (!this.reportsServiceProvider) return void 0;
|
|
2568
2736
|
try {
|
|
2569
|
-
return await this.reportsServiceProvider(
|
|
2737
|
+
return await this.reportsServiceProvider(environmentId);
|
|
2570
2738
|
} catch {
|
|
2571
2739
|
return void 0;
|
|
2572
2740
|
}
|
|
@@ -2595,10 +2763,10 @@ var RestServer = class {
|
|
|
2595
2763
|
path: `${dataPath}/reports`,
|
|
2596
2764
|
handler: async (req, res) => {
|
|
2597
2765
|
try {
|
|
2598
|
-
const
|
|
2599
|
-
const context = await this.resolveExecCtx(
|
|
2766
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2767
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2600
2768
|
if (this.enforceAuth(req, res, context)) return;
|
|
2601
|
-
const svc = await resolveService(
|
|
2769
|
+
const svc = await resolveService(environmentId);
|
|
2602
2770
|
if (!svc) return respond501(res);
|
|
2603
2771
|
const q = req.query ?? {};
|
|
2604
2772
|
const rows = await svc.listReports({ object: q.object, ownerId: q.ownerId }, context ?? {});
|
|
@@ -2615,10 +2783,10 @@ var RestServer = class {
|
|
|
2615
2783
|
path: `${dataPath}/reports`,
|
|
2616
2784
|
handler: async (req, res) => {
|
|
2617
2785
|
try {
|
|
2618
|
-
const
|
|
2619
|
-
const context = await this.resolveExecCtx(
|
|
2786
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2787
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2620
2788
|
if (this.enforceAuth(req, res, context)) return;
|
|
2621
|
-
const svc = await resolveService(
|
|
2789
|
+
const svc = await resolveService(environmentId);
|
|
2622
2790
|
if (!svc) return respond501(res);
|
|
2623
2791
|
try {
|
|
2624
2792
|
const row = await svc.saveReport(req.body ?? {}, context ?? {});
|
|
@@ -2639,10 +2807,10 @@ var RestServer = class {
|
|
|
2639
2807
|
path: `${dataPath}/reports/:id`,
|
|
2640
2808
|
handler: async (req, res) => {
|
|
2641
2809
|
try {
|
|
2642
|
-
const
|
|
2643
|
-
const context = await this.resolveExecCtx(
|
|
2810
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2811
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2644
2812
|
if (this.enforceAuth(req, res, context)) return;
|
|
2645
|
-
const svc = await resolveService(
|
|
2813
|
+
const svc = await resolveService(environmentId);
|
|
2646
2814
|
if (!svc) return respond501(res);
|
|
2647
2815
|
const row = await svc.getReport(req.params.id, context ?? {});
|
|
2648
2816
|
if (!row) {
|
|
@@ -2662,10 +2830,10 @@ var RestServer = class {
|
|
|
2662
2830
|
path: `${dataPath}/reports/:id`,
|
|
2663
2831
|
handler: async (req, res) => {
|
|
2664
2832
|
try {
|
|
2665
|
-
const
|
|
2666
|
-
const context = await this.resolveExecCtx(
|
|
2833
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2834
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2667
2835
|
if (this.enforceAuth(req, res, context)) return;
|
|
2668
|
-
const svc = await resolveService(
|
|
2836
|
+
const svc = await resolveService(environmentId);
|
|
2669
2837
|
if (!svc) return respond501(res);
|
|
2670
2838
|
await svc.deleteReport(req.params.id, context ?? {});
|
|
2671
2839
|
res.status(204).end();
|
|
@@ -2681,10 +2849,10 @@ var RestServer = class {
|
|
|
2681
2849
|
path: `${dataPath}/reports/:id/run`,
|
|
2682
2850
|
handler: async (req, res) => {
|
|
2683
2851
|
try {
|
|
2684
|
-
const
|
|
2685
|
-
const context = await this.resolveExecCtx(
|
|
2852
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2853
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2686
2854
|
if (this.enforceAuth(req, res, context)) return;
|
|
2687
|
-
const svc = await resolveService(
|
|
2855
|
+
const svc = await resolveService(environmentId);
|
|
2688
2856
|
if (!svc) return respond501(res);
|
|
2689
2857
|
try {
|
|
2690
2858
|
const result = await svc.run(req.params.id, context ?? {});
|
|
@@ -2705,10 +2873,10 @@ var RestServer = class {
|
|
|
2705
2873
|
path: `${dataPath}/reports/:id/schedule`,
|
|
2706
2874
|
handler: async (req, res) => {
|
|
2707
2875
|
try {
|
|
2708
|
-
const
|
|
2709
|
-
const context = await this.resolveExecCtx(
|
|
2876
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2877
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2710
2878
|
if (this.enforceAuth(req, res, context)) return;
|
|
2711
|
-
const svc = await resolveService(
|
|
2879
|
+
const svc = await resolveService(environmentId);
|
|
2712
2880
|
if (!svc) return respond501(res);
|
|
2713
2881
|
const body = req.body ?? {};
|
|
2714
2882
|
try {
|
|
@@ -2741,10 +2909,10 @@ var RestServer = class {
|
|
|
2741
2909
|
path: `${dataPath}/reports/:id/schedules`,
|
|
2742
2910
|
handler: async (req, res) => {
|
|
2743
2911
|
try {
|
|
2744
|
-
const
|
|
2745
|
-
const context = await this.resolveExecCtx(
|
|
2912
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2913
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2746
2914
|
if (this.enforceAuth(req, res, context)) return;
|
|
2747
|
-
const svc = await resolveService(
|
|
2915
|
+
const svc = await resolveService(environmentId);
|
|
2748
2916
|
if (!svc) return respond501(res);
|
|
2749
2917
|
const rows = await svc.listSchedules({ reportId: req.params.id }, context ?? {});
|
|
2750
2918
|
res.json({ data: rows });
|
|
@@ -2760,10 +2928,10 @@ var RestServer = class {
|
|
|
2760
2928
|
path: `${dataPath}/reports/schedules/:scheduleId`,
|
|
2761
2929
|
handler: async (req, res) => {
|
|
2762
2930
|
try {
|
|
2763
|
-
const
|
|
2764
|
-
const context = await this.resolveExecCtx(
|
|
2931
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2932
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2765
2933
|
if (this.enforceAuth(req, res, context)) return;
|
|
2766
|
-
const svc = await resolveService(
|
|
2934
|
+
const svc = await resolveService(environmentId);
|
|
2767
2935
|
if (!svc) return respond501(res);
|
|
2768
2936
|
await svc.unscheduleReport(req.params.scheduleId, context ?? {});
|
|
2769
2937
|
res.status(204).end();
|
|
@@ -2796,11 +2964,11 @@ var RestServer = class {
|
|
|
2796
2964
|
*/
|
|
2797
2965
|
registerApprovalsEndpoints(basePath) {
|
|
2798
2966
|
const dataPath = basePath;
|
|
2799
|
-
const isScoped = basePath.includes("/
|
|
2800
|
-
const resolveService = async (
|
|
2967
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
2968
|
+
const resolveService = async (environmentId) => {
|
|
2801
2969
|
if (!this.approvalsServiceProvider) return void 0;
|
|
2802
2970
|
try {
|
|
2803
|
-
return await this.approvalsServiceProvider(
|
|
2971
|
+
return await this.approvalsServiceProvider(environmentId);
|
|
2804
2972
|
} catch {
|
|
2805
2973
|
return void 0;
|
|
2806
2974
|
}
|
|
@@ -2833,10 +3001,10 @@ var RestServer = class {
|
|
|
2833
3001
|
path: `${dataPath}/approvals/processes`,
|
|
2834
3002
|
handler: async (req, res) => {
|
|
2835
3003
|
try {
|
|
2836
|
-
const
|
|
2837
|
-
const context = await this.resolveExecCtx(
|
|
3004
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3005
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2838
3006
|
if (this.enforceAuth(req, res, context)) return;
|
|
2839
|
-
const svc = await resolveService(
|
|
3007
|
+
const svc = await resolveService(environmentId);
|
|
2840
3008
|
if (!svc) return respond501(res);
|
|
2841
3009
|
const q = req.query ?? {};
|
|
2842
3010
|
const rows = await svc.listProcesses({
|
|
@@ -2856,10 +3024,10 @@ var RestServer = class {
|
|
|
2856
3024
|
path: `${dataPath}/approvals/processes`,
|
|
2857
3025
|
handler: async (req, res) => {
|
|
2858
3026
|
try {
|
|
2859
|
-
const
|
|
2860
|
-
const context = await this.resolveExecCtx(
|
|
3027
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3028
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2861
3029
|
if (this.enforceAuth(req, res, context)) return;
|
|
2862
|
-
const svc = await resolveService(
|
|
3030
|
+
const svc = await resolveService(environmentId);
|
|
2863
3031
|
if (!svc) return respond501(res);
|
|
2864
3032
|
try {
|
|
2865
3033
|
const row = await svc.defineProcess(req.body ?? {}, context ?? {});
|
|
@@ -2880,10 +3048,10 @@ var RestServer = class {
|
|
|
2880
3048
|
path: `${dataPath}/approvals/processes/:id`,
|
|
2881
3049
|
handler: async (req, res) => {
|
|
2882
3050
|
try {
|
|
2883
|
-
const
|
|
2884
|
-
const context = await this.resolveExecCtx(
|
|
3051
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3052
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2885
3053
|
if (this.enforceAuth(req, res, context)) return;
|
|
2886
|
-
const svc = await resolveService(
|
|
3054
|
+
const svc = await resolveService(environmentId);
|
|
2887
3055
|
if (!svc) return respond501(res);
|
|
2888
3056
|
const row = await svc.getProcess(req.params.id, context ?? {});
|
|
2889
3057
|
if (!row) {
|
|
@@ -2903,10 +3071,10 @@ var RestServer = class {
|
|
|
2903
3071
|
path: `${dataPath}/approvals/processes/:id`,
|
|
2904
3072
|
handler: async (req, res) => {
|
|
2905
3073
|
try {
|
|
2906
|
-
const
|
|
2907
|
-
const context = await this.resolveExecCtx(
|
|
3074
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3075
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2908
3076
|
if (this.enforceAuth(req, res, context)) return;
|
|
2909
|
-
const svc = await resolveService(
|
|
3077
|
+
const svc = await resolveService(environmentId);
|
|
2910
3078
|
if (!svc) return respond501(res);
|
|
2911
3079
|
await svc.deleteProcess(req.params.id, context ?? {});
|
|
2912
3080
|
res.status(204).end();
|
|
@@ -2922,10 +3090,10 @@ var RestServer = class {
|
|
|
2922
3090
|
path: `${dataPath}/approvals/requests`,
|
|
2923
3091
|
handler: async (req, res) => {
|
|
2924
3092
|
try {
|
|
2925
|
-
const
|
|
2926
|
-
const context = await this.resolveExecCtx(
|
|
3093
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3094
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2927
3095
|
if (this.enforceAuth(req, res, context)) return;
|
|
2928
|
-
const svc = await resolveService(
|
|
3096
|
+
const svc = await resolveService(environmentId);
|
|
2929
3097
|
if (!svc) return respond501(res);
|
|
2930
3098
|
const body = req.body ?? {};
|
|
2931
3099
|
try {
|
|
@@ -2954,10 +3122,10 @@ var RestServer = class {
|
|
|
2954
3122
|
path: `${dataPath}/approvals/requests`,
|
|
2955
3123
|
handler: async (req, res) => {
|
|
2956
3124
|
try {
|
|
2957
|
-
const
|
|
2958
|
-
const context = await this.resolveExecCtx(
|
|
3125
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3126
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2959
3127
|
if (this.enforceAuth(req, res, context)) return;
|
|
2960
|
-
const svc = await resolveService(
|
|
3128
|
+
const svc = await resolveService(environmentId);
|
|
2961
3129
|
if (!svc) {
|
|
2962
3130
|
res.json({ data: [] });
|
|
2963
3131
|
return;
|
|
@@ -2983,10 +3151,10 @@ var RestServer = class {
|
|
|
2983
3151
|
path: `${dataPath}/approvals/requests/:id`,
|
|
2984
3152
|
handler: async (req, res) => {
|
|
2985
3153
|
try {
|
|
2986
|
-
const
|
|
2987
|
-
const context = await this.resolveExecCtx(
|
|
3154
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3155
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2988
3156
|
if (this.enforceAuth(req, res, context)) return;
|
|
2989
|
-
const svc = await resolveService(
|
|
3157
|
+
const svc = await resolveService(environmentId);
|
|
2990
3158
|
if (!svc) return respond501(res);
|
|
2991
3159
|
const row = await svc.getRequest(req.params.id, context ?? {});
|
|
2992
3160
|
if (!row) {
|
|
@@ -3007,10 +3175,10 @@ var RestServer = class {
|
|
|
3007
3175
|
path: `${dataPath}/approvals/requests/:id/${suffix}`,
|
|
3008
3176
|
handler: async (req, res) => {
|
|
3009
3177
|
try {
|
|
3010
|
-
const
|
|
3011
|
-
const context = await this.resolveExecCtx(
|
|
3178
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3179
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3012
3180
|
if (this.enforceAuth(req, res, context)) return;
|
|
3013
|
-
const svc = await resolveService(
|
|
3181
|
+
const svc = await resolveService(environmentId);
|
|
3014
3182
|
if (!svc) return respond501(res);
|
|
3015
3183
|
const body = req.body ?? {};
|
|
3016
3184
|
try {
|
|
@@ -3039,10 +3207,10 @@ var RestServer = class {
|
|
|
3039
3207
|
path: `${dataPath}/approvals/requests/:id/actions`,
|
|
3040
3208
|
handler: async (req, res) => {
|
|
3041
3209
|
try {
|
|
3042
|
-
const
|
|
3043
|
-
const context = await this.resolveExecCtx(
|
|
3210
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3211
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3044
3212
|
if (this.enforceAuth(req, res, context)) return;
|
|
3045
|
-
const svc = await resolveService(
|
|
3213
|
+
const svc = await resolveService(environmentId);
|
|
3046
3214
|
if (!svc) return respond501(res);
|
|
3047
3215
|
const rows = await svc.listActions(req.params.id, context ?? {});
|
|
3048
3216
|
res.json({ data: rows });
|
|
@@ -3060,7 +3228,7 @@ var RestServer = class {
|
|
|
3060
3228
|
registerBatchEndpoints(basePath) {
|
|
3061
3229
|
const { crud, batch } = this.config;
|
|
3062
3230
|
const dataPath = `${basePath}${crud.dataPrefix}`;
|
|
3063
|
-
const isScoped = basePath.includes("/
|
|
3231
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
3064
3232
|
const operations = batch.operations;
|
|
3065
3233
|
if (batch.enableBatchEndpoint && this.protocol.batchData) {
|
|
3066
3234
|
this.routeManager.register({
|
|
@@ -3068,14 +3236,14 @@ var RestServer = class {
|
|
|
3068
3236
|
path: `${dataPath}/:object/batch`,
|
|
3069
3237
|
handler: async (req, res) => {
|
|
3070
3238
|
try {
|
|
3071
|
-
const
|
|
3072
|
-
const p = await this.resolveProtocol(
|
|
3073
|
-
const context = await this.resolveExecCtx(
|
|
3239
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3240
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
3241
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3074
3242
|
if (this.enforceAuth(req, res, context)) return;
|
|
3075
3243
|
const result = await p.batchData({
|
|
3076
3244
|
object: req.params.object,
|
|
3077
3245
|
request: req.body,
|
|
3078
|
-
...
|
|
3246
|
+
...environmentId ? { environmentId } : {},
|
|
3079
3247
|
...context ? { context } : {}
|
|
3080
3248
|
});
|
|
3081
3249
|
res.json(result);
|
|
@@ -3096,14 +3264,14 @@ var RestServer = class {
|
|
|
3096
3264
|
path: `${dataPath}/:object/createMany`,
|
|
3097
3265
|
handler: async (req, res) => {
|
|
3098
3266
|
try {
|
|
3099
|
-
const
|
|
3100
|
-
const p = await this.resolveProtocol(
|
|
3101
|
-
const context = await this.resolveExecCtx(
|
|
3267
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3268
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
3269
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3102
3270
|
if (this.enforceAuth(req, res, context)) return;
|
|
3103
3271
|
const result = await p.createManyData({
|
|
3104
3272
|
object: req.params.object,
|
|
3105
3273
|
records: req.body || [],
|
|
3106
|
-
...
|
|
3274
|
+
...environmentId ? { environmentId } : {},
|
|
3107
3275
|
...context ? { context } : {}
|
|
3108
3276
|
});
|
|
3109
3277
|
res.status(201).json(result);
|
|
@@ -3124,14 +3292,14 @@ var RestServer = class {
|
|
|
3124
3292
|
path: `${dataPath}/:object/updateMany`,
|
|
3125
3293
|
handler: async (req, res) => {
|
|
3126
3294
|
try {
|
|
3127
|
-
const
|
|
3128
|
-
const p = await this.resolveProtocol(
|
|
3129
|
-
const context = await this.resolveExecCtx(
|
|
3295
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3296
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
3297
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3130
3298
|
if (this.enforceAuth(req, res, context)) return;
|
|
3131
3299
|
const result = await p.updateManyData({
|
|
3132
3300
|
object: req.params.object,
|
|
3133
3301
|
...req.body,
|
|
3134
|
-
...
|
|
3302
|
+
...environmentId ? { environmentId } : {},
|
|
3135
3303
|
...context ? { context } : {}
|
|
3136
3304
|
});
|
|
3137
3305
|
res.json(result);
|
|
@@ -3152,14 +3320,14 @@ var RestServer = class {
|
|
|
3152
3320
|
path: `${dataPath}/:object/deleteMany`,
|
|
3153
3321
|
handler: async (req, res) => {
|
|
3154
3322
|
try {
|
|
3155
|
-
const
|
|
3156
|
-
const p = await this.resolveProtocol(
|
|
3157
|
-
const context = await this.resolveExecCtx(
|
|
3323
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3324
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
3325
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3158
3326
|
if (this.enforceAuth(req, res, context)) return;
|
|
3159
3327
|
const result = await p.deleteManyData({
|
|
3160
3328
|
object: req.params.object,
|
|
3161
3329
|
...req.body,
|
|
3162
|
-
...
|
|
3330
|
+
...environmentId ? { environmentId } : {},
|
|
3163
3331
|
...context ? { context } : {}
|
|
3164
3332
|
});
|
|
3165
3333
|
res.json(result);
|
|
@@ -3337,64 +3505,64 @@ function createRestApiPlugin(config = {}) {
|
|
|
3337
3505
|
envRegistry = ctx.getService("env-registry");
|
|
3338
3506
|
} catch (e) {
|
|
3339
3507
|
}
|
|
3340
|
-
const
|
|
3508
|
+
const defaultEnvironmentIdProvider = () => {
|
|
3341
3509
|
try {
|
|
3342
3510
|
const dp = ctx.getService("default-project");
|
|
3343
|
-
return dp?.
|
|
3511
|
+
return dp?.environmentId;
|
|
3344
3512
|
} catch {
|
|
3345
3513
|
return void 0;
|
|
3346
3514
|
}
|
|
3347
3515
|
};
|
|
3348
|
-
const authServiceProvider = async (
|
|
3516
|
+
const authServiceProvider = async (_environmentId) => {
|
|
3349
3517
|
try {
|
|
3350
3518
|
return ctx.getService("auth");
|
|
3351
3519
|
} catch {
|
|
3352
3520
|
return void 0;
|
|
3353
3521
|
}
|
|
3354
3522
|
};
|
|
3355
|
-
const objectQLProvider = async (
|
|
3523
|
+
const objectQLProvider = async (_environmentId) => {
|
|
3356
3524
|
try {
|
|
3357
3525
|
return ctx.getService("objectql");
|
|
3358
3526
|
} catch {
|
|
3359
3527
|
return void 0;
|
|
3360
3528
|
}
|
|
3361
3529
|
};
|
|
3362
|
-
const emailServiceProvider = async (
|
|
3530
|
+
const emailServiceProvider = async (_environmentId) => {
|
|
3363
3531
|
try {
|
|
3364
3532
|
return ctx.getService("email");
|
|
3365
3533
|
} catch {
|
|
3366
3534
|
return void 0;
|
|
3367
3535
|
}
|
|
3368
3536
|
};
|
|
3369
|
-
const sharingServiceProvider = async (
|
|
3537
|
+
const sharingServiceProvider = async (_environmentId) => {
|
|
3370
3538
|
try {
|
|
3371
3539
|
return ctx.getService("sharing");
|
|
3372
3540
|
} catch {
|
|
3373
3541
|
return void 0;
|
|
3374
3542
|
}
|
|
3375
3543
|
};
|
|
3376
|
-
const reportsServiceProvider = async (
|
|
3544
|
+
const reportsServiceProvider = async (_environmentId) => {
|
|
3377
3545
|
try {
|
|
3378
3546
|
return ctx.getService("reports");
|
|
3379
3547
|
} catch {
|
|
3380
3548
|
return void 0;
|
|
3381
3549
|
}
|
|
3382
3550
|
};
|
|
3383
|
-
const approvalsServiceProvider = async (
|
|
3551
|
+
const approvalsServiceProvider = async (_environmentId) => {
|
|
3384
3552
|
try {
|
|
3385
3553
|
return ctx.getService("approvals");
|
|
3386
3554
|
} catch {
|
|
3387
3555
|
return void 0;
|
|
3388
3556
|
}
|
|
3389
3557
|
};
|
|
3390
|
-
const sharingRulesServiceProvider = async (
|
|
3558
|
+
const sharingRulesServiceProvider = async (_environmentId) => {
|
|
3391
3559
|
try {
|
|
3392
3560
|
return ctx.getService("sharingRules");
|
|
3393
3561
|
} catch {
|
|
3394
3562
|
return void 0;
|
|
3395
3563
|
}
|
|
3396
3564
|
};
|
|
3397
|
-
const i18nServiceProvider = async (
|
|
3565
|
+
const i18nServiceProvider = async (_environmentId) => {
|
|
3398
3566
|
try {
|
|
3399
3567
|
return ctx.getService("i18n");
|
|
3400
3568
|
} catch {
|
|
@@ -3411,7 +3579,7 @@ function createRestApiPlugin(config = {}) {
|
|
|
3411
3579
|
}
|
|
3412
3580
|
ctx.logger.info("Hydrating REST API from Protocol...");
|
|
3413
3581
|
try {
|
|
3414
|
-
const restServer = new RestServer(server, protocol, config.api, kernelManager, envRegistry,
|
|
3582
|
+
const restServer = new RestServer(server, protocol, config.api, kernelManager, envRegistry, defaultEnvironmentIdProvider, authServiceProvider, objectQLProvider, emailServiceProvider, sharingServiceProvider, reportsServiceProvider, approvalsServiceProvider, sharingRulesServiceProvider, i18nServiceProvider);
|
|
3415
3583
|
restServer.registerRoutes();
|
|
3416
3584
|
ctx.logger.info("REST API successfully registered");
|
|
3417
3585
|
} catch (err) {
|
|
@@ -3427,13 +3595,13 @@ function createRestApiPlugin(config = {}) {
|
|
|
3427
3595
|
const enableProjectScoping = config.api?.api?.enableProjectScoping ?? false;
|
|
3428
3596
|
const projectResolution = config.api?.api?.projectResolution ?? "auto";
|
|
3429
3597
|
if (enableProjectScoping && projectResolution === "required") {
|
|
3430
|
-
registerPackageRoutes(server, packageService, `${versionedBase}/
|
|
3598
|
+
registerPackageRoutes(server, packageService, `${versionedBase}/environments/:environmentId`, {
|
|
3431
3599
|
protocol
|
|
3432
3600
|
});
|
|
3433
3601
|
} else {
|
|
3434
3602
|
registerPackageRoutes(server, packageService, versionedBase, { protocol });
|
|
3435
3603
|
if (enableProjectScoping) {
|
|
3436
|
-
registerPackageRoutes(server, packageService, `${versionedBase}/
|
|
3604
|
+
registerPackageRoutes(server, packageService, `${versionedBase}/environments/:environmentId`, {
|
|
3437
3605
|
protocol
|
|
3438
3606
|
});
|
|
3439
3607
|
}
|