@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.js
CHANGED
|
@@ -246,7 +246,7 @@ function mapDataError(error, object) {
|
|
|
246
246
|
}
|
|
247
247
|
const raw = String(error?.message ?? error ?? "");
|
|
248
248
|
const lower = raw.toLowerCase();
|
|
249
|
-
if (raw.includes("[
|
|
249
|
+
if (raw.includes("[EnvironmentKernelFactory]") && (lower.includes("missing database_url") || lower.includes("not found"))) {
|
|
250
250
|
const isProvisioning = lower.includes("status='provisioning'") || lower.includes("status='pending'");
|
|
251
251
|
const isFailed = lower.includes("status='failed'");
|
|
252
252
|
return {
|
|
@@ -403,13 +403,19 @@ function rowsToCsv(fields, rows, includeHeader) {
|
|
|
403
403
|
return lines.join("\r\n") + (lines.length > 0 ? "\r\n" : "");
|
|
404
404
|
}
|
|
405
405
|
var RestServer = class {
|
|
406
|
-
constructor(server, protocol, config = {}, kernelManager, envRegistry,
|
|
406
|
+
constructor(server, protocol, config = {}, kernelManager, envRegistry, defaultEnvironmentIdProvider, authServiceProvider, objectQLProvider, emailServiceProvider, sharingServiceProvider, reportsServiceProvider, approvalsServiceProvider, sharingRulesServiceProvider, i18nServiceProvider) {
|
|
407
|
+
/**
|
|
408
|
+
* Lazily load the OpenAPI spec JSON shipped by @objectstack/spec.
|
|
409
|
+
* Cached after first read. Resilient to missing files / parse errors
|
|
410
|
+
* so a degraded environment still boots.
|
|
411
|
+
*/
|
|
412
|
+
this._openApiSpecCache = void 0;
|
|
407
413
|
this.protocol = protocol;
|
|
408
414
|
this.config = this.normalizeConfig(config);
|
|
409
415
|
this.routeManager = new RouteManager(server);
|
|
410
416
|
this.kernelManager = kernelManager;
|
|
411
417
|
this.envRegistry = envRegistry;
|
|
412
|
-
this.
|
|
418
|
+
this.defaultEnvironmentIdProvider = defaultEnvironmentIdProvider;
|
|
413
419
|
this.authServiceProvider = authServiceProvider;
|
|
414
420
|
this.objectQLProvider = objectQLProvider;
|
|
415
421
|
this.emailServiceProvider = emailServiceProvider;
|
|
@@ -420,20 +426,20 @@ var RestServer = class {
|
|
|
420
426
|
this.i18nServiceProvider = i18nServiceProvider;
|
|
421
427
|
}
|
|
422
428
|
/**
|
|
423
|
-
* Resolve the protocol for a given request. When `
|
|
429
|
+
* Resolve the protocol for a given request. When `environmentId` is present
|
|
424
430
|
* and a KernelManager is wired, fetch the per-project kernel's
|
|
425
431
|
* `protocol` service so metadata / data / UI reads hit the project's
|
|
426
432
|
* own registry and datastore.
|
|
427
433
|
*
|
|
428
|
-
* When `
|
|
434
|
+
* When `environmentId` is absent on an unscoped route and an `envRegistry`
|
|
429
435
|
* is wired (runtime mode), the resolution chain is:
|
|
430
|
-
* 1. Hostname →
|
|
431
|
-
* 2. `X-
|
|
432
|
-
* 3. Default-project fallback (`
|
|
433
|
-
* `
|
|
436
|
+
* 1. Hostname → environmentId (`envRegistry.resolveByHostname`)
|
|
437
|
+
* 2. `X-Environment-Id` header → environmentId (`envRegistry.resolveById`)
|
|
438
|
+
* 3. Default-project fallback (`defaultEnvironmentIdProvider`, set by
|
|
439
|
+
* `createSingleEnvironmentPlugin`)
|
|
434
440
|
* 4. Control-plane protocol captured at boot.
|
|
435
441
|
*
|
|
436
|
-
* Special case: `
|
|
442
|
+
* Special case: `environmentId === 'platform'` is a reserved virtual id used
|
|
437
443
|
* by Studio to address the control plane through the regular project
|
|
438
444
|
* URL shape (`/projects/platform/...`). It is NOT a row in the projects
|
|
439
445
|
* table, so we must never call `KernelManager.getOrCreate('platform')`.
|
|
@@ -441,37 +447,37 @@ var RestServer = class {
|
|
|
441
447
|
* (and any other client) speak a single, uniform URL family without
|
|
442
448
|
* duplicating route logic for the platform surface.
|
|
443
449
|
*/
|
|
444
|
-
async resolveProtocol(
|
|
445
|
-
if (
|
|
446
|
-
if (!
|
|
450
|
+
async resolveProtocol(environmentId, req) {
|
|
451
|
+
if (environmentId === "platform") return this.protocol;
|
|
452
|
+
if (!environmentId && req && this.envRegistry && this.kernelManager) {
|
|
447
453
|
const host = this.extractHostname(req);
|
|
448
454
|
if (host) {
|
|
449
455
|
try {
|
|
450
456
|
const result = await this.envRegistry.resolveByHostname(host);
|
|
451
|
-
if (result?.
|
|
457
|
+
if (result?.environmentId) environmentId = result.environmentId;
|
|
452
458
|
} catch {
|
|
453
459
|
}
|
|
454
460
|
}
|
|
455
|
-
if (!
|
|
461
|
+
if (!environmentId && typeof this.envRegistry.resolveById === "function") {
|
|
456
462
|
const headerVal = this.extractProjectIdHeader(req);
|
|
457
463
|
if (headerVal) {
|
|
458
464
|
try {
|
|
459
465
|
const driver = await this.envRegistry.resolveById(headerVal);
|
|
460
|
-
if (driver)
|
|
466
|
+
if (driver) environmentId = headerVal;
|
|
461
467
|
} catch {
|
|
462
468
|
}
|
|
463
469
|
}
|
|
464
470
|
}
|
|
465
471
|
}
|
|
466
|
-
if (!
|
|
472
|
+
if (!environmentId && this.defaultEnvironmentIdProvider) {
|
|
467
473
|
try {
|
|
468
|
-
const def = this.
|
|
469
|
-
if (def)
|
|
474
|
+
const def = this.defaultEnvironmentIdProvider();
|
|
475
|
+
if (def) environmentId = def;
|
|
470
476
|
} catch {
|
|
471
477
|
}
|
|
472
478
|
}
|
|
473
|
-
if (!
|
|
474
|
-
const kernel = await this.kernelManager.getOrCreate(
|
|
479
|
+
if (!environmentId || !this.kernelManager) return this.protocol;
|
|
480
|
+
const kernel = await this.kernelManager.getOrCreate(environmentId);
|
|
475
481
|
return kernel.getServiceAsync("protocol");
|
|
476
482
|
}
|
|
477
483
|
/**
|
|
@@ -480,43 +486,43 @@ var RestServer = class {
|
|
|
480
486
|
* registered, so callers can short-circuit and skip translation rather
|
|
481
487
|
* than failing.
|
|
482
488
|
*
|
|
483
|
-
* Mirrors `resolveProtocol`'s lookup chain: explicit `
|
|
489
|
+
* Mirrors `resolveProtocol`'s lookup chain: explicit `environmentId` from the
|
|
484
490
|
* route → kernel-managed `i18n` service. Control-plane / unscoped
|
|
485
491
|
* requests intentionally return `undefined` because the platform kernel
|
|
486
492
|
* does not own per-app translation bundles.
|
|
487
493
|
*/
|
|
488
|
-
async resolveI18nService(
|
|
489
|
-
if (
|
|
490
|
-
if (!
|
|
494
|
+
async resolveI18nService(environmentId, req) {
|
|
495
|
+
if (environmentId === "platform") return void 0;
|
|
496
|
+
if (!environmentId && req && this.envRegistry && this.kernelManager) {
|
|
491
497
|
const host = this.extractHostname(req);
|
|
492
498
|
if (host) {
|
|
493
499
|
try {
|
|
494
500
|
const result = await this.envRegistry.resolveByHostname(host);
|
|
495
|
-
if (result?.
|
|
501
|
+
if (result?.environmentId) environmentId = result.environmentId;
|
|
496
502
|
} catch {
|
|
497
503
|
}
|
|
498
504
|
}
|
|
499
|
-
if (!
|
|
505
|
+
if (!environmentId && typeof this.envRegistry.resolveById === "function") {
|
|
500
506
|
const headerVal = this.extractProjectIdHeader(req);
|
|
501
507
|
if (headerVal) {
|
|
502
508
|
try {
|
|
503
509
|
const driver = await this.envRegistry.resolveById(headerVal);
|
|
504
|
-
if (driver)
|
|
510
|
+
if (driver) environmentId = headerVal;
|
|
505
511
|
} catch {
|
|
506
512
|
}
|
|
507
513
|
}
|
|
508
514
|
}
|
|
509
515
|
}
|
|
510
|
-
if (!
|
|
516
|
+
if (!environmentId && this.defaultEnvironmentIdProvider) {
|
|
511
517
|
try {
|
|
512
|
-
const def = this.
|
|
513
|
-
if (def)
|
|
518
|
+
const def = this.defaultEnvironmentIdProvider();
|
|
519
|
+
if (def) environmentId = def;
|
|
514
520
|
} catch {
|
|
515
521
|
}
|
|
516
522
|
}
|
|
517
|
-
if (
|
|
523
|
+
if (environmentId && this.kernelManager) {
|
|
518
524
|
try {
|
|
519
|
-
const kernel = await this.kernelManager.getOrCreate(
|
|
525
|
+
const kernel = await this.kernelManager.getOrCreate(environmentId);
|
|
520
526
|
const svc = await kernel.getServiceAsync("i18n");
|
|
521
527
|
if (svc) return svc;
|
|
522
528
|
} catch {
|
|
@@ -524,7 +530,7 @@ var RestServer = class {
|
|
|
524
530
|
}
|
|
525
531
|
if (this.i18nServiceProvider) {
|
|
526
532
|
try {
|
|
527
|
-
return await this.i18nServiceProvider(
|
|
533
|
+
return await this.i18nServiceProvider(environmentId);
|
|
528
534
|
} catch {
|
|
529
535
|
return void 0;
|
|
530
536
|
}
|
|
@@ -556,23 +562,23 @@ var RestServer = class {
|
|
|
556
562
|
* `undefined` for anonymous requests so callers can pass `context` as-is
|
|
557
563
|
* to the protocol layer (the SecurityPlugin treats undefined as anon).
|
|
558
564
|
*/
|
|
559
|
-
async resolveExecCtx(
|
|
565
|
+
async resolveExecCtx(environmentId, req) {
|
|
560
566
|
try {
|
|
561
|
-
if (!
|
|
567
|
+
if (!environmentId && req && this.envRegistry && this.kernelManager) {
|
|
562
568
|
const host = this.extractHostname(req);
|
|
563
569
|
if (host) {
|
|
564
570
|
try {
|
|
565
571
|
const result = await this.envRegistry.resolveByHostname(host);
|
|
566
|
-
if (result?.
|
|
572
|
+
if (result?.environmentId) environmentId = result.environmentId;
|
|
567
573
|
} catch {
|
|
568
574
|
}
|
|
569
575
|
}
|
|
570
|
-
if (!
|
|
576
|
+
if (!environmentId && typeof this.envRegistry.resolveById === "function") {
|
|
571
577
|
const headerVal = this.extractProjectIdHeader(req);
|
|
572
578
|
if (headerVal) {
|
|
573
579
|
try {
|
|
574
580
|
const driver = await this.envRegistry.resolveById(headerVal);
|
|
575
|
-
if (driver)
|
|
581
|
+
if (driver) environmentId = headerVal;
|
|
576
582
|
} catch {
|
|
577
583
|
}
|
|
578
584
|
}
|
|
@@ -580,13 +586,13 @@ var RestServer = class {
|
|
|
580
586
|
}
|
|
581
587
|
let authService;
|
|
582
588
|
let kernel;
|
|
583
|
-
if (
|
|
584
|
-
kernel = await this.kernelManager.getOrCreate(
|
|
589
|
+
if (environmentId && environmentId !== "platform" && this.kernelManager) {
|
|
590
|
+
kernel = await this.kernelManager.getOrCreate(environmentId);
|
|
585
591
|
authService = await kernel.getServiceAsync("auth").catch(() => void 0);
|
|
586
592
|
}
|
|
587
|
-
if (!authService && this.
|
|
593
|
+
if (!authService && this.defaultEnvironmentIdProvider && this.kernelManager) {
|
|
588
594
|
try {
|
|
589
|
-
const def = this.
|
|
595
|
+
const def = this.defaultEnvironmentIdProvider();
|
|
590
596
|
if (def) {
|
|
591
597
|
kernel = await this.kernelManager.getOrCreate(def);
|
|
592
598
|
authService = await kernel.getServiceAsync("auth").catch(() => void 0);
|
|
@@ -595,7 +601,7 @@ var RestServer = class {
|
|
|
595
601
|
}
|
|
596
602
|
}
|
|
597
603
|
if (!authService && this.authServiceProvider) {
|
|
598
|
-
authService = await this.authServiceProvider(
|
|
604
|
+
authService = await this.authServiceProvider(environmentId).catch(() => void 0);
|
|
599
605
|
}
|
|
600
606
|
if (!authService) return void 0;
|
|
601
607
|
let api = authService.api;
|
|
@@ -628,7 +634,7 @@ var RestServer = class {
|
|
|
628
634
|
ql = await kernel.getServiceAsync("objectql").catch(() => void 0);
|
|
629
635
|
}
|
|
630
636
|
if (!ql && this.objectQLProvider) {
|
|
631
|
-
ql = await this.objectQLProvider(
|
|
637
|
+
ql = await this.objectQLProvider(environmentId).catch(() => void 0);
|
|
632
638
|
}
|
|
633
639
|
if (ql && typeof ql.find === "function") {
|
|
634
640
|
const sysOpts = { context: { isSystem: true } };
|
|
@@ -670,12 +676,40 @@ var RestServer = class {
|
|
|
670
676
|
}
|
|
671
677
|
} catch {
|
|
672
678
|
}
|
|
679
|
+
let org_user_ids = [userId];
|
|
680
|
+
if (tenantId) {
|
|
681
|
+
try {
|
|
682
|
+
let ql;
|
|
683
|
+
if (kernel) {
|
|
684
|
+
ql = await kernel.getServiceAsync("objectql").catch(() => void 0);
|
|
685
|
+
}
|
|
686
|
+
if (!ql && this.objectQLProvider) {
|
|
687
|
+
ql = await this.objectQLProvider(environmentId).catch(() => void 0);
|
|
688
|
+
}
|
|
689
|
+
if (ql && typeof ql.find === "function") {
|
|
690
|
+
const sysOpts = { context: { isSystem: true } };
|
|
691
|
+
const memberRows = await ql.find("sys_member", {
|
|
692
|
+
where: { organization_id: tenantId },
|
|
693
|
+
limit: 1e3,
|
|
694
|
+
...sysOpts
|
|
695
|
+
}).catch(() => []);
|
|
696
|
+
const ids = /* @__PURE__ */ new Set([userId]);
|
|
697
|
+
for (const m of memberRows ?? []) {
|
|
698
|
+
const uid = m.user_id ?? m.userId;
|
|
699
|
+
if (typeof uid === "string" && uid.length > 0) ids.add(uid);
|
|
700
|
+
}
|
|
701
|
+
org_user_ids = Array.from(ids);
|
|
702
|
+
}
|
|
703
|
+
} catch {
|
|
704
|
+
}
|
|
705
|
+
}
|
|
673
706
|
return {
|
|
674
707
|
userId,
|
|
675
708
|
tenantId,
|
|
676
709
|
roles,
|
|
677
710
|
permissions,
|
|
678
|
-
isSystem: false
|
|
711
|
+
isSystem: false,
|
|
712
|
+
org_user_ids
|
|
679
713
|
};
|
|
680
714
|
} catch {
|
|
681
715
|
return void 0;
|
|
@@ -729,10 +763,10 @@ var RestServer = class {
|
|
|
729
763
|
* locale yields a match. Falls through unchanged for unsupported types
|
|
730
764
|
* or missing translations.
|
|
731
765
|
*/
|
|
732
|
-
async translateMetaItem(req, type,
|
|
766
|
+
async translateMetaItem(req, type, environmentId, item) {
|
|
733
767
|
if (!item || typeof item !== "object") return item;
|
|
734
768
|
if (type !== "view" && type !== "action" && type !== "object") return item;
|
|
735
|
-
const i18n = await this.resolveI18nService(
|
|
769
|
+
const i18n = await this.resolveI18nService(environmentId, req);
|
|
736
770
|
const bundle = this.buildTranslationBundle(i18n);
|
|
737
771
|
if (!bundle) return item;
|
|
738
772
|
const locale = this.extractLocale(req, i18n);
|
|
@@ -743,10 +777,10 @@ var RestServer = class {
|
|
|
743
777
|
/**
|
|
744
778
|
* Translate a list of metadata documents using `translateMetaItem`.
|
|
745
779
|
*/
|
|
746
|
-
async translateMetaItems(req, type,
|
|
780
|
+
async translateMetaItems(req, type, environmentId, items) {
|
|
747
781
|
if (!Array.isArray(items)) return items;
|
|
748
782
|
if (type !== "view" && type !== "action" && type !== "object") return items;
|
|
749
|
-
const i18n = await this.resolveI18nService(
|
|
783
|
+
const i18n = await this.resolveI18nService(environmentId, req);
|
|
750
784
|
const bundle = this.buildTranslationBundle(i18n);
|
|
751
785
|
if (!bundle) return items;
|
|
752
786
|
const locale = this.extractLocale(req, i18n);
|
|
@@ -780,7 +814,7 @@ var RestServer = class {
|
|
|
780
814
|
return String(host).split(":")[0].toLowerCase();
|
|
781
815
|
}
|
|
782
816
|
/**
|
|
783
|
-
* Pull the `X-
|
|
817
|
+
* Pull the `X-Environment-Id` header from a Node- or Fetch-style request.
|
|
784
818
|
* Header names are case-insensitive; we probe both casings to cover
|
|
785
819
|
* adapters that don't normalize headers (e.g. raw Node http).
|
|
786
820
|
*/
|
|
@@ -789,9 +823,9 @@ var RestServer = class {
|
|
|
789
823
|
if (!headers) return void 0;
|
|
790
824
|
let val;
|
|
791
825
|
if (typeof headers.get === "function") {
|
|
792
|
-
val = headers.get("x-
|
|
826
|
+
val = headers.get("x-environment-id") ?? headers.get("X-Environment-Id");
|
|
793
827
|
} else {
|
|
794
|
-
val = headers["x-
|
|
828
|
+
val = headers["x-environment-id"] ?? headers["X-Environment-Id"];
|
|
795
829
|
}
|
|
796
830
|
if (Array.isArray(val)) val = val[0];
|
|
797
831
|
if (typeof val !== "string") return void 0;
|
|
@@ -817,6 +851,7 @@ var RestServer = class {
|
|
|
817
851
|
enableUi: api.enableUi ?? true,
|
|
818
852
|
enableBatch: api.enableBatch ?? true,
|
|
819
853
|
enableDiscovery: api.enableDiscovery ?? true,
|
|
854
|
+
enableOpenApi: api.enableOpenApi ?? true,
|
|
820
855
|
enableSearch: api.enableSearch ?? true,
|
|
821
856
|
enableProjectScoping: api.enableProjectScoping ?? false,
|
|
822
857
|
projectResolution: api.projectResolution ?? "auto",
|
|
@@ -875,16 +910,16 @@ var RestServer = class {
|
|
|
875
910
|
}
|
|
876
911
|
/**
|
|
877
912
|
* Get the project-scoped base path for a given unscoped base.
|
|
878
|
-
* Example: `/api/v1` → `/api/v1/
|
|
913
|
+
* Example: `/api/v1` → `/api/v1/environments/:environmentId`.
|
|
879
914
|
*/
|
|
880
915
|
getScopedBasePath(basePath) {
|
|
881
|
-
return `${basePath}/
|
|
916
|
+
return `${basePath}/environments/:environmentId`;
|
|
882
917
|
}
|
|
883
918
|
/**
|
|
884
919
|
* Register all REST API routes
|
|
885
920
|
*
|
|
886
921
|
* When `enableProjectScoping` is true, routes are registered under
|
|
887
|
-
* `/api/v1/
|
|
922
|
+
* `/api/v1/environments/:environmentId/...`. The `projectResolution` strategy
|
|
888
923
|
* controls whether unscoped legacy routes remain available:
|
|
889
924
|
* - `required` → only scoped routes registered.
|
|
890
925
|
* - `optional` / `auto` → both scoped and unscoped routes registered.
|
|
@@ -896,6 +931,9 @@ var RestServer = class {
|
|
|
896
931
|
if (this.config.api.enableDiscovery) {
|
|
897
932
|
this.registerDiscoveryEndpoints(bp);
|
|
898
933
|
}
|
|
934
|
+
if (this.config.api.enableOpenApi ?? true) {
|
|
935
|
+
this.registerOpenApiEndpoints(bp);
|
|
936
|
+
}
|
|
899
937
|
if (this.config.api.enableMetadata) {
|
|
900
938
|
this.registerMetadataEndpoints(bp);
|
|
901
939
|
}
|
|
@@ -935,12 +973,12 @@ var RestServer = class {
|
|
|
935
973
|
* Register discovery endpoints
|
|
936
974
|
*/
|
|
937
975
|
registerDiscoveryEndpoints(basePath) {
|
|
938
|
-
const isScoped = basePath.includes("/
|
|
976
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
939
977
|
const discoveryHandler = async (req, res) => {
|
|
940
978
|
try {
|
|
941
979
|
const discovery = await this.protocol.getDiscovery();
|
|
942
980
|
discovery.version = this.config.api.version;
|
|
943
|
-
const realBase = isScoped ? basePath.replace(":
|
|
981
|
+
const realBase = isScoped ? basePath.replace(":environmentId", req.params?.environmentId ?? ":environmentId") : basePath;
|
|
944
982
|
if (discovery.routes) {
|
|
945
983
|
if (this.config.api.enableCrud) {
|
|
946
984
|
discovery.routes.data = `${realBase}${this.config.crud.dataPrefix}`;
|
|
@@ -952,7 +990,7 @@ var RestServer = class {
|
|
|
952
990
|
discovery.routes.ui = `${realBase}/ui`;
|
|
953
991
|
}
|
|
954
992
|
if (discovery.routes.auth) {
|
|
955
|
-
const unscopedBase = isScoped ? basePath.replace(/\/projects\/:
|
|
993
|
+
const unscopedBase = isScoped ? basePath.replace(/\/projects\/:environmentId$/, "") : basePath;
|
|
956
994
|
discovery.routes.auth = `${unscopedBase}/auth`;
|
|
957
995
|
}
|
|
958
996
|
}
|
|
@@ -960,7 +998,7 @@ var RestServer = class {
|
|
|
960
998
|
enabled: this.config.api.enableProjectScoping,
|
|
961
999
|
resolution: this.config.api.projectResolution,
|
|
962
1000
|
scoped: isScoped,
|
|
963
|
-
|
|
1001
|
+
environmentId: isScoped ? req.params?.environmentId : void 0
|
|
964
1002
|
};
|
|
965
1003
|
res.json(discovery);
|
|
966
1004
|
} catch (error) {
|
|
@@ -987,21 +1025,150 @@ var RestServer = class {
|
|
|
987
1025
|
}
|
|
988
1026
|
});
|
|
989
1027
|
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Register OpenAPI 3.1 spec + interactive docs viewer.
|
|
1030
|
+
*
|
|
1031
|
+
* GET <basePath>/openapi.json → enriched OpenAPI document
|
|
1032
|
+
* GET <basePath>/docs → Scalar-rendered HTML (CDN, no dep)
|
|
1033
|
+
*
|
|
1034
|
+
* Enrichment at request time:
|
|
1035
|
+
* - servers[0].url — derived from the request's Host header
|
|
1036
|
+
* - paths — `{object}` placeholders expanded into
|
|
1037
|
+
* one concrete path per registered object
|
|
1038
|
+
* from the protocol's discovery metadata
|
|
1039
|
+
*
|
|
1040
|
+
* The base spec is loaded lazily from @objectstack/spec/openapi.json
|
|
1041
|
+
* (shipped pre-generated by spec's build pipeline) so we don't pay
|
|
1042
|
+
* the cost of regenerating on every request, and a missing or
|
|
1043
|
+
* malformed file degrades to a stub instead of crashing.
|
|
1044
|
+
*/
|
|
1045
|
+
registerOpenApiEndpoints(basePath) {
|
|
1046
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1047
|
+
const openApiHandler = async (req, res) => {
|
|
1048
|
+
try {
|
|
1049
|
+
const spec = await this.loadOpenApiSpec();
|
|
1050
|
+
if (!spec) {
|
|
1051
|
+
res.status?.(503);
|
|
1052
|
+
res.json({
|
|
1053
|
+
error: "openapi_unavailable",
|
|
1054
|
+
message: "OpenAPI spec is not bundled with this runtime."
|
|
1055
|
+
});
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
const enriched = { ...spec, servers: [...spec.servers ?? []] };
|
|
1059
|
+
const host = req.headers?.host ?? req.headers?.["host"];
|
|
1060
|
+
const proto = req.headers?.["x-forwarded-proto"] || req.protocol || "http";
|
|
1061
|
+
if (host) {
|
|
1062
|
+
enriched.servers = [
|
|
1063
|
+
{ url: `${proto}://${host}`, description: "Current server" },
|
|
1064
|
+
...spec.servers ?? []
|
|
1065
|
+
];
|
|
1066
|
+
}
|
|
1067
|
+
try {
|
|
1068
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1069
|
+
const protocol = await this.resolveProtocol(environmentId, req);
|
|
1070
|
+
const items = await protocol?.getMetaItems?.({ type: "object" }).catch(() => null);
|
|
1071
|
+
const objects = Array.isArray(items?.items) ? items.items.map((i) => i?.name).filter(Boolean) : Array.isArray(items) ? items.map((i) => i?.name).filter(Boolean) : [];
|
|
1072
|
+
if (objects.length > 0 && enriched.paths) {
|
|
1073
|
+
const expanded = {};
|
|
1074
|
+
for (const [p, def] of Object.entries(enriched.paths)) {
|
|
1075
|
+
if (p.includes("{object}")) {
|
|
1076
|
+
expanded[p] = { ...def, "x-template": true };
|
|
1077
|
+
for (const obj of objects) {
|
|
1078
|
+
expanded[p.replace("{object}", obj)] = def;
|
|
1079
|
+
}
|
|
1080
|
+
} else {
|
|
1081
|
+
expanded[p] = def;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
enriched.paths = expanded;
|
|
1085
|
+
}
|
|
1086
|
+
} catch {
|
|
1087
|
+
}
|
|
1088
|
+
if (enriched.info) {
|
|
1089
|
+
enriched.info = {
|
|
1090
|
+
...enriched.info,
|
|
1091
|
+
version: this.config.api.version || enriched.info.version
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
res.json(enriched);
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
logError("[REST] openapi.json error:", error);
|
|
1097
|
+
sendError(res, error);
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
this.routeManager.register({
|
|
1101
|
+
method: "GET",
|
|
1102
|
+
path: `${basePath}/openapi.json`,
|
|
1103
|
+
handler: openApiHandler,
|
|
1104
|
+
metadata: {
|
|
1105
|
+
summary: "OpenAPI 3.1 specification (machine-readable)",
|
|
1106
|
+
tags: ["openapi"]
|
|
1107
|
+
}
|
|
1108
|
+
});
|
|
1109
|
+
this.routeManager.register({
|
|
1110
|
+
method: "GET",
|
|
1111
|
+
path: `${basePath}/docs`,
|
|
1112
|
+
handler: async (req, res) => {
|
|
1113
|
+
const reqPath = req.path || req.url || `${basePath}/docs`;
|
|
1114
|
+
const apiBase = reqPath.replace(/\/docs\/?$/, "");
|
|
1115
|
+
const specUrl = `${apiBase}/openapi.json`;
|
|
1116
|
+
const html = `<!doctype html>
|
|
1117
|
+
<html>
|
|
1118
|
+
<head>
|
|
1119
|
+
<meta charset="utf-8" />
|
|
1120
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1121
|
+
<title>ObjectStack API Docs</title>
|
|
1122
|
+
</head>
|
|
1123
|
+
<body>
|
|
1124
|
+
<script id="api-reference" data-url="${specUrl}"></script>
|
|
1125
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
1126
|
+
</body>
|
|
1127
|
+
</html>`;
|
|
1128
|
+
if (res.setHeader) res.setHeader("content-type", "text/html; charset=utf-8");
|
|
1129
|
+
if (res.send) res.send(html);
|
|
1130
|
+
else if (res.body) res.body = html;
|
|
1131
|
+
else res.json?.(html);
|
|
1132
|
+
},
|
|
1133
|
+
metadata: {
|
|
1134
|
+
summary: "Interactive API docs (Scalar viewer)",
|
|
1135
|
+
tags: ["openapi"]
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
async loadOpenApiSpec() {
|
|
1140
|
+
if (this._openApiSpecCache !== void 0) return this._openApiSpecCache;
|
|
1141
|
+
try {
|
|
1142
|
+
const mod = await import("module");
|
|
1143
|
+
const requireFn = mod.createRequire(import.meta.url);
|
|
1144
|
+
const pkgJsonPath = requireFn.resolve("@objectstack/spec/package.json");
|
|
1145
|
+
const pathMod = await import("path");
|
|
1146
|
+
const fsMod = await import("fs");
|
|
1147
|
+
const specPath = pathMod.join(pathMod.dirname(pkgJsonPath), "json-schema", "openapi.json");
|
|
1148
|
+
const raw = await fsMod.promises.readFile(specPath, "utf-8");
|
|
1149
|
+
this._openApiSpecCache = JSON.parse(raw);
|
|
1150
|
+
return this._openApiSpecCache;
|
|
1151
|
+
} catch (err) {
|
|
1152
|
+
logError("[REST] Failed to load OpenAPI spec:", err?.message ?? err);
|
|
1153
|
+
this._openApiSpecCache = null;
|
|
1154
|
+
return null;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
990
1157
|
/**
|
|
991
1158
|
* Register metadata endpoints
|
|
992
1159
|
*/
|
|
993
1160
|
registerMetadataEndpoints(basePath) {
|
|
994
1161
|
const { metadata } = this.config;
|
|
995
1162
|
const metaPath = `${basePath}${metadata.prefix}`;
|
|
996
|
-
const isScoped = basePath.includes("/
|
|
1163
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
997
1164
|
if (metadata.endpoints.types !== false) {
|
|
998
1165
|
this.routeManager.register({
|
|
999
1166
|
method: "GET",
|
|
1000
1167
|
path: metaPath,
|
|
1001
1168
|
handler: async (req, res) => {
|
|
1002
1169
|
try {
|
|
1003
|
-
const
|
|
1004
|
-
const p = await this.resolveProtocol(
|
|
1170
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1171
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1005
1172
|
const types = await p.getMetaTypes();
|
|
1006
1173
|
res.json(types);
|
|
1007
1174
|
} catch (error) {
|
|
@@ -1022,14 +1189,14 @@ var RestServer = class {
|
|
|
1022
1189
|
handler: async (req, res) => {
|
|
1023
1190
|
try {
|
|
1024
1191
|
const packageId = req.query?.package || void 0;
|
|
1025
|
-
const
|
|
1026
|
-
const p = await this.resolveProtocol(
|
|
1192
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1193
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1027
1194
|
const items = await p.getMetaItems({
|
|
1028
1195
|
type: req.params.type,
|
|
1029
1196
|
packageId,
|
|
1030
|
-
...
|
|
1197
|
+
...environmentId ? { environmentId } : {}
|
|
1031
1198
|
});
|
|
1032
|
-
const translated = await this.translateMetaItems(req, req.params.type,
|
|
1199
|
+
const translated = await this.translateMetaItems(req, req.params.type, environmentId, items);
|
|
1033
1200
|
res.header("Vary", "Accept-Language");
|
|
1034
1201
|
res.json(translated);
|
|
1035
1202
|
} catch (error) {
|
|
@@ -1049,8 +1216,8 @@ var RestServer = class {
|
|
|
1049
1216
|
path: `${metaPath}/:type/:name`,
|
|
1050
1217
|
handler: async (req, res) => {
|
|
1051
1218
|
try {
|
|
1052
|
-
const
|
|
1053
|
-
const p = await this.resolveProtocol(
|
|
1219
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1220
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1054
1221
|
if (metadata.enableCache && p.getMetaItemCached) {
|
|
1055
1222
|
const cacheRequest = {
|
|
1056
1223
|
ifNoneMatch: req.headers["if-none-match"],
|
|
@@ -1060,7 +1227,7 @@ var RestServer = class {
|
|
|
1060
1227
|
type: req.params.type,
|
|
1061
1228
|
name: req.params.name,
|
|
1062
1229
|
cacheRequest,
|
|
1063
|
-
...
|
|
1230
|
+
...environmentId ? { environmentId } : {}
|
|
1064
1231
|
});
|
|
1065
1232
|
if (result.notModified) {
|
|
1066
1233
|
res.status(304).send();
|
|
@@ -1079,7 +1246,7 @@ var RestServer = class {
|
|
|
1079
1246
|
res.header("Cache-Control", directives + maxAge);
|
|
1080
1247
|
}
|
|
1081
1248
|
res.header("Vary", "Accept-Language");
|
|
1082
|
-
res.json(await this.translateMetaItem(req, req.params.type,
|
|
1249
|
+
res.json(await this.translateMetaItem(req, req.params.type, environmentId, result.data));
|
|
1083
1250
|
} else {
|
|
1084
1251
|
const packageId = req.query?.package || void 0;
|
|
1085
1252
|
const item = await p.getMetaItem({
|
|
@@ -1088,7 +1255,7 @@ var RestServer = class {
|
|
|
1088
1255
|
packageId
|
|
1089
1256
|
});
|
|
1090
1257
|
res.header("Vary", "Accept-Language");
|
|
1091
|
-
res.json(await this.translateMetaItem(req, req.params.type,
|
|
1258
|
+
res.json(await this.translateMetaItem(req, req.params.type, environmentId, item));
|
|
1092
1259
|
}
|
|
1093
1260
|
} catch (error) {
|
|
1094
1261
|
logError("[REST] Unhandled error:", error);
|
|
@@ -1106,8 +1273,8 @@ var RestServer = class {
|
|
|
1106
1273
|
path: `${metaPath}/:type/:name`,
|
|
1107
1274
|
handler: async (req, res) => {
|
|
1108
1275
|
try {
|
|
1109
|
-
const
|
|
1110
|
-
const p = await this.resolveProtocol(
|
|
1276
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1277
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1111
1278
|
if (!p.saveMetaItem) {
|
|
1112
1279
|
res.status(501).json({ error: "Save operation not supported by protocol implementation" });
|
|
1113
1280
|
return;
|
|
@@ -1122,7 +1289,7 @@ var RestServer = class {
|
|
|
1122
1289
|
type: req.params.type,
|
|
1123
1290
|
name: req.params.name,
|
|
1124
1291
|
item,
|
|
1125
|
-
...
|
|
1292
|
+
...environmentId ? { environmentId } : {},
|
|
1126
1293
|
...parentVersion !== void 0 ? { parentVersion } : {},
|
|
1127
1294
|
...actor ? { actor } : {}
|
|
1128
1295
|
});
|
|
@@ -1142,8 +1309,8 @@ var RestServer = class {
|
|
|
1142
1309
|
path: `${metaPath}/:type/:name`,
|
|
1143
1310
|
handler: async (req, res) => {
|
|
1144
1311
|
try {
|
|
1145
|
-
const
|
|
1146
|
-
const p = await this.resolveProtocol(
|
|
1312
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1313
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1147
1314
|
if (!p.deleteMetaItem) {
|
|
1148
1315
|
res.status(501).json({
|
|
1149
1316
|
error: "Reset operation not supported by protocol implementation"
|
|
@@ -1157,7 +1324,7 @@ var RestServer = class {
|
|
|
1157
1324
|
const result = await p.deleteMetaItem({
|
|
1158
1325
|
type: req.params.type,
|
|
1159
1326
|
name: req.params.name,
|
|
1160
|
-
...
|
|
1327
|
+
...environmentId ? { environmentId } : {},
|
|
1161
1328
|
...parentVersion !== void 0 ? { parentVersion } : {},
|
|
1162
1329
|
...actor ? { actor } : {}
|
|
1163
1330
|
});
|
|
@@ -1177,8 +1344,8 @@ var RestServer = class {
|
|
|
1177
1344
|
path: `${metaPath}/:type/:name/history`,
|
|
1178
1345
|
handler: async (req, res) => {
|
|
1179
1346
|
try {
|
|
1180
|
-
const
|
|
1181
|
-
const p = await this.resolveProtocol(
|
|
1347
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1348
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1182
1349
|
if (!p.historyMetaItem) {
|
|
1183
1350
|
res.status(501).json({
|
|
1184
1351
|
error: "History query not supported by protocol implementation"
|
|
@@ -1190,7 +1357,7 @@ var RestServer = class {
|
|
|
1190
1357
|
const result = await p.historyMetaItem({
|
|
1191
1358
|
type: req.params.type,
|
|
1192
1359
|
name: req.params.name,
|
|
1193
|
-
...
|
|
1360
|
+
...environmentId ? { environmentId } : {},
|
|
1194
1361
|
...sinceSeq !== void 0 && Number.isFinite(sinceSeq) ? { sinceSeq } : {},
|
|
1195
1362
|
...limit !== void 0 && Number.isFinite(limit) ? { limit } : {}
|
|
1196
1363
|
});
|
|
@@ -1211,8 +1378,8 @@ var RestServer = class {
|
|
|
1211
1378
|
path: `${metaPath}/:type/:section/:name`,
|
|
1212
1379
|
handler: async (req, res) => {
|
|
1213
1380
|
try {
|
|
1214
|
-
const
|
|
1215
|
-
const p = await this.resolveProtocol(
|
|
1381
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1382
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1216
1383
|
const compoundName = `${req.params.section}/${req.params.name}`;
|
|
1217
1384
|
const packageId = req.query?.package || void 0;
|
|
1218
1385
|
const item = await p.getMetaItem({
|
|
@@ -1221,7 +1388,7 @@ var RestServer = class {
|
|
|
1221
1388
|
packageId
|
|
1222
1389
|
});
|
|
1223
1390
|
res.header("Vary", "Accept-Language");
|
|
1224
|
-
res.json(await this.translateMetaItem(req, req.params.type,
|
|
1391
|
+
res.json(await this.translateMetaItem(req, req.params.type, environmentId, item));
|
|
1225
1392
|
} catch (error) {
|
|
1226
1393
|
logError("[REST] Unhandled error:", error);
|
|
1227
1394
|
sendError(res, error);
|
|
@@ -1238,8 +1405,8 @@ var RestServer = class {
|
|
|
1238
1405
|
path: `${metaPath}/:type/:section/:name`,
|
|
1239
1406
|
handler: async (req, res) => {
|
|
1240
1407
|
try {
|
|
1241
|
-
const
|
|
1242
|
-
const p = await this.resolveProtocol(
|
|
1408
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1409
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1243
1410
|
if (!p.saveMetaItem) {
|
|
1244
1411
|
res.status(501).json({ error: "Save operation not supported by protocol implementation" });
|
|
1245
1412
|
return;
|
|
@@ -1253,7 +1420,7 @@ var RestServer = class {
|
|
|
1253
1420
|
type: req.params.type,
|
|
1254
1421
|
name: compoundName,
|
|
1255
1422
|
item: req.body,
|
|
1256
|
-
...
|
|
1423
|
+
...environmentId ? { environmentId } : {},
|
|
1257
1424
|
...parentVersion !== void 0 ? { parentVersion } : {},
|
|
1258
1425
|
...actor ? { actor } : {}
|
|
1259
1426
|
});
|
|
@@ -1274,19 +1441,19 @@ var RestServer = class {
|
|
|
1274
1441
|
*/
|
|
1275
1442
|
registerUiEndpoints(basePath) {
|
|
1276
1443
|
const uiPath = `${basePath}/ui`;
|
|
1277
|
-
const isScoped = basePath.includes("/
|
|
1444
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1278
1445
|
this.routeManager.register({
|
|
1279
1446
|
method: "GET",
|
|
1280
1447
|
path: `${uiPath}/view/:object/:type`,
|
|
1281
1448
|
handler: async (req, res) => {
|
|
1282
1449
|
try {
|
|
1283
|
-
const
|
|
1284
|
-
const p = await this.resolveProtocol(
|
|
1450
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1451
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1285
1452
|
if (p.getUiView) {
|
|
1286
1453
|
const view = await p.getUiView({
|
|
1287
1454
|
object: req.params.object,
|
|
1288
1455
|
type: req.params.type,
|
|
1289
|
-
...
|
|
1456
|
+
...environmentId ? { environmentId } : {}
|
|
1290
1457
|
});
|
|
1291
1458
|
res.json(view);
|
|
1292
1459
|
} else {
|
|
@@ -1309,7 +1476,7 @@ var RestServer = class {
|
|
|
1309
1476
|
registerCrudEndpoints(basePath) {
|
|
1310
1477
|
const { crud } = this.config;
|
|
1311
1478
|
const dataPath = `${basePath}${crud.dataPrefix}`;
|
|
1312
|
-
const isScoped = basePath.includes("/
|
|
1479
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1313
1480
|
const operations = crud.operations;
|
|
1314
1481
|
if (operations.list) {
|
|
1315
1482
|
this.routeManager.register({
|
|
@@ -1317,14 +1484,14 @@ var RestServer = class {
|
|
|
1317
1484
|
path: `${dataPath}/:object`,
|
|
1318
1485
|
handler: async (req, res) => {
|
|
1319
1486
|
try {
|
|
1320
|
-
const
|
|
1321
|
-
const p = await this.resolveProtocol(
|
|
1322
|
-
const context = await this.resolveExecCtx(
|
|
1487
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1488
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1489
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1323
1490
|
if (this.enforceAuth(req, res, context)) return;
|
|
1324
1491
|
const result = await p.findData({
|
|
1325
1492
|
object: req.params.object,
|
|
1326
1493
|
query: req.query,
|
|
1327
|
-
...
|
|
1494
|
+
...environmentId ? { environmentId } : {},
|
|
1328
1495
|
...context ? { context } : {}
|
|
1329
1496
|
});
|
|
1330
1497
|
res.json(result);
|
|
@@ -1350,17 +1517,17 @@ var RestServer = class {
|
|
|
1350
1517
|
path: `${dataPath}/:object/:id`,
|
|
1351
1518
|
handler: async (req, res) => {
|
|
1352
1519
|
try {
|
|
1353
|
-
const
|
|
1354
|
-
const p = await this.resolveProtocol(
|
|
1520
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1521
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1355
1522
|
const { select, expand } = req.query || {};
|
|
1356
|
-
const context = await this.resolveExecCtx(
|
|
1523
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1357
1524
|
if (this.enforceAuth(req, res, context)) return;
|
|
1358
1525
|
const result = await p.getData({
|
|
1359
1526
|
object: req.params.object,
|
|
1360
1527
|
id: req.params.id,
|
|
1361
1528
|
...select != null ? { select } : {},
|
|
1362
1529
|
...expand != null ? { expand } : {},
|
|
1363
|
-
...
|
|
1530
|
+
...environmentId ? { environmentId } : {},
|
|
1364
1531
|
...context ? { context } : {}
|
|
1365
1532
|
});
|
|
1366
1533
|
res.json(result);
|
|
@@ -1382,14 +1549,14 @@ var RestServer = class {
|
|
|
1382
1549
|
path: `${dataPath}/:object`,
|
|
1383
1550
|
handler: async (req, res) => {
|
|
1384
1551
|
try {
|
|
1385
|
-
const
|
|
1386
|
-
const p = await this.resolveProtocol(
|
|
1387
|
-
const context = await this.resolveExecCtx(
|
|
1552
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1553
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1554
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1388
1555
|
if (this.enforceAuth(req, res, context)) return;
|
|
1389
1556
|
const result = await p.createData({
|
|
1390
1557
|
object: req.params.object,
|
|
1391
1558
|
data: req.body,
|
|
1392
|
-
...
|
|
1559
|
+
...environmentId ? { environmentId } : {},
|
|
1393
1560
|
...context ? { context } : {}
|
|
1394
1561
|
});
|
|
1395
1562
|
res.status(201).json(result);
|
|
@@ -1411,14 +1578,14 @@ var RestServer = class {
|
|
|
1411
1578
|
path: `${dataPath}/:object/query`,
|
|
1412
1579
|
handler: async (req, res) => {
|
|
1413
1580
|
try {
|
|
1414
|
-
const
|
|
1415
|
-
const p = await this.resolveProtocol(
|
|
1416
|
-
const context = await this.resolveExecCtx(
|
|
1581
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1582
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1583
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1417
1584
|
if (this.enforceAuth(req, res, context)) return;
|
|
1418
1585
|
const result = await p.findData({
|
|
1419
1586
|
object: req.params.object,
|
|
1420
1587
|
query: req.body || {},
|
|
1421
|
-
...
|
|
1588
|
+
...environmentId ? { environmentId } : {},
|
|
1422
1589
|
...context ? { context } : {}
|
|
1423
1590
|
});
|
|
1424
1591
|
res.json(result);
|
|
@@ -1440,9 +1607,9 @@ var RestServer = class {
|
|
|
1440
1607
|
path: `${dataPath}/:object/:id`,
|
|
1441
1608
|
handler: async (req, res) => {
|
|
1442
1609
|
try {
|
|
1443
|
-
const
|
|
1444
|
-
const p = await this.resolveProtocol(
|
|
1445
|
-
const context = await this.resolveExecCtx(
|
|
1610
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1611
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1612
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1446
1613
|
if (this.enforceAuth(req, res, context)) return;
|
|
1447
1614
|
const ifMatchHeader = req.headers?.["if-match"] ?? req.headers?.["If-Match"];
|
|
1448
1615
|
const bodyVersion = req.body && typeof req.body === "object" ? req.body.expectedVersion : void 0;
|
|
@@ -1457,7 +1624,7 @@ var RestServer = class {
|
|
|
1457
1624
|
id: req.params.id,
|
|
1458
1625
|
data,
|
|
1459
1626
|
...expectedVersion ? { expectedVersion: String(expectedVersion) } : {},
|
|
1460
|
-
...
|
|
1627
|
+
...environmentId ? { environmentId } : {},
|
|
1461
1628
|
...context ? { context } : {}
|
|
1462
1629
|
});
|
|
1463
1630
|
res.json(result);
|
|
@@ -1479,9 +1646,9 @@ var RestServer = class {
|
|
|
1479
1646
|
path: `${dataPath}/:object/:id`,
|
|
1480
1647
|
handler: async (req, res) => {
|
|
1481
1648
|
try {
|
|
1482
|
-
const
|
|
1483
|
-
const p = await this.resolveProtocol(
|
|
1484
|
-
const context = await this.resolveExecCtx(
|
|
1649
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1650
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1651
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1485
1652
|
if (this.enforceAuth(req, res, context)) return;
|
|
1486
1653
|
const ifMatchHeader = req.headers?.["if-match"] ?? req.headers?.["If-Match"];
|
|
1487
1654
|
const queryVersion = req.query && typeof req.query === "object" ? req.query.expectedVersion : void 0;
|
|
@@ -1490,7 +1657,7 @@ var RestServer = class {
|
|
|
1490
1657
|
object: req.params.object,
|
|
1491
1658
|
id: req.params.id,
|
|
1492
1659
|
...expectedVersion ? { expectedVersion: String(expectedVersion) } : {},
|
|
1493
|
-
...
|
|
1660
|
+
...environmentId ? { environmentId } : {},
|
|
1494
1661
|
...context ? { context } : {}
|
|
1495
1662
|
});
|
|
1496
1663
|
res.json(result);
|
|
@@ -1516,7 +1683,7 @@ var RestServer = class {
|
|
|
1516
1683
|
* POST {basePath}/data/lead/:id/convert — M10.6 lead conversion.
|
|
1517
1684
|
*/
|
|
1518
1685
|
registerDataActionEndpoints(basePath) {
|
|
1519
|
-
const isScoped = basePath.includes("/
|
|
1686
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1520
1687
|
const { crud } = this.config;
|
|
1521
1688
|
const dataPath = `${basePath}${crud.dataPrefix}`;
|
|
1522
1689
|
this.routeManager.register({
|
|
@@ -1524,9 +1691,9 @@ var RestServer = class {
|
|
|
1524
1691
|
path: `${dataPath}/lead/:id/convert`,
|
|
1525
1692
|
handler: async (req, res) => {
|
|
1526
1693
|
try {
|
|
1527
|
-
const
|
|
1528
|
-
const p = await this.resolveProtocol(
|
|
1529
|
-
const context = await this.resolveExecCtx(
|
|
1694
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1695
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1696
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1530
1697
|
if (this.enforceAuth(req, res, context)) return;
|
|
1531
1698
|
const convertLead = p.convertLead;
|
|
1532
1699
|
if (typeof convertLead !== "function") {
|
|
@@ -1559,9 +1726,9 @@ var RestServer = class {
|
|
|
1559
1726
|
path: `${dataPath}/:object/import`,
|
|
1560
1727
|
handler: async (req, res) => {
|
|
1561
1728
|
try {
|
|
1562
|
-
const
|
|
1563
|
-
const p = await this.resolveProtocol(
|
|
1564
|
-
const context = await this.resolveExecCtx(
|
|
1729
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1730
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1731
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1565
1732
|
if (this.enforceAuth(req, res, context)) return;
|
|
1566
1733
|
const objectName = String(req.params.object || "");
|
|
1567
1734
|
if (!objectName) {
|
|
@@ -1642,9 +1809,9 @@ var RestServer = class {
|
|
|
1642
1809
|
path: `${dataPath}/:object/export`,
|
|
1643
1810
|
handler: async (req, res) => {
|
|
1644
1811
|
try {
|
|
1645
|
-
const
|
|
1646
|
-
const p = await this.resolveProtocol(
|
|
1647
|
-
const context = await this.resolveExecCtx(
|
|
1812
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1813
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1814
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1648
1815
|
if (this.enforceAuth(req, res, context)) return;
|
|
1649
1816
|
const objectName = String(req.params.object || "");
|
|
1650
1817
|
if (!objectName) {
|
|
@@ -1693,7 +1860,7 @@ var RestServer = class {
|
|
|
1693
1860
|
}
|
|
1694
1861
|
if (!fields || fields.length === 0) {
|
|
1695
1862
|
try {
|
|
1696
|
-
const schema = await p.getObjectSchema?.(objectName,
|
|
1863
|
+
const schema = await p.getObjectSchema?.(objectName, environmentId);
|
|
1697
1864
|
const schemaFields = schema?.fields;
|
|
1698
1865
|
if (Array.isArray(schemaFields)) {
|
|
1699
1866
|
fields = schemaFields.map((f) => f.name).filter((n) => typeof n === "string");
|
|
@@ -1727,7 +1894,7 @@ var RestServer = class {
|
|
|
1727
1894
|
$top: take,
|
|
1728
1895
|
$skip: skip
|
|
1729
1896
|
},
|
|
1730
|
-
...
|
|
1897
|
+
...environmentId ? { environmentId } : {},
|
|
1731
1898
|
...context ? { context } : {}
|
|
1732
1899
|
};
|
|
1733
1900
|
const result = await p.findData(findArgs);
|
|
@@ -1775,15 +1942,15 @@ var RestServer = class {
|
|
|
1775
1942
|
* GET {basePath}/search?q=acme&objects=lead,account&limit=20&perObject=5
|
|
1776
1943
|
*/
|
|
1777
1944
|
registerSearchEndpoints(basePath) {
|
|
1778
|
-
const isScoped = basePath.includes("/
|
|
1945
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1779
1946
|
this.routeManager.register({
|
|
1780
1947
|
method: "GET",
|
|
1781
1948
|
path: `${basePath}/search`,
|
|
1782
1949
|
handler: async (req, res) => {
|
|
1783
1950
|
try {
|
|
1784
|
-
const
|
|
1785
|
-
const p = await this.resolveProtocol(
|
|
1786
|
-
const context = await this.resolveExecCtx(
|
|
1951
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1952
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1953
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1787
1954
|
if (this.enforceAuth(req, res, context)) return;
|
|
1788
1955
|
const searchAll = p.searchAll;
|
|
1789
1956
|
if (typeof searchAll !== "function") {
|
|
@@ -1835,14 +2002,14 @@ var RestServer = class {
|
|
|
1835
2002
|
* }
|
|
1836
2003
|
*/
|
|
1837
2004
|
registerEmailEndpoints(basePath) {
|
|
1838
|
-
const isScoped = basePath.includes("/
|
|
2005
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1839
2006
|
this.routeManager.register({
|
|
1840
2007
|
method: "POST",
|
|
1841
2008
|
path: `${basePath}/email/send`,
|
|
1842
2009
|
handler: async (req, res) => {
|
|
1843
2010
|
try {
|
|
1844
|
-
const
|
|
1845
|
-
const context = await this.resolveExecCtx(
|
|
2011
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2012
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
1846
2013
|
if (this.enforceAuth(req, res, context)) return;
|
|
1847
2014
|
if (!this.emailServiceProvider) {
|
|
1848
2015
|
res.status(501).json({
|
|
@@ -1851,7 +2018,7 @@ var RestServer = class {
|
|
|
1851
2018
|
});
|
|
1852
2019
|
return;
|
|
1853
2020
|
}
|
|
1854
|
-
const emailService = await this.emailServiceProvider(
|
|
2021
|
+
const emailService = await this.emailServiceProvider(environmentId).catch(() => void 0);
|
|
1855
2022
|
if (!emailService || typeof emailService.send !== "function") {
|
|
1856
2023
|
res.status(501).json({
|
|
1857
2024
|
code: "NOT_IMPLEMENTED",
|
|
@@ -1930,7 +2097,7 @@ var RestServer = class {
|
|
|
1930
2097
|
* `mapViewSpecToEmbeddableConfig` expects.
|
|
1931
2098
|
*/
|
|
1932
2099
|
registerFormEndpoints(basePath) {
|
|
1933
|
-
const isScoped = basePath.includes("/
|
|
2100
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
1934
2101
|
const slugMatchesPublicLink = (publicLink, slug) => {
|
|
1935
2102
|
if (!publicLink || typeof publicLink !== "string") return false;
|
|
1936
2103
|
const normalized = publicLink.replace(/^\/+/, "").replace(/^forms\//, "");
|
|
@@ -1960,12 +2127,12 @@ var RestServer = class {
|
|
|
1960
2127
|
}
|
|
1961
2128
|
return null;
|
|
1962
2129
|
};
|
|
1963
|
-
const resolveFormBySlug = async (
|
|
1964
|
-
const p = await this.resolveProtocol(
|
|
2130
|
+
const resolveFormBySlug = async (environmentId, req, slug) => {
|
|
2131
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1965
2132
|
if (typeof p.getMetaItems !== "function") return null;
|
|
1966
2133
|
const result = await p.getMetaItems({
|
|
1967
2134
|
type: "view",
|
|
1968
|
-
...
|
|
2135
|
+
...environmentId ? { environmentId } : {}
|
|
1969
2136
|
});
|
|
1970
2137
|
const items = Array.isArray(result?.items) ? result.items : Array.isArray(result) ? result : [];
|
|
1971
2138
|
return findPublicFormView(items, slug);
|
|
@@ -1975,13 +2142,13 @@ var RestServer = class {
|
|
|
1975
2142
|
path: `${basePath}/forms/:slug`,
|
|
1976
2143
|
handler: async (req, res) => {
|
|
1977
2144
|
try {
|
|
1978
|
-
const
|
|
2145
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
1979
2146
|
const slug = String(req.params?.slug ?? "").trim();
|
|
1980
2147
|
if (!slug) {
|
|
1981
2148
|
res.status(400).json({ code: "INVALID_REQUEST", error: "slug is required" });
|
|
1982
2149
|
return;
|
|
1983
2150
|
}
|
|
1984
|
-
const match = await resolveFormBySlug(
|
|
2151
|
+
const match = await resolveFormBySlug(environmentId, req, slug);
|
|
1985
2152
|
if (!match) {
|
|
1986
2153
|
res.status(404).json({
|
|
1987
2154
|
code: "FORM_NOT_FOUND",
|
|
@@ -1991,11 +2158,11 @@ var RestServer = class {
|
|
|
1991
2158
|
}
|
|
1992
2159
|
let objectSchema = null;
|
|
1993
2160
|
try {
|
|
1994
|
-
const p = await this.resolveProtocol(
|
|
2161
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
1995
2162
|
if (typeof p.getMetaItems === "function") {
|
|
1996
2163
|
const r = await p.getMetaItems({
|
|
1997
2164
|
type: "object",
|
|
1998
|
-
...
|
|
2165
|
+
...environmentId ? { environmentId } : {}
|
|
1999
2166
|
});
|
|
2000
2167
|
const items = Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];
|
|
2001
2168
|
const obj = items.find((o) => o?.name === match.object);
|
|
@@ -2015,7 +2182,7 @@ var RestServer = class {
|
|
|
2015
2182
|
}
|
|
2016
2183
|
objectSchema = { name: obj.name, label: obj.label, fields };
|
|
2017
2184
|
try {
|
|
2018
|
-
const i18n = await this.resolveI18nService(
|
|
2185
|
+
const i18n = await this.resolveI18nService(environmentId, req);
|
|
2019
2186
|
const bundle = this.buildTranslationBundle(i18n);
|
|
2020
2187
|
const locale = this.extractLocale(req, i18n);
|
|
2021
2188
|
if (bundle && locale) {
|
|
@@ -2075,13 +2242,13 @@ var RestServer = class {
|
|
|
2075
2242
|
path: `${basePath}/forms/:slug/submit`,
|
|
2076
2243
|
handler: async (req, res) => {
|
|
2077
2244
|
try {
|
|
2078
|
-
const
|
|
2245
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2079
2246
|
const slug = String(req.params?.slug ?? "").trim();
|
|
2080
2247
|
if (!slug) {
|
|
2081
2248
|
res.status(400).json({ code: "INVALID_REQUEST", error: "slug is required" });
|
|
2082
2249
|
return;
|
|
2083
2250
|
}
|
|
2084
|
-
const match = await resolveFormBySlug(
|
|
2251
|
+
const match = await resolveFormBySlug(environmentId, req, slug);
|
|
2085
2252
|
if (!match) {
|
|
2086
2253
|
res.status(404).json({
|
|
2087
2254
|
code: "FORM_NOT_FOUND",
|
|
@@ -2109,11 +2276,11 @@ var RestServer = class {
|
|
|
2109
2276
|
permissions: ["guest_portal"],
|
|
2110
2277
|
anonymous: true
|
|
2111
2278
|
};
|
|
2112
|
-
const p = await this.resolveProtocol(
|
|
2279
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
2113
2280
|
const result = await p.createData({
|
|
2114
2281
|
object: match.object,
|
|
2115
2282
|
data: filteredData,
|
|
2116
|
-
...
|
|
2283
|
+
...environmentId ? { environmentId } : {},
|
|
2117
2284
|
context
|
|
2118
2285
|
});
|
|
2119
2286
|
res.status(201).json(result);
|
|
@@ -2135,14 +2302,14 @@ var RestServer = class {
|
|
|
2135
2302
|
path: `${basePath}/forms/:slug/lookup/:field`,
|
|
2136
2303
|
handler: async (req, res) => {
|
|
2137
2304
|
try {
|
|
2138
|
-
const
|
|
2305
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2139
2306
|
const slug = String(req.params?.slug ?? "").trim();
|
|
2140
2307
|
const fieldName = String(req.params?.field ?? "").trim();
|
|
2141
2308
|
if (!slug || !fieldName) {
|
|
2142
2309
|
res.status(400).json({ code: "INVALID_REQUEST", error: "slug and field are required" });
|
|
2143
2310
|
return;
|
|
2144
2311
|
}
|
|
2145
|
-
const match = await resolveFormBySlug(
|
|
2312
|
+
const match = await resolveFormBySlug(environmentId, req, slug);
|
|
2146
2313
|
if (!match) {
|
|
2147
2314
|
res.status(404).json({
|
|
2148
2315
|
code: "FORM_NOT_FOUND",
|
|
@@ -2169,13 +2336,13 @@ var RestServer = class {
|
|
|
2169
2336
|
});
|
|
2170
2337
|
return;
|
|
2171
2338
|
}
|
|
2172
|
-
const p = await this.resolveProtocol(
|
|
2339
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
2173
2340
|
let referenceTo = picker.object;
|
|
2174
2341
|
if (!referenceTo && typeof p.getMetaItems === "function") {
|
|
2175
2342
|
try {
|
|
2176
2343
|
const r = await p.getMetaItems({
|
|
2177
2344
|
type: "object",
|
|
2178
|
-
...
|
|
2345
|
+
...environmentId ? { environmentId } : {}
|
|
2179
2346
|
});
|
|
2180
2347
|
const items = Array.isArray(r?.items) ? r.items : Array.isArray(r) ? r : [];
|
|
2181
2348
|
const obj = items.find((o) => o?.name === match.object);
|
|
@@ -2211,7 +2378,7 @@ var RestServer = class {
|
|
|
2211
2378
|
select: ["id", ...displayFields],
|
|
2212
2379
|
sort: picker.sort ?? [{ field: displayFields[0], order: "asc" }]
|
|
2213
2380
|
},
|
|
2214
|
-
...
|
|
2381
|
+
...environmentId ? { environmentId } : {},
|
|
2215
2382
|
context
|
|
2216
2383
|
});
|
|
2217
2384
|
const rows = Array.isArray(result?.data) ? result.data : Array.isArray(result?.items) ? result.items : [];
|
|
@@ -2261,11 +2428,11 @@ var RestServer = class {
|
|
|
2261
2428
|
registerSharingEndpoints(basePath) {
|
|
2262
2429
|
const { crud } = this.config;
|
|
2263
2430
|
const dataPath = `${basePath}${crud.dataPrefix}`;
|
|
2264
|
-
const isScoped = basePath.includes("/
|
|
2265
|
-
const resolveService = async (
|
|
2431
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
2432
|
+
const resolveService = async (environmentId) => {
|
|
2266
2433
|
if (!this.sharingServiceProvider) return void 0;
|
|
2267
2434
|
try {
|
|
2268
|
-
return await this.sharingServiceProvider(
|
|
2435
|
+
return await this.sharingServiceProvider(environmentId);
|
|
2269
2436
|
} catch {
|
|
2270
2437
|
return void 0;
|
|
2271
2438
|
}
|
|
@@ -2279,10 +2446,10 @@ var RestServer = class {
|
|
|
2279
2446
|
path: `${dataPath}/:object/:id/shares`,
|
|
2280
2447
|
handler: async (req, res) => {
|
|
2281
2448
|
try {
|
|
2282
|
-
const
|
|
2283
|
-
const context = await this.resolveExecCtx(
|
|
2449
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2450
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2284
2451
|
if (this.enforceAuth(req, res, context)) return;
|
|
2285
|
-
const svc = await resolveService(
|
|
2452
|
+
const svc = await resolveService(environmentId);
|
|
2286
2453
|
if (!svc) return respond501(res);
|
|
2287
2454
|
const rows = await svc.listShares(req.params.object, req.params.id, context ?? {});
|
|
2288
2455
|
res.json({ data: rows });
|
|
@@ -2298,10 +2465,10 @@ var RestServer = class {
|
|
|
2298
2465
|
path: `${dataPath}/:object/:id/shares`,
|
|
2299
2466
|
handler: async (req, res) => {
|
|
2300
2467
|
try {
|
|
2301
|
-
const
|
|
2302
|
-
const context = await this.resolveExecCtx(
|
|
2468
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2469
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2303
2470
|
if (this.enforceAuth(req, res, context)) return;
|
|
2304
|
-
const svc = await resolveService(
|
|
2471
|
+
const svc = await resolveService(environmentId);
|
|
2305
2472
|
if (!svc) return respond501(res);
|
|
2306
2473
|
const body = req.body ?? {};
|
|
2307
2474
|
const input = {
|
|
@@ -2340,10 +2507,10 @@ var RestServer = class {
|
|
|
2340
2507
|
path: `${dataPath}/:object/:id/shares/:shareId`,
|
|
2341
2508
|
handler: async (req, res) => {
|
|
2342
2509
|
try {
|
|
2343
|
-
const
|
|
2344
|
-
const context = await this.resolveExecCtx(
|
|
2510
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2511
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2345
2512
|
if (this.enforceAuth(req, res, context)) return;
|
|
2346
|
-
const svc = await resolveService(
|
|
2513
|
+
const svc = await resolveService(environmentId);
|
|
2347
2514
|
if (!svc) return respond501(res);
|
|
2348
2515
|
await svc.revoke(req.params.shareId, context ?? {});
|
|
2349
2516
|
res.status(204).end();
|
|
@@ -2369,11 +2536,11 @@ var RestServer = class {
|
|
|
2369
2536
|
*/
|
|
2370
2537
|
registerSharingRuleEndpoints(basePath) {
|
|
2371
2538
|
const dataPath = basePath;
|
|
2372
|
-
const isScoped = basePath.includes("/
|
|
2373
|
-
const resolveService = async (
|
|
2539
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
2540
|
+
const resolveService = async (environmentId) => {
|
|
2374
2541
|
if (!this.sharingRulesServiceProvider) return void 0;
|
|
2375
2542
|
try {
|
|
2376
|
-
return await this.sharingRulesServiceProvider(
|
|
2543
|
+
return await this.sharingRulesServiceProvider(environmentId);
|
|
2377
2544
|
} catch {
|
|
2378
2545
|
return void 0;
|
|
2379
2546
|
}
|
|
@@ -2398,10 +2565,10 @@ var RestServer = class {
|
|
|
2398
2565
|
path: `${dataPath}/sharing/rules`,
|
|
2399
2566
|
handler: async (req, res) => {
|
|
2400
2567
|
try {
|
|
2401
|
-
const
|
|
2402
|
-
const context = await this.resolveExecCtx(
|
|
2568
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2569
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2403
2570
|
if (this.enforceAuth(req, res, context)) return;
|
|
2404
|
-
const svc = await resolveService(
|
|
2571
|
+
const svc = await resolveService(environmentId);
|
|
2405
2572
|
if (!svc) return respond501(res);
|
|
2406
2573
|
const rows = await svc.listRules({
|
|
2407
2574
|
object: req.query?.object,
|
|
@@ -2419,10 +2586,10 @@ var RestServer = class {
|
|
|
2419
2586
|
path: `${dataPath}/sharing/rules`,
|
|
2420
2587
|
handler: async (req, res) => {
|
|
2421
2588
|
try {
|
|
2422
|
-
const
|
|
2423
|
-
const context = await this.resolveExecCtx(
|
|
2589
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2590
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2424
2591
|
if (this.enforceAuth(req, res, context)) return;
|
|
2425
|
-
const svc = await resolveService(
|
|
2592
|
+
const svc = await resolveService(environmentId);
|
|
2426
2593
|
if (!svc) return respond501(res);
|
|
2427
2594
|
const body = req.body ?? {};
|
|
2428
2595
|
const input = {
|
|
@@ -2449,10 +2616,10 @@ var RestServer = class {
|
|
|
2449
2616
|
path: `${dataPath}/sharing/rules/:idOrName`,
|
|
2450
2617
|
handler: async (req, res) => {
|
|
2451
2618
|
try {
|
|
2452
|
-
const
|
|
2453
|
-
const context = await this.resolveExecCtx(
|
|
2619
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2620
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2454
2621
|
if (this.enforceAuth(req, res, context)) return;
|
|
2455
|
-
const svc = await resolveService(
|
|
2622
|
+
const svc = await resolveService(environmentId);
|
|
2456
2623
|
if (!svc) return respond501(res);
|
|
2457
2624
|
const row = await svc.getRule(req.params.idOrName, context ?? {});
|
|
2458
2625
|
if (!row) return res.status(404).json({ code: "RULE_NOT_FOUND" });
|
|
@@ -2468,10 +2635,10 @@ var RestServer = class {
|
|
|
2468
2635
|
path: `${dataPath}/sharing/rules/:idOrName`,
|
|
2469
2636
|
handler: async (req, res) => {
|
|
2470
2637
|
try {
|
|
2471
|
-
const
|
|
2472
|
-
const context = await this.resolveExecCtx(
|
|
2638
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2639
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2473
2640
|
if (this.enforceAuth(req, res, context)) return;
|
|
2474
|
-
const svc = await resolveService(
|
|
2641
|
+
const svc = await resolveService(environmentId);
|
|
2475
2642
|
if (!svc) return respond501(res);
|
|
2476
2643
|
await svc.deleteRule(req.params.idOrName, context ?? {});
|
|
2477
2644
|
res.status(204).end();
|
|
@@ -2486,10 +2653,10 @@ var RestServer = class {
|
|
|
2486
2653
|
path: `${dataPath}/sharing/rules/:idOrName/evaluate`,
|
|
2487
2654
|
handler: async (req, res) => {
|
|
2488
2655
|
try {
|
|
2489
|
-
const
|
|
2490
|
-
const context = await this.resolveExecCtx(
|
|
2656
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2657
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2491
2658
|
if (this.enforceAuth(req, res, context)) return;
|
|
2492
|
-
const svc = await resolveService(
|
|
2659
|
+
const svc = await resolveService(environmentId);
|
|
2493
2660
|
if (!svc) return respond501(res);
|
|
2494
2661
|
const result = await svc.evaluateRule(req.params.idOrName, context ?? {});
|
|
2495
2662
|
res.json(result);
|
|
@@ -2523,11 +2690,11 @@ var RestServer = class {
|
|
|
2523
2690
|
*/
|
|
2524
2691
|
registerReportsEndpoints(basePath) {
|
|
2525
2692
|
const dataPath = basePath;
|
|
2526
|
-
const isScoped = basePath.includes("/
|
|
2527
|
-
const resolveService = async (
|
|
2693
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
2694
|
+
const resolveService = async (environmentId) => {
|
|
2528
2695
|
if (!this.reportsServiceProvider) return void 0;
|
|
2529
2696
|
try {
|
|
2530
|
-
return await this.reportsServiceProvider(
|
|
2697
|
+
return await this.reportsServiceProvider(environmentId);
|
|
2531
2698
|
} catch {
|
|
2532
2699
|
return void 0;
|
|
2533
2700
|
}
|
|
@@ -2556,10 +2723,10 @@ var RestServer = class {
|
|
|
2556
2723
|
path: `${dataPath}/reports`,
|
|
2557
2724
|
handler: async (req, res) => {
|
|
2558
2725
|
try {
|
|
2559
|
-
const
|
|
2560
|
-
const context = await this.resolveExecCtx(
|
|
2726
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2727
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2561
2728
|
if (this.enforceAuth(req, res, context)) return;
|
|
2562
|
-
const svc = await resolveService(
|
|
2729
|
+
const svc = await resolveService(environmentId);
|
|
2563
2730
|
if (!svc) return respond501(res);
|
|
2564
2731
|
const q = req.query ?? {};
|
|
2565
2732
|
const rows = await svc.listReports({ object: q.object, ownerId: q.ownerId }, context ?? {});
|
|
@@ -2576,10 +2743,10 @@ var RestServer = class {
|
|
|
2576
2743
|
path: `${dataPath}/reports`,
|
|
2577
2744
|
handler: async (req, res) => {
|
|
2578
2745
|
try {
|
|
2579
|
-
const
|
|
2580
|
-
const context = await this.resolveExecCtx(
|
|
2746
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2747
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2581
2748
|
if (this.enforceAuth(req, res, context)) return;
|
|
2582
|
-
const svc = await resolveService(
|
|
2749
|
+
const svc = await resolveService(environmentId);
|
|
2583
2750
|
if (!svc) return respond501(res);
|
|
2584
2751
|
try {
|
|
2585
2752
|
const row = await svc.saveReport(req.body ?? {}, context ?? {});
|
|
@@ -2600,10 +2767,10 @@ var RestServer = class {
|
|
|
2600
2767
|
path: `${dataPath}/reports/:id`,
|
|
2601
2768
|
handler: async (req, res) => {
|
|
2602
2769
|
try {
|
|
2603
|
-
const
|
|
2604
|
-
const context = await this.resolveExecCtx(
|
|
2770
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2771
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2605
2772
|
if (this.enforceAuth(req, res, context)) return;
|
|
2606
|
-
const svc = await resolveService(
|
|
2773
|
+
const svc = await resolveService(environmentId);
|
|
2607
2774
|
if (!svc) return respond501(res);
|
|
2608
2775
|
const row = await svc.getReport(req.params.id, context ?? {});
|
|
2609
2776
|
if (!row) {
|
|
@@ -2623,10 +2790,10 @@ var RestServer = class {
|
|
|
2623
2790
|
path: `${dataPath}/reports/:id`,
|
|
2624
2791
|
handler: async (req, res) => {
|
|
2625
2792
|
try {
|
|
2626
|
-
const
|
|
2627
|
-
const context = await this.resolveExecCtx(
|
|
2793
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2794
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2628
2795
|
if (this.enforceAuth(req, res, context)) return;
|
|
2629
|
-
const svc = await resolveService(
|
|
2796
|
+
const svc = await resolveService(environmentId);
|
|
2630
2797
|
if (!svc) return respond501(res);
|
|
2631
2798
|
await svc.deleteReport(req.params.id, context ?? {});
|
|
2632
2799
|
res.status(204).end();
|
|
@@ -2642,10 +2809,10 @@ var RestServer = class {
|
|
|
2642
2809
|
path: `${dataPath}/reports/:id/run`,
|
|
2643
2810
|
handler: async (req, res) => {
|
|
2644
2811
|
try {
|
|
2645
|
-
const
|
|
2646
|
-
const context = await this.resolveExecCtx(
|
|
2812
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2813
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2647
2814
|
if (this.enforceAuth(req, res, context)) return;
|
|
2648
|
-
const svc = await resolveService(
|
|
2815
|
+
const svc = await resolveService(environmentId);
|
|
2649
2816
|
if (!svc) return respond501(res);
|
|
2650
2817
|
try {
|
|
2651
2818
|
const result = await svc.run(req.params.id, context ?? {});
|
|
@@ -2666,10 +2833,10 @@ var RestServer = class {
|
|
|
2666
2833
|
path: `${dataPath}/reports/:id/schedule`,
|
|
2667
2834
|
handler: async (req, res) => {
|
|
2668
2835
|
try {
|
|
2669
|
-
const
|
|
2670
|
-
const context = await this.resolveExecCtx(
|
|
2836
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2837
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2671
2838
|
if (this.enforceAuth(req, res, context)) return;
|
|
2672
|
-
const svc = await resolveService(
|
|
2839
|
+
const svc = await resolveService(environmentId);
|
|
2673
2840
|
if (!svc) return respond501(res);
|
|
2674
2841
|
const body = req.body ?? {};
|
|
2675
2842
|
try {
|
|
@@ -2702,10 +2869,10 @@ var RestServer = class {
|
|
|
2702
2869
|
path: `${dataPath}/reports/:id/schedules`,
|
|
2703
2870
|
handler: async (req, res) => {
|
|
2704
2871
|
try {
|
|
2705
|
-
const
|
|
2706
|
-
const context = await this.resolveExecCtx(
|
|
2872
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2873
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2707
2874
|
if (this.enforceAuth(req, res, context)) return;
|
|
2708
|
-
const svc = await resolveService(
|
|
2875
|
+
const svc = await resolveService(environmentId);
|
|
2709
2876
|
if (!svc) return respond501(res);
|
|
2710
2877
|
const rows = await svc.listSchedules({ reportId: req.params.id }, context ?? {});
|
|
2711
2878
|
res.json({ data: rows });
|
|
@@ -2721,10 +2888,10 @@ var RestServer = class {
|
|
|
2721
2888
|
path: `${dataPath}/reports/schedules/:scheduleId`,
|
|
2722
2889
|
handler: async (req, res) => {
|
|
2723
2890
|
try {
|
|
2724
|
-
const
|
|
2725
|
-
const context = await this.resolveExecCtx(
|
|
2891
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2892
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2726
2893
|
if (this.enforceAuth(req, res, context)) return;
|
|
2727
|
-
const svc = await resolveService(
|
|
2894
|
+
const svc = await resolveService(environmentId);
|
|
2728
2895
|
if (!svc) return respond501(res);
|
|
2729
2896
|
await svc.unscheduleReport(req.params.scheduleId, context ?? {});
|
|
2730
2897
|
res.status(204).end();
|
|
@@ -2757,11 +2924,11 @@ var RestServer = class {
|
|
|
2757
2924
|
*/
|
|
2758
2925
|
registerApprovalsEndpoints(basePath) {
|
|
2759
2926
|
const dataPath = basePath;
|
|
2760
|
-
const isScoped = basePath.includes("/
|
|
2761
|
-
const resolveService = async (
|
|
2927
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
2928
|
+
const resolveService = async (environmentId) => {
|
|
2762
2929
|
if (!this.approvalsServiceProvider) return void 0;
|
|
2763
2930
|
try {
|
|
2764
|
-
return await this.approvalsServiceProvider(
|
|
2931
|
+
return await this.approvalsServiceProvider(environmentId);
|
|
2765
2932
|
} catch {
|
|
2766
2933
|
return void 0;
|
|
2767
2934
|
}
|
|
@@ -2794,10 +2961,10 @@ var RestServer = class {
|
|
|
2794
2961
|
path: `${dataPath}/approvals/processes`,
|
|
2795
2962
|
handler: async (req, res) => {
|
|
2796
2963
|
try {
|
|
2797
|
-
const
|
|
2798
|
-
const context = await this.resolveExecCtx(
|
|
2964
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2965
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2799
2966
|
if (this.enforceAuth(req, res, context)) return;
|
|
2800
|
-
const svc = await resolveService(
|
|
2967
|
+
const svc = await resolveService(environmentId);
|
|
2801
2968
|
if (!svc) return respond501(res);
|
|
2802
2969
|
const q = req.query ?? {};
|
|
2803
2970
|
const rows = await svc.listProcesses({
|
|
@@ -2817,10 +2984,10 @@ var RestServer = class {
|
|
|
2817
2984
|
path: `${dataPath}/approvals/processes`,
|
|
2818
2985
|
handler: async (req, res) => {
|
|
2819
2986
|
try {
|
|
2820
|
-
const
|
|
2821
|
-
const context = await this.resolveExecCtx(
|
|
2987
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
2988
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2822
2989
|
if (this.enforceAuth(req, res, context)) return;
|
|
2823
|
-
const svc = await resolveService(
|
|
2990
|
+
const svc = await resolveService(environmentId);
|
|
2824
2991
|
if (!svc) return respond501(res);
|
|
2825
2992
|
try {
|
|
2826
2993
|
const row = await svc.defineProcess(req.body ?? {}, context ?? {});
|
|
@@ -2841,10 +3008,10 @@ var RestServer = class {
|
|
|
2841
3008
|
path: `${dataPath}/approvals/processes/:id`,
|
|
2842
3009
|
handler: async (req, res) => {
|
|
2843
3010
|
try {
|
|
2844
|
-
const
|
|
2845
|
-
const context = await this.resolveExecCtx(
|
|
3011
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3012
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2846
3013
|
if (this.enforceAuth(req, res, context)) return;
|
|
2847
|
-
const svc = await resolveService(
|
|
3014
|
+
const svc = await resolveService(environmentId);
|
|
2848
3015
|
if (!svc) return respond501(res);
|
|
2849
3016
|
const row = await svc.getProcess(req.params.id, context ?? {});
|
|
2850
3017
|
if (!row) {
|
|
@@ -2864,10 +3031,10 @@ var RestServer = class {
|
|
|
2864
3031
|
path: `${dataPath}/approvals/processes/:id`,
|
|
2865
3032
|
handler: async (req, res) => {
|
|
2866
3033
|
try {
|
|
2867
|
-
const
|
|
2868
|
-
const context = await this.resolveExecCtx(
|
|
3034
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3035
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2869
3036
|
if (this.enforceAuth(req, res, context)) return;
|
|
2870
|
-
const svc = await resolveService(
|
|
3037
|
+
const svc = await resolveService(environmentId);
|
|
2871
3038
|
if (!svc) return respond501(res);
|
|
2872
3039
|
await svc.deleteProcess(req.params.id, context ?? {});
|
|
2873
3040
|
res.status(204).end();
|
|
@@ -2883,10 +3050,10 @@ var RestServer = class {
|
|
|
2883
3050
|
path: `${dataPath}/approvals/requests`,
|
|
2884
3051
|
handler: async (req, res) => {
|
|
2885
3052
|
try {
|
|
2886
|
-
const
|
|
2887
|
-
const context = await this.resolveExecCtx(
|
|
3053
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3054
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2888
3055
|
if (this.enforceAuth(req, res, context)) return;
|
|
2889
|
-
const svc = await resolveService(
|
|
3056
|
+
const svc = await resolveService(environmentId);
|
|
2890
3057
|
if (!svc) return respond501(res);
|
|
2891
3058
|
const body = req.body ?? {};
|
|
2892
3059
|
try {
|
|
@@ -2915,10 +3082,10 @@ var RestServer = class {
|
|
|
2915
3082
|
path: `${dataPath}/approvals/requests`,
|
|
2916
3083
|
handler: async (req, res) => {
|
|
2917
3084
|
try {
|
|
2918
|
-
const
|
|
2919
|
-
const context = await this.resolveExecCtx(
|
|
3085
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3086
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2920
3087
|
if (this.enforceAuth(req, res, context)) return;
|
|
2921
|
-
const svc = await resolveService(
|
|
3088
|
+
const svc = await resolveService(environmentId);
|
|
2922
3089
|
if (!svc) {
|
|
2923
3090
|
res.json({ data: [] });
|
|
2924
3091
|
return;
|
|
@@ -2944,10 +3111,10 @@ var RestServer = class {
|
|
|
2944
3111
|
path: `${dataPath}/approvals/requests/:id`,
|
|
2945
3112
|
handler: async (req, res) => {
|
|
2946
3113
|
try {
|
|
2947
|
-
const
|
|
2948
|
-
const context = await this.resolveExecCtx(
|
|
3114
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3115
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2949
3116
|
if (this.enforceAuth(req, res, context)) return;
|
|
2950
|
-
const svc = await resolveService(
|
|
3117
|
+
const svc = await resolveService(environmentId);
|
|
2951
3118
|
if (!svc) return respond501(res);
|
|
2952
3119
|
const row = await svc.getRequest(req.params.id, context ?? {});
|
|
2953
3120
|
if (!row) {
|
|
@@ -2968,10 +3135,10 @@ var RestServer = class {
|
|
|
2968
3135
|
path: `${dataPath}/approvals/requests/:id/${suffix}`,
|
|
2969
3136
|
handler: async (req, res) => {
|
|
2970
3137
|
try {
|
|
2971
|
-
const
|
|
2972
|
-
const context = await this.resolveExecCtx(
|
|
3138
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3139
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
2973
3140
|
if (this.enforceAuth(req, res, context)) return;
|
|
2974
|
-
const svc = await resolveService(
|
|
3141
|
+
const svc = await resolveService(environmentId);
|
|
2975
3142
|
if (!svc) return respond501(res);
|
|
2976
3143
|
const body = req.body ?? {};
|
|
2977
3144
|
try {
|
|
@@ -3000,10 +3167,10 @@ var RestServer = class {
|
|
|
3000
3167
|
path: `${dataPath}/approvals/requests/:id/actions`,
|
|
3001
3168
|
handler: async (req, res) => {
|
|
3002
3169
|
try {
|
|
3003
|
-
const
|
|
3004
|
-
const context = await this.resolveExecCtx(
|
|
3170
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3171
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3005
3172
|
if (this.enforceAuth(req, res, context)) return;
|
|
3006
|
-
const svc = await resolveService(
|
|
3173
|
+
const svc = await resolveService(environmentId);
|
|
3007
3174
|
if (!svc) return respond501(res);
|
|
3008
3175
|
const rows = await svc.listActions(req.params.id, context ?? {});
|
|
3009
3176
|
res.json({ data: rows });
|
|
@@ -3021,7 +3188,7 @@ var RestServer = class {
|
|
|
3021
3188
|
registerBatchEndpoints(basePath) {
|
|
3022
3189
|
const { crud, batch } = this.config;
|
|
3023
3190
|
const dataPath = `${basePath}${crud.dataPrefix}`;
|
|
3024
|
-
const isScoped = basePath.includes("/
|
|
3191
|
+
const isScoped = basePath.includes("/environments/:environmentId");
|
|
3025
3192
|
const operations = batch.operations;
|
|
3026
3193
|
if (batch.enableBatchEndpoint && this.protocol.batchData) {
|
|
3027
3194
|
this.routeManager.register({
|
|
@@ -3029,14 +3196,14 @@ var RestServer = class {
|
|
|
3029
3196
|
path: `${dataPath}/:object/batch`,
|
|
3030
3197
|
handler: async (req, res) => {
|
|
3031
3198
|
try {
|
|
3032
|
-
const
|
|
3033
|
-
const p = await this.resolveProtocol(
|
|
3034
|
-
const context = await this.resolveExecCtx(
|
|
3199
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3200
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
3201
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3035
3202
|
if (this.enforceAuth(req, res, context)) return;
|
|
3036
3203
|
const result = await p.batchData({
|
|
3037
3204
|
object: req.params.object,
|
|
3038
3205
|
request: req.body,
|
|
3039
|
-
...
|
|
3206
|
+
...environmentId ? { environmentId } : {},
|
|
3040
3207
|
...context ? { context } : {}
|
|
3041
3208
|
});
|
|
3042
3209
|
res.json(result);
|
|
@@ -3057,14 +3224,14 @@ var RestServer = class {
|
|
|
3057
3224
|
path: `${dataPath}/:object/createMany`,
|
|
3058
3225
|
handler: async (req, res) => {
|
|
3059
3226
|
try {
|
|
3060
|
-
const
|
|
3061
|
-
const p = await this.resolveProtocol(
|
|
3062
|
-
const context = await this.resolveExecCtx(
|
|
3227
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3228
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
3229
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3063
3230
|
if (this.enforceAuth(req, res, context)) return;
|
|
3064
3231
|
const result = await p.createManyData({
|
|
3065
3232
|
object: req.params.object,
|
|
3066
3233
|
records: req.body || [],
|
|
3067
|
-
...
|
|
3234
|
+
...environmentId ? { environmentId } : {},
|
|
3068
3235
|
...context ? { context } : {}
|
|
3069
3236
|
});
|
|
3070
3237
|
res.status(201).json(result);
|
|
@@ -3085,14 +3252,14 @@ var RestServer = class {
|
|
|
3085
3252
|
path: `${dataPath}/:object/updateMany`,
|
|
3086
3253
|
handler: async (req, res) => {
|
|
3087
3254
|
try {
|
|
3088
|
-
const
|
|
3089
|
-
const p = await this.resolveProtocol(
|
|
3090
|
-
const context = await this.resolveExecCtx(
|
|
3255
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3256
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
3257
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3091
3258
|
if (this.enforceAuth(req, res, context)) return;
|
|
3092
3259
|
const result = await p.updateManyData({
|
|
3093
3260
|
object: req.params.object,
|
|
3094
3261
|
...req.body,
|
|
3095
|
-
...
|
|
3262
|
+
...environmentId ? { environmentId } : {},
|
|
3096
3263
|
...context ? { context } : {}
|
|
3097
3264
|
});
|
|
3098
3265
|
res.json(result);
|
|
@@ -3113,14 +3280,14 @@ var RestServer = class {
|
|
|
3113
3280
|
path: `${dataPath}/:object/deleteMany`,
|
|
3114
3281
|
handler: async (req, res) => {
|
|
3115
3282
|
try {
|
|
3116
|
-
const
|
|
3117
|
-
const p = await this.resolveProtocol(
|
|
3118
|
-
const context = await this.resolveExecCtx(
|
|
3283
|
+
const environmentId = isScoped ? req.params?.environmentId : void 0;
|
|
3284
|
+
const p = await this.resolveProtocol(environmentId, req);
|
|
3285
|
+
const context = await this.resolveExecCtx(environmentId, req);
|
|
3119
3286
|
if (this.enforceAuth(req, res, context)) return;
|
|
3120
3287
|
const result = await p.deleteManyData({
|
|
3121
3288
|
object: req.params.object,
|
|
3122
3289
|
...req.body,
|
|
3123
|
-
...
|
|
3290
|
+
...environmentId ? { environmentId } : {},
|
|
3124
3291
|
...context ? { context } : {}
|
|
3125
3292
|
});
|
|
3126
3293
|
res.json(result);
|
|
@@ -3298,64 +3465,64 @@ function createRestApiPlugin(config = {}) {
|
|
|
3298
3465
|
envRegistry = ctx.getService("env-registry");
|
|
3299
3466
|
} catch (e) {
|
|
3300
3467
|
}
|
|
3301
|
-
const
|
|
3468
|
+
const defaultEnvironmentIdProvider = () => {
|
|
3302
3469
|
try {
|
|
3303
3470
|
const dp = ctx.getService("default-project");
|
|
3304
|
-
return dp?.
|
|
3471
|
+
return dp?.environmentId;
|
|
3305
3472
|
} catch {
|
|
3306
3473
|
return void 0;
|
|
3307
3474
|
}
|
|
3308
3475
|
};
|
|
3309
|
-
const authServiceProvider = async (
|
|
3476
|
+
const authServiceProvider = async (_environmentId) => {
|
|
3310
3477
|
try {
|
|
3311
3478
|
return ctx.getService("auth");
|
|
3312
3479
|
} catch {
|
|
3313
3480
|
return void 0;
|
|
3314
3481
|
}
|
|
3315
3482
|
};
|
|
3316
|
-
const objectQLProvider = async (
|
|
3483
|
+
const objectQLProvider = async (_environmentId) => {
|
|
3317
3484
|
try {
|
|
3318
3485
|
return ctx.getService("objectql");
|
|
3319
3486
|
} catch {
|
|
3320
3487
|
return void 0;
|
|
3321
3488
|
}
|
|
3322
3489
|
};
|
|
3323
|
-
const emailServiceProvider = async (
|
|
3490
|
+
const emailServiceProvider = async (_environmentId) => {
|
|
3324
3491
|
try {
|
|
3325
3492
|
return ctx.getService("email");
|
|
3326
3493
|
} catch {
|
|
3327
3494
|
return void 0;
|
|
3328
3495
|
}
|
|
3329
3496
|
};
|
|
3330
|
-
const sharingServiceProvider = async (
|
|
3497
|
+
const sharingServiceProvider = async (_environmentId) => {
|
|
3331
3498
|
try {
|
|
3332
3499
|
return ctx.getService("sharing");
|
|
3333
3500
|
} catch {
|
|
3334
3501
|
return void 0;
|
|
3335
3502
|
}
|
|
3336
3503
|
};
|
|
3337
|
-
const reportsServiceProvider = async (
|
|
3504
|
+
const reportsServiceProvider = async (_environmentId) => {
|
|
3338
3505
|
try {
|
|
3339
3506
|
return ctx.getService("reports");
|
|
3340
3507
|
} catch {
|
|
3341
3508
|
return void 0;
|
|
3342
3509
|
}
|
|
3343
3510
|
};
|
|
3344
|
-
const approvalsServiceProvider = async (
|
|
3511
|
+
const approvalsServiceProvider = async (_environmentId) => {
|
|
3345
3512
|
try {
|
|
3346
3513
|
return ctx.getService("approvals");
|
|
3347
3514
|
} catch {
|
|
3348
3515
|
return void 0;
|
|
3349
3516
|
}
|
|
3350
3517
|
};
|
|
3351
|
-
const sharingRulesServiceProvider = async (
|
|
3518
|
+
const sharingRulesServiceProvider = async (_environmentId) => {
|
|
3352
3519
|
try {
|
|
3353
3520
|
return ctx.getService("sharingRules");
|
|
3354
3521
|
} catch {
|
|
3355
3522
|
return void 0;
|
|
3356
3523
|
}
|
|
3357
3524
|
};
|
|
3358
|
-
const i18nServiceProvider = async (
|
|
3525
|
+
const i18nServiceProvider = async (_environmentId) => {
|
|
3359
3526
|
try {
|
|
3360
3527
|
return ctx.getService("i18n");
|
|
3361
3528
|
} catch {
|
|
@@ -3372,7 +3539,7 @@ function createRestApiPlugin(config = {}) {
|
|
|
3372
3539
|
}
|
|
3373
3540
|
ctx.logger.info("Hydrating REST API from Protocol...");
|
|
3374
3541
|
try {
|
|
3375
|
-
const restServer = new RestServer(server, protocol, config.api, kernelManager, envRegistry,
|
|
3542
|
+
const restServer = new RestServer(server, protocol, config.api, kernelManager, envRegistry, defaultEnvironmentIdProvider, authServiceProvider, objectQLProvider, emailServiceProvider, sharingServiceProvider, reportsServiceProvider, approvalsServiceProvider, sharingRulesServiceProvider, i18nServiceProvider);
|
|
3376
3543
|
restServer.registerRoutes();
|
|
3377
3544
|
ctx.logger.info("REST API successfully registered");
|
|
3378
3545
|
} catch (err) {
|
|
@@ -3388,13 +3555,13 @@ function createRestApiPlugin(config = {}) {
|
|
|
3388
3555
|
const enableProjectScoping = config.api?.api?.enableProjectScoping ?? false;
|
|
3389
3556
|
const projectResolution = config.api?.api?.projectResolution ?? "auto";
|
|
3390
3557
|
if (enableProjectScoping && projectResolution === "required") {
|
|
3391
|
-
registerPackageRoutes(server, packageService, `${versionedBase}/
|
|
3558
|
+
registerPackageRoutes(server, packageService, `${versionedBase}/environments/:environmentId`, {
|
|
3392
3559
|
protocol
|
|
3393
3560
|
});
|
|
3394
3561
|
} else {
|
|
3395
3562
|
registerPackageRoutes(server, packageService, versionedBase, { protocol });
|
|
3396
3563
|
if (enableProjectScoping) {
|
|
3397
|
-
registerPackageRoutes(server, packageService, `${versionedBase}/
|
|
3564
|
+
registerPackageRoutes(server, packageService, `${versionedBase}/environments/:environmentId`, {
|
|
3398
3565
|
protocol
|
|
3399
3566
|
});
|
|
3400
3567
|
}
|