@ensera/plugin-backend 1.1.0 → 1.2.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.d.ts +14 -1
- package/dist/index.js +103 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -391,4 +391,17 @@ type CommandRegistry = {
|
|
|
391
391
|
declare function createCommandRegistry(): CommandRegistry;
|
|
392
392
|
declare function createCoreRouter(app: Express, registry: CommandRegistry): void;
|
|
393
393
|
|
|
394
|
-
|
|
394
|
+
type CreateDbOptions = {
|
|
395
|
+
prismaDir?: string;
|
|
396
|
+
coreApiUrl?: string;
|
|
397
|
+
serviceToken?: string;
|
|
398
|
+
runMigrations?: boolean;
|
|
399
|
+
};
|
|
400
|
+
type DbProvisionResult = {
|
|
401
|
+
connectionString: string;
|
|
402
|
+
schemaName: string;
|
|
403
|
+
featureSlug: string;
|
|
404
|
+
};
|
|
405
|
+
declare function provisionDb(options?: CreateDbOptions): Promise<DbProvisionResult>;
|
|
406
|
+
|
|
407
|
+
export { type BackendNotification, type CommandHandler, type CommandRegistry, type CoreRequestContext, type CreateDbOptions, type DbProvisionResult, type JsonObject, type JsonValue, type NotificationAction, type NotificationApiPayload, type NotificationBulkApiPayload, type NotificationBulkResponse, type NotificationCancelResponse, type NotificationCapabilities, type NotificationOptions, type NotificationPublishResponse, type NotificationPublisher, type NotificationPublisherConfig, type NotificationTypeConfig, type PluginAuthOptions, type PluginContext, PluginError, type PluginErrorResponse, type PluginScope, type RequestWithContext, type ScheduleOptions, assertPluginScope, buildDateTime, calculateScheduleTime, createCommandRegistry, createCoreRouter, createNotificationPublisher, forbidClientInstanceId, formatTime, getPluginScope, isPastDate, pluginAuth, pluginErrorHandler, provisionDb, requireFeature, requirePermission, requireTabView, requireTaskScope, resolveEffectiveInstanceId, toDateString, withCoreServiceToken, withInstanceOnly, withInstanceScope, withUserAndInstance };
|
package/dist/index.js
CHANGED
|
@@ -751,6 +751,108 @@ function createCoreRouter(app, registry) {
|
|
|
751
751
|
})
|
|
752
752
|
);
|
|
753
753
|
}
|
|
754
|
+
|
|
755
|
+
// src/createDb.ts
|
|
756
|
+
import { execSync } from "child_process";
|
|
757
|
+
import fs from "fs";
|
|
758
|
+
import path from "path";
|
|
759
|
+
function isRecord(value) {
|
|
760
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
761
|
+
}
|
|
762
|
+
function getString(value) {
|
|
763
|
+
if (typeof value !== "string") return void 0;
|
|
764
|
+
const trimmed = value.trim();
|
|
765
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
766
|
+
}
|
|
767
|
+
function parseProvisionResult(value) {
|
|
768
|
+
if (!isRecord(value)) {
|
|
769
|
+
throw new Error("provisionDb: Core returned an invalid response body");
|
|
770
|
+
}
|
|
771
|
+
const connectionString = getString(value.connectionString);
|
|
772
|
+
const schemaName = getString(value.schemaName);
|
|
773
|
+
const featureSlug = getString(value.featureSlug);
|
|
774
|
+
if (!connectionString) {
|
|
775
|
+
throw new Error("provisionDb: Core did not return a connectionString");
|
|
776
|
+
}
|
|
777
|
+
if (!schemaName) {
|
|
778
|
+
throw new Error("provisionDb: Core did not return a schemaName");
|
|
779
|
+
}
|
|
780
|
+
if (!featureSlug) {
|
|
781
|
+
throw new Error("provisionDb: Core did not return a featureSlug");
|
|
782
|
+
}
|
|
783
|
+
return {
|
|
784
|
+
connectionString,
|
|
785
|
+
schemaName,
|
|
786
|
+
featureSlug
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
async function provisionDb(options = {}) {
|
|
790
|
+
const coreApiUrl = (options.coreApiUrl ?? process.env.CORE_API_URL)?.replace(/\/+$/, "");
|
|
791
|
+
const serviceToken = options.serviceToken ?? process.env.CORE_SERVICE_TOKEN;
|
|
792
|
+
if (!coreApiUrl) {
|
|
793
|
+
throw new Error(
|
|
794
|
+
"provisionDb: CORE_API_URL is not set. Add it to your .env file."
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
if (!serviceToken) {
|
|
798
|
+
throw new Error(
|
|
799
|
+
"provisionDb: CORE_SERVICE_TOKEN is not set. Add it to your .env file."
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
const response = await fetch(`${coreApiUrl}/api/internal/db/provision`, {
|
|
803
|
+
method: "POST",
|
|
804
|
+
headers: {
|
|
805
|
+
"Content-Type": "application/json",
|
|
806
|
+
Authorization: `Bearer ${serviceToken}`
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
let payload = null;
|
|
810
|
+
try {
|
|
811
|
+
payload = await response.json();
|
|
812
|
+
} catch {
|
|
813
|
+
payload = null;
|
|
814
|
+
}
|
|
815
|
+
if (!response.ok) {
|
|
816
|
+
const errorMessage = isRecord(payload) ? getString(payload.error) : void 0;
|
|
817
|
+
throw new Error(
|
|
818
|
+
`provisionDb: Core returned ${response.status}. ${errorMessage ?? "Unknown error"}`
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
const result = parseProvisionResult(payload);
|
|
822
|
+
const shouldMigrate = options.runMigrations !== false;
|
|
823
|
+
if (shouldMigrate) {
|
|
824
|
+
const prismaDir = options.prismaDir ?? path.join(process.cwd(), "prisma");
|
|
825
|
+
const migrationsDir = path.join(prismaDir, "migrations");
|
|
826
|
+
if (fs.existsSync(prismaDir) && fs.existsSync(migrationsDir)) {
|
|
827
|
+
console.log(
|
|
828
|
+
`[ensera-db] Running migrations for schema: ${result.schemaName}`
|
|
829
|
+
);
|
|
830
|
+
try {
|
|
831
|
+
execSync("npx prisma migrate deploy", {
|
|
832
|
+
cwd: path.dirname(prismaDir),
|
|
833
|
+
stdio: "inherit",
|
|
834
|
+
env: {
|
|
835
|
+
...process.env,
|
|
836
|
+
DATABASE_URL: result.connectionString
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
console.log("[ensera-db] Migrations complete");
|
|
840
|
+
} catch (error) {
|
|
841
|
+
const message = error instanceof Error ? error.message : "Unknown migration error";
|
|
842
|
+
throw new Error(`[ensera-db] Migration failed: ${message}`);
|
|
843
|
+
}
|
|
844
|
+
} else if (fs.existsSync(prismaDir)) {
|
|
845
|
+
console.warn(
|
|
846
|
+
`[ensera-db] No prisma migrations found at ${migrationsDir}. Skipping migrations.`
|
|
847
|
+
);
|
|
848
|
+
} else {
|
|
849
|
+
console.warn(
|
|
850
|
+
`[ensera-db] No prisma directory found at ${prismaDir}. Skipping migrations.`
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
return result;
|
|
855
|
+
}
|
|
754
856
|
export {
|
|
755
857
|
PluginError,
|
|
756
858
|
assertPluginScope,
|
|
@@ -765,6 +867,7 @@ export {
|
|
|
765
867
|
isPastDate,
|
|
766
868
|
pluginAuth,
|
|
767
869
|
pluginErrorHandler,
|
|
870
|
+
provisionDb,
|
|
768
871
|
requireFeature,
|
|
769
872
|
requirePermission,
|
|
770
873
|
requireTabView,
|