mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-30 12:21:57 +00:00
chore: Do the migrations
This commit is contained in:
12
Makefile
12
Makefile
@@ -3,14 +3,17 @@ version = $(shell git tag --sort=committerdate | tail -1)
|
|||||||
test: $(TS_FILES) lib/test/output.ts
|
test: $(TS_FILES) lib/test/output.ts
|
||||||
npm test
|
npm test
|
||||||
|
|
||||||
make clean:
|
clean:
|
||||||
rm -rf dist
|
rm -rf dist/* | true
|
||||||
|
|
||||||
lib/test/output.ts: lib/test/makeOutput.ts scripts/oldSpecToBuilder.ts
|
lib/test/output.ts: lib/test/makeOutput.ts scripts/oldSpecToBuilder.ts
|
||||||
npm run buildOutput
|
npm run buildOutput
|
||||||
|
|
||||||
bundle: fmt $(TS_FILES) package.json .FORCE node_modules test
|
bundle: clean fmt $(TS_FILES) package.json .FORCE node_modules test
|
||||||
npx tsc
|
npx tsc
|
||||||
|
cp package.json dist/package.json
|
||||||
|
cp README.md dist/README.md
|
||||||
|
cp LICENSE dist/LICENSE
|
||||||
|
|
||||||
check:
|
check:
|
||||||
npm run check
|
npm run check
|
||||||
@@ -22,9 +25,6 @@ node_modules: package.json
|
|||||||
npm install
|
npm install
|
||||||
|
|
||||||
publish: clean bundle package.json README.md LICENSE
|
publish: clean bundle package.json README.md LICENSE
|
||||||
cp package.json dist/package.json
|
|
||||||
cp README.md dist/README.md
|
|
||||||
cp LICENSE dist/LICENSE
|
|
||||||
cd dist && npm publish
|
cd dist && npm publish
|
||||||
link: bundle
|
link: bundle
|
||||||
cp package.json dist/package.json
|
cp package.json dist/package.json
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ export function setupActions(...createdActions: CreatedAction<any, any>[]) {
|
|||||||
actions[action.metaData.id] = action.exportedAction;
|
actions[action.metaData.id] = action.exportedAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
const manifestActions = async (effects: Effects) => {
|
const initializeActions = async (effects: Effects) => {
|
||||||
for (const action of createdActions) {
|
for (const action of createdActions) {
|
||||||
action.exportAction(effects);
|
action.exportAction(effects);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
actions,
|
actions,
|
||||||
manifestActions,
|
initializeActions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { GenericManifest } from "../manifest/ManifestTypes";
|
import { GenericManifest } from "../manifest/ManifestTypes";
|
||||||
import * as T from "../types";
|
import * as T from "../types";
|
||||||
|
|
||||||
|
export type BACKUP = "BACKUP";
|
||||||
export const DEFAULT_OPTIONS: T.BackupOptions = {
|
export const DEFAULT_OPTIONS: T.BackupOptions = {
|
||||||
delete: true,
|
delete: true,
|
||||||
force: true,
|
force: true,
|
||||||
ignoreExisting: false,
|
ignoreExisting: false,
|
||||||
exclude: [],
|
exclude: [],
|
||||||
};
|
};
|
||||||
type BackupSet = {
|
type BackupSet<Volumes extends string> = {
|
||||||
srcPath: string;
|
srcPath: string;
|
||||||
srcVolume: string;
|
srcVolume: Volumes | BACKUP;
|
||||||
dstPath: string;
|
dstPath: string;
|
||||||
dstVolume: string;
|
dstVolume: Volumes | BACKUP;
|
||||||
options?: Partial<T.BackupOptions>;
|
options?: Partial<T.BackupOptions>;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
@@ -37,13 +38,13 @@ type BackupSet = {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export class Backups<M extends GenericManifest> {
|
export class Backups<M extends GenericManifest> {
|
||||||
static BACKUP = "BACKUP" as const;
|
static BACKUP: BACKUP = "BACKUP";
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private options = DEFAULT_OPTIONS,
|
private options = DEFAULT_OPTIONS,
|
||||||
private backupSet = [] as BackupSet[],
|
private backupSet = [] as BackupSet<keyof M["volumes"] & string>[],
|
||||||
) {}
|
) {}
|
||||||
static volumes<M extends GenericManifest>(
|
static volumes<M extends GenericManifest = never>(
|
||||||
...volumeNames: Array<keyof M["volumes"] & string>
|
...volumeNames: Array<keyof M["volumes"] & string>
|
||||||
) {
|
) {
|
||||||
return new Backups().addSets(
|
return new Backups().addSets(
|
||||||
@@ -55,10 +56,14 @@ export class Backups<M extends GenericManifest> {
|
|||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
static addSets(...options: BackupSet[]) {
|
static addSets<M extends GenericManifest = never>(
|
||||||
|
...options: BackupSet<keyof M["volumes"] & string>[]
|
||||||
|
) {
|
||||||
return new Backups().addSets(...options);
|
return new Backups().addSets(...options);
|
||||||
}
|
}
|
||||||
static with_options(options?: Partial<T.BackupOptions>) {
|
static with_options<M extends GenericManifest = never>(
|
||||||
|
options?: Partial<T.BackupOptions>,
|
||||||
|
) {
|
||||||
return new Backups({ ...DEFAULT_OPTIONS, ...options });
|
return new Backups({ ...DEFAULT_OPTIONS, ...options });
|
||||||
}
|
}
|
||||||
set_options(options?: Partial<T.BackupOptions>) {
|
set_options(options?: Partial<T.BackupOptions>) {
|
||||||
@@ -78,7 +83,7 @@ export class Backups<M extends GenericManifest> {
|
|||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
addSets(...options: BackupSet[]) {
|
addSets(...options: BackupSet<keyof M["volumes"] & string>[]) {
|
||||||
options.forEach((x) =>
|
options.forEach((x) =>
|
||||||
this.backupSet.push({ ...x, options: { ...this.options, ...x.options } }),
|
this.backupSet.push({ ...x, options: { ...this.options, ...x.options } }),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { string } from "ts-matches";
|
import { string } from "ts-matches";
|
||||||
import { Backups } from ".";
|
import { Backups } from ".";
|
||||||
import { GenericManifest } from "../manifest/ManifestTypes";
|
import { GenericManifest } from "../manifest/ManifestTypes";
|
||||||
import { BackupOptions } from "../types";
|
import { BackupOptions, ExpectedExports } from "../types";
|
||||||
|
|
||||||
export type SetupBackupsParams<M extends GenericManifest> =
|
export type SetupBackupsParams<M extends GenericManifest> =
|
||||||
| [Partial<BackupOptions>, ...Array<keyof M["volumes"] & string>]
|
| [Partial<BackupOptions>, ...Array<keyof M["volumes"] & string>]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Config } from "./builder";
|
import { Config } from "./builder";
|
||||||
import { DeepPartial, Dependencies, Effects, ExpectedExports } from "../types";
|
import { DeepPartial, Dependencies, Effects, ExpectedExports } from "../types";
|
||||||
import { InputSpec } from "./configTypes";
|
import { InputSpec } from "./configTypes";
|
||||||
import { Utils, nullIfEmpty, utils } from "../util";
|
import { Utils, nullIfEmpty, once, utils } from "../util";
|
||||||
import { TypeFromProps } from "../util/propertiesMatcher";
|
import { TypeFromProps } from "../util/propertiesMatcher";
|
||||||
|
|
||||||
declare const dependencyProof: unique symbol;
|
declare const dependencyProof: unique symbol;
|
||||||
@@ -30,11 +30,11 @@ export function setupConfig<WD, A extends Config<InputSpec>>(
|
|||||||
write: Save<WD, TypeFromProps<A>>,
|
write: Save<WD, TypeFromProps<A>>,
|
||||||
read: Read<WD, TypeFromProps<A>>,
|
read: Read<WD, TypeFromProps<A>>,
|
||||||
) {
|
) {
|
||||||
const validator = spec.validator();
|
const validator = once(() => spec.validator());
|
||||||
return {
|
return {
|
||||||
setConfig: (async ({ effects, input }) => {
|
setConfig: (async ({ effects, input }) => {
|
||||||
if (!validator.test(input)) {
|
if (!validator().test(input)) {
|
||||||
await effects.error(String(validator.errorMessage(input)));
|
await effects.error(String(validator().errorMessage(input)));
|
||||||
return { error: "Set config type error for config" };
|
return { error: "Set config type error for config" };
|
||||||
}
|
}
|
||||||
await write({
|
await write({
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ describe("EmVer", () => {
|
|||||||
expect(checker.check("1.2.3.4")).toEqual(true);
|
expect(checker.check("1.2.3.4")).toEqual(true);
|
||||||
});
|
});
|
||||||
test("rangeOf('*') invalid", () => {
|
test("rangeOf('*') invalid", () => {
|
||||||
|
// @ts-expect-error
|
||||||
expect(() => checker.check("a")).toThrow();
|
expect(() => checker.check("a")).toThrow();
|
||||||
|
// @ts-expect-error
|
||||||
expect(() => checker.check("")).toThrow();
|
expect(() => checker.check("")).toThrow();
|
||||||
expect(() => checker.check("1..3")).toThrow();
|
expect(() => checker.check("1..3")).toThrow();
|
||||||
});
|
});
|
||||||
@@ -18,6 +20,7 @@ describe("EmVer", () => {
|
|||||||
{
|
{
|
||||||
const checker = rangeOf(">1.2.3.4");
|
const checker = rangeOf(">1.2.3.4");
|
||||||
test(`rangeOf(">1.2.3.4") valid`, () => {
|
test(`rangeOf(">1.2.3.4") valid`, () => {
|
||||||
|
expect(checker.check("2-beta123")).toEqual(true);
|
||||||
expect(checker.check("2")).toEqual(true);
|
expect(checker.check("2")).toEqual(true);
|
||||||
expect(checker.check("1.2.3.5")).toEqual(true);
|
expect(checker.check("1.2.3.5")).toEqual(true);
|
||||||
expect(checker.check("1.2.3.4.1")).toEqual(true);
|
expect(checker.check("1.2.3.4.1")).toEqual(true);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import * as matches from "ts-matches";
|
import * as matches from "ts-matches";
|
||||||
|
|
||||||
const starSub = /((\d+\.)*\d+)\.\*/;
|
const starSub = /((\d+\.)*\d+)\.\*/;
|
||||||
|
// prettier-ignore
|
||||||
|
export type ValidEmVer = `${'>' | '<' | '>=' | '<=' | '=' | ''}${number | '*'}${`.${number | '*'}` | ""}${`.${number | '*'}` | ""}${`.${number | '*'}` | ""}${`-${string}` | ""}`;
|
||||||
|
|
||||||
function incrementLastNumber(list: number[]) {
|
function incrementLastNumber(list: number[]) {
|
||||||
const newList = [...list];
|
const newList = [...list];
|
||||||
@@ -61,7 +63,7 @@ export class EmVer {
|
|||||||
* Or an already made emver
|
* Or an already made emver
|
||||||
* IsUnsafe
|
* IsUnsafe
|
||||||
*/
|
*/
|
||||||
static from(range: string | EmVer): EmVer {
|
static from(range: ValidEmVer | EmVer): EmVer {
|
||||||
if (range instanceof EmVer) {
|
if (range instanceof EmVer) {
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
@@ -71,22 +73,26 @@ export class EmVer {
|
|||||||
* Convert the range, should be 1.2.* or * into a emver
|
* Convert the range, should be 1.2.* or * into a emver
|
||||||
* IsUnsafe
|
* IsUnsafe
|
||||||
*/
|
*/
|
||||||
static parse(range: string): EmVer {
|
static parse(rangeExtra: string): EmVer {
|
||||||
|
const [range, extra] = rangeExtra.split("-");
|
||||||
const values = range.split(".").map((x) => parseInt(x));
|
const values = range.split(".").map((x) => parseInt(x));
|
||||||
for (const value of values) {
|
for (const value of values) {
|
||||||
if (isNaN(value)) {
|
if (isNaN(value)) {
|
||||||
throw new Error(`Couldn't parse range: ${range}`);
|
throw new Error(`Couldn't parse range: ${range}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new EmVer(values);
|
return new EmVer(values, extra);
|
||||||
}
|
}
|
||||||
private constructor(public readonly values: number[]) {}
|
private constructor(
|
||||||
|
public readonly values: number[],
|
||||||
|
readonly extra: string | null,
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when we need a new emver that has the last number incremented, used in the 1.* like things
|
* Used when we need a new emver that has the last number incremented, used in the 1.* like things
|
||||||
*/
|
*/
|
||||||
public withLastIncremented() {
|
public withLastIncremented() {
|
||||||
return new EmVer(incrementLastNumber(this.values));
|
return new EmVer(incrementLastNumber(this.values), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public greaterThan(other: EmVer): boolean {
|
public greaterThan(other: EmVer): boolean {
|
||||||
@@ -153,6 +159,10 @@ export class EmVer {
|
|||||||
.when("less", () => -1 as const)
|
.when("less", () => -1 as const)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return `${this.values.join(".")}${this.extra ? `-${this.extra}` : ""}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,7 +258,7 @@ export class Checker {
|
|||||||
* Check is the function that will be given a emver or unparsed emver and should give if it follows
|
* Check is the function that will be given a emver or unparsed emver and should give if it follows
|
||||||
* a pattern
|
* a pattern
|
||||||
*/
|
*/
|
||||||
public readonly check: (value: string | EmVer) => boolean,
|
public readonly check: (value: ValidEmVer | EmVer) => boolean,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
import { ExpectedExports } from "../types";
|
|
||||||
|
|
||||||
declare const ActionProof: unique symbol;
|
|
||||||
export type ActionReceipt = {
|
|
||||||
[ActionProof]: never;
|
|
||||||
};
|
|
||||||
export function noActions(): ActionReceipt {
|
|
||||||
return {} as ActionReceipt;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare const MigrationProof: unique symbol;
|
|
||||||
export type MigrationReceipt = {
|
|
||||||
[MigrationProof]: never;
|
|
||||||
};
|
|
||||||
export function noMigrationsUp(): MigrationReceipt {
|
|
||||||
return {} as MigrationReceipt;
|
|
||||||
}
|
|
||||||
export function migrationUp(fn: () => Promise<unknown>): MigrationReceipt {
|
|
||||||
fn();
|
|
||||||
return {} as MigrationReceipt;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare const MigrationDownProof: unique symbol;
|
|
||||||
export type MigrationDownReceipt = {
|
|
||||||
[MigrationDownProof]: never;
|
|
||||||
};
|
|
||||||
export function noMigrationsDown(): MigrationDownReceipt {
|
|
||||||
return {} as MigrationDownReceipt;
|
|
||||||
}
|
|
||||||
export function migrationDown(
|
|
||||||
fn: () => Promise<unknown>,
|
|
||||||
): MigrationDownReceipt {
|
|
||||||
fn();
|
|
||||||
return {} as MigrationDownReceipt;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setupInit(
|
|
||||||
fn: (
|
|
||||||
...args: Parameters<ExpectedExports.init>
|
|
||||||
) => Promise<[MigrationReceipt, ActionReceipt]>,
|
|
||||||
) {
|
|
||||||
const initFn: ExpectedExports.init = (...args) => fn(...args);
|
|
||||||
return initFn;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setupUninit(
|
|
||||||
fn: (
|
|
||||||
...args: Parameters<ExpectedExports.uninit>
|
|
||||||
) => Promise<[MigrationDownReceipt]>,
|
|
||||||
) {
|
|
||||||
const uninitFn: ExpectedExports.uninit = (...args) => fn(...args);
|
|
||||||
return uninitFn;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Effects, ExpectedExports } from "../types";
|
import { Effects, ExpectedExports } from "../types";
|
||||||
|
import { Utils, utils } from "../util";
|
||||||
import { Daemons } from "./Daemons";
|
import { Daemons } from "./Daemons";
|
||||||
export * as network from "./exportInterfaces";
|
export * as network from "./exportInterfaces";
|
||||||
export { LocalBinding } from "./LocalBinding";
|
export { LocalBinding } from "./LocalBinding";
|
||||||
@@ -21,14 +22,18 @@ export { Daemons } from "./Daemons";
|
|||||||
* @param fn
|
* @param fn
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const runningMain: (
|
export const setupMain = <WrapperData>(
|
||||||
fn: (o: {
|
fn: (o: {
|
||||||
effects: Effects;
|
effects: Effects;
|
||||||
started(onTerm: () => void): null;
|
started(onTerm: () => void): null;
|
||||||
|
utils: Utils<WrapperData>;
|
||||||
}) => Promise<Daemons<any>>,
|
}) => Promise<Daemons<any>>,
|
||||||
) => ExpectedExports.main = (fn) => {
|
): ExpectedExports.main => {
|
||||||
return async (options) => {
|
return async (options) => {
|
||||||
const result = await fn(options);
|
const result = await fn({
|
||||||
|
...options,
|
||||||
|
utils: utils<WrapperData>(options.effects),
|
||||||
|
});
|
||||||
await result.build().then((x) => x.wait());
|
await result.build().then((x) => x.wait());
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ValidEmVer } from "../emverLite/mod";
|
||||||
|
|
||||||
export interface Container {
|
export interface Container {
|
||||||
image: string;
|
image: string;
|
||||||
mounts: Record<string, string>;
|
mounts: Record<string, string>;
|
||||||
@@ -5,10 +7,12 @@ export interface Container {
|
|||||||
sigtermTimeout?: string; // if more than 30s to shutdown
|
sigtermTimeout?: string; // if more than 30s to shutdown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ManifestVersion = ValidEmVer;
|
||||||
|
|
||||||
export interface GenericManifest {
|
export interface GenericManifest {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
version: string;
|
version: ManifestVersion;
|
||||||
releaseNotes: string;
|
releaseNotes: string;
|
||||||
license: string; // name of license
|
license: string; // name of license
|
||||||
replaces: string[];
|
replaces: string[];
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { GenericManifest } from "./ManifestTypes";
|
import { GenericManifest, ManifestVersion } from "./ManifestTypes";
|
||||||
|
|
||||||
export function setupManifest<
|
export function setupManifest<
|
||||||
M extends GenericManifest & { id: Id },
|
M extends GenericManifest & { id: Id; version: Version },
|
||||||
Id extends string,
|
Id extends string,
|
||||||
|
Version extends ManifestVersion,
|
||||||
>(manifest: M): M {
|
>(manifest: M): M {
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
|||||||
28
lib/migrations/Migration.ts
Normal file
28
lib/migrations/Migration.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { ManifestVersion } from "../manifest/ManifestTypes";
|
||||||
|
import { Effects } from "../types";
|
||||||
|
import { Utils } from "../util";
|
||||||
|
|
||||||
|
export class Migration<Version extends ManifestVersion> {
|
||||||
|
constructor(
|
||||||
|
readonly options: {
|
||||||
|
version: Version;
|
||||||
|
up: (opts: { effects: Effects }) => Promise<void>;
|
||||||
|
down: (opts: { effects: Effects }) => Promise<void>;
|
||||||
|
},
|
||||||
|
) {}
|
||||||
|
static of<Version extends ManifestVersion>(options: {
|
||||||
|
version: Version;
|
||||||
|
up: (opts: { effects: Effects }) => Promise<void>;
|
||||||
|
down: (opts: { effects: Effects }) => Promise<void>;
|
||||||
|
}) {
|
||||||
|
return new Migration(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
async up(opts: { effects: Effects }) {
|
||||||
|
this.up(opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(opts: { effects: Effects }) {
|
||||||
|
this.down(opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
52
lib/migrations/setupMigrations.ts
Normal file
52
lib/migrations/setupMigrations.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { setupActions } from "../actions/setupActions";
|
||||||
|
import { EmVer } from "../emverLite/mod";
|
||||||
|
import { GenericManifest } from "../manifest/ManifestTypes";
|
||||||
|
import { ExpectedExports } from "../types";
|
||||||
|
import { once } from "../util/once";
|
||||||
|
import { Migration } from "./Migration";
|
||||||
|
|
||||||
|
export function setupMigrations<Migrations extends Array<Migration<any>>>(
|
||||||
|
manifest: GenericManifest,
|
||||||
|
initializeActions: ReturnType<typeof setupActions>["initializeActions"],
|
||||||
|
...migrations: EnsureUniqueId<Migrations>
|
||||||
|
) {
|
||||||
|
const sortedMigrations = once(() => {
|
||||||
|
const migrationsAsVersions = (migrations as Array<Migration<any>>).map(
|
||||||
|
(x) => [EmVer.parse(x.options.version), x] as const,
|
||||||
|
);
|
||||||
|
migrationsAsVersions.sort((a, b) => a[0].compareForSort(b[0]));
|
||||||
|
return migrationsAsVersions;
|
||||||
|
});
|
||||||
|
const currentVersion = once(() => EmVer.parse(manifest.version));
|
||||||
|
const init: ExpectedExports.init = async ({ effects, previousVersion }) => {
|
||||||
|
await initializeActions(effects);
|
||||||
|
if (!!previousVersion) {
|
||||||
|
const previousVersionEmVer = EmVer.parse(previousVersion);
|
||||||
|
for (const [_, migration] of sortedMigrations()
|
||||||
|
.filter((x) => x[0].greaterThan(previousVersionEmVer))
|
||||||
|
.filter((x) => x[0].lessThanOrEqual(currentVersion()))) {
|
||||||
|
await migration.up({ effects });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const uninit: ExpectedExports.uninit = async ({ effects, nextVersion }) => {
|
||||||
|
if (!!nextVersion) {
|
||||||
|
const nextVersionEmVer = EmVer.parse(nextVersion);
|
||||||
|
const reversed = [...sortedMigrations()].reverse();
|
||||||
|
for (const [_, migration] of reversed
|
||||||
|
.filter((x) => x[0].greaterThan(nextVersionEmVer))
|
||||||
|
.filter((x) => x[0].lessThanOrEqual(currentVersion()))) {
|
||||||
|
await migration.down({ effects });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return { init, uninit };
|
||||||
|
}
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
export type EnsureUniqueId<A, B = A, ids = never> =
|
||||||
|
B extends [] ? A :
|
||||||
|
B extends [Migration<infer id>, ...infer Rest] ? (
|
||||||
|
id extends ids ? "One of the ids are not unique"[] :
|
||||||
|
EnsureUniqueId<A, Rest, id | ids>
|
||||||
|
) : "There exists a migration that is not a Migration"[]
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ExpectedExports, Properties } from "../types";
|
import { ExpectedExports, Properties } from "../types";
|
||||||
|
import { Utils, utils } from "../util";
|
||||||
import "../util/extensions";
|
import "../util/extensions";
|
||||||
import { PropertyGroup } from "./PropertyGroup";
|
import { PropertyGroup } from "./PropertyGroup";
|
||||||
import { PropertyString } from "./PropertyString";
|
import { PropertyString } from "./PropertyString";
|
||||||
@@ -18,13 +19,17 @@ export type UnionToIntersection<T> = ((x: T) => any) extends (x: infer R) => any
|
|||||||
* @param fn
|
* @param fn
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function setupPropertiesExport(
|
export function setupProperties<WrapperData>(
|
||||||
fn: (
|
fn: (args: {
|
||||||
...args: Parameters<ExpectedExports.properties>
|
wrapperData: WrapperData;
|
||||||
) => void | Promise<void> | Promise<(PropertyGroup | PropertyString)[]>,
|
}) => void | Promise<void> | Promise<(PropertyGroup | PropertyString)[]>,
|
||||||
): ExpectedExports.properties {
|
): ExpectedExports.properties {
|
||||||
return (async (...args) => {
|
return (async (options) => {
|
||||||
const result = await fn(...args);
|
const result = await fn(
|
||||||
|
options as {
|
||||||
|
wrapperData: WrapperData & typeof options.wrapperData;
|
||||||
|
},
|
||||||
|
);
|
||||||
if (result) {
|
if (result) {
|
||||||
const answer: Properties = result.map((x) => x.data);
|
const answer: Properties = result.map((x) => x.data);
|
||||||
return answer;
|
return answer;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
export * as configTypes from "./config/configTypes";
|
export * as configTypes from "./config/configTypes";
|
||||||
import { InputSpec } from "./config/configTypes";
|
import { InputSpec } from "./config/configTypes";
|
||||||
import { DependenciesReceipt } from "./config/setupConfig";
|
import { DependenciesReceipt } from "./config/setupConfig";
|
||||||
import { ActionReceipt } from "./init";
|
|
||||||
|
|
||||||
export type ExportedAction = (options: {
|
export type ExportedAction = (options: {
|
||||||
effects: Effects;
|
effects: Effects;
|
||||||
@@ -350,7 +349,7 @@ export type Effects = {
|
|||||||
*
|
*
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
exportAction(options: ActionMetaData): Promise<void & ActionReceipt>;
|
exportAction(options: ActionMetaData): Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Remove an action that was exported. Used problably during main or during setConfig.
|
* Remove an action that was exported. Used problably during main or during setConfig.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export { FileHelper } from "./fileHelper";
|
|||||||
export { getWrapperData } from "./getWrapperData";
|
export { getWrapperData } from "./getWrapperData";
|
||||||
export { deepEqual } from "./deepEqual";
|
export { deepEqual } from "./deepEqual";
|
||||||
export { deepMerge } from "./deepMerge";
|
export { deepMerge } from "./deepMerge";
|
||||||
|
export { once } from "./once";
|
||||||
|
|
||||||
/** Used to check if the file exists before hand */
|
/** Used to check if the file exists before hand */
|
||||||
export const exists = (
|
export const exists = (
|
||||||
|
|||||||
9
lib/util/once.ts
Normal file
9
lib/util/once.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function once<B>(fn: () => B): () => B {
|
||||||
|
let result: [B] | [] = [];
|
||||||
|
return () => {
|
||||||
|
if (!result.length) {
|
||||||
|
result = [fn()];
|
||||||
|
}
|
||||||
|
return result[0];
|
||||||
|
};
|
||||||
|
}
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "start-sdk",
|
"name": "start-sdk",
|
||||||
"version": "0.4.0-lib0.charlie33",
|
"version": "0.4.0-lib0.charlie34",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "start-sdk",
|
"name": "start-sdk",
|
||||||
"version": "0.4.0-lib0.charlie33",
|
"version": "0.4.0-lib0.charlie34",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iarna/toml": "^2.2.5",
|
"@iarna/toml": "^2.2.5",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "start-sdk",
|
"name": "start-sdk",
|
||||||
"version": "0.4.0-lib0.charlie33",
|
"version": "0.4.0-lib0.charlie34",
|
||||||
"description": "For making the patterns that are wanted in making services for the startOS.",
|
"description": "For making the patterns that are wanted in making services for the startOS.",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
|
|||||||
Reference in New Issue
Block a user