declastruct 1.2.0 → 1.3.1
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/domain.objects/ContextDeclastruct.d.ts +1 -1
- package/dist/domain.objects/DeclastructChange.d.ts +1 -1
- package/dist/domain.objects/DeclastructChange.js.map +1 -1
- package/dist/domain.objects/DeclastructDao.d.ts +2 -2
- package/dist/domain.objects/DeclastructPlan.d.ts +2 -2
- package/dist/domain.objects/DeclastructProvider.d.ts +1 -1
- package/dist/domain.operations/apply/applyChanges.js +8 -3
- package/dist/domain.operations/apply/applyChanges.js.map +1 -1
- package/dist/domain.operations/plan/computeChange.js +2 -28
- package/dist/domain.operations/plan/computeChange.js.map +1 -1
- package/dist/domain.operations/plan/getDisplayableDiff.d.ts +10 -0
- package/dist/domain.operations/plan/getDisplayableDiff.js +40 -0
- package/dist/domain.operations/plan/getDisplayableDiff.js.map +1 -0
- package/dist/infra/asIsoTimestamp.d.ts +1 -1
- package/license.md +21 -0
- package/package.json +19 -9
- package/readme.md +52 -32
- package/dist/.test/assets/providers/demo.provider.d.ts +0 -32
- package/dist/.test/assets/providers/demo.provider.js +0 -101
- package/dist/.test/assets/providers/demo.provider.js.map +0 -1
- package/dist/contract/cli/apply.integration.test.d.ts +0 -1
- package/dist/contract/cli/apply.integration.test.js +0 -215
- package/dist/contract/cli/apply.integration.test.js.map +0 -1
- package/dist/contract/cli/plan.integration.test.d.ts +0 -1
- package/dist/contract/cli/plan.integration.test.js +0 -142
- package/dist/contract/cli/plan.integration.test.js.map +0 -1
- package/dist/domain.objects/ContextDeclastruct.test.d.ts +0 -1
- package/dist/domain.objects/ContextDeclastruct.test.js +0 -41
- package/dist/domain.objects/ContextDeclastruct.test.js.map +0 -1
- package/dist/domain.objects/DeclastructChange.test.d.ts +0 -1
- package/dist/domain.objects/DeclastructChange.test.js +0 -59
- package/dist/domain.objects/DeclastructChange.test.js.map +0 -1
- package/dist/domain.objects/DeclastructDao.test.d.ts +0 -1
- package/dist/domain.objects/DeclastructDao.test.js +0 -78
- package/dist/domain.objects/DeclastructDao.test.js.map +0 -1
- package/dist/domain.objects/DeclastructPlan.test.d.ts +0 -1
- package/dist/domain.objects/DeclastructPlan.test.js +0 -31
- package/dist/domain.objects/DeclastructPlan.test.js.map +0 -1
- package/dist/domain.objects/DeclastructProvider.test.d.ts +0 -1
- package/dist/domain.objects/DeclastructProvider.test.js +0 -80
- package/dist/domain.objects/DeclastructProvider.test.js.map +0 -1
- package/dist/domain.objects/IsoTimestamp.test.d.ts +0 -1
- package/dist/domain.objects/IsoTimestamp.test.js +0 -10
- package/dist/domain.objects/IsoTimestamp.test.js.map +0 -1
- package/dist/domain.operations/apply/applyChange.test.d.ts +0 -1
- package/dist/domain.operations/apply/applyChange.test.js +0 -241
- package/dist/domain.operations/apply/applyChange.test.js.map +0 -1
- package/dist/domain.operations/apply/applyChanges.integration.test.d.ts +0 -1
- package/dist/domain.operations/apply/applyChanges.integration.test.js +0 -291
- package/dist/domain.operations/apply/applyChanges.integration.test.js.map +0 -1
- package/dist/domain.operations/plan/computeChange.test.d.ts +0 -1
- package/dist/domain.operations/plan/computeChange.test.js +0 -153
- package/dist/domain.operations/plan/computeChange.test.js.map +0 -1
- package/dist/domain.operations/plan/getDaoByResource.test.d.ts +0 -1
- package/dist/domain.operations/plan/getDaoByResource.test.js +0 -101
- package/dist/domain.operations/plan/getDaoByResource.test.js.map +0 -1
- package/dist/domain.operations/plan/planChanges.integration.test.d.ts +0 -1
- package/dist/domain.operations/plan/planChanges.integration.test.js +0 -200
- package/dist/domain.operations/plan/planChanges.integration.test.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeclastructChange.js","sourceRoot":"","sources":["../../src/domain.objects/DeclastructChange.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"DeclastructChange.js","sourceRoot":"","sources":["../../src/domain.objects/DeclastructChange.ts"],"names":[],"mappings":";;;AAAA,mDAAkE;AAElE;;;GAGG;AACH,IAAY,uBAyBX;AAzBD,WAAY,uBAAuB;IACjC;;OAEG;IACH,wCAAa,CAAA;IAEb;;OAEG;IACH,4CAAiB,CAAA;IAEjB;;OAEG;IACH,4CAAiB,CAAA;IAEjB;;OAEG;IACH,8CAAmB,CAAA;IAEnB;;OAEG;IACH,8CAAmB,CAAA;AACrB,CAAC,EAzBW,uBAAuB,uCAAvB,uBAAuB,QAyBlC;AAsDD,MAAa,iBAGX,SAAQ,8BAA2C;CACT;AAJ5C,8CAI4C"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DomainEntity, DomainLiteral, Ref, Refable, RefByPrimary, RefByUnique } from 'domain-objects';
|
|
2
|
-
import { HasMetadata } from 'type-fns';
|
|
1
|
+
import { type DomainEntity, DomainLiteral, type Ref, type Refable, type RefByPrimary, type RefByUnique } from 'domain-objects';
|
|
2
|
+
import { type HasMetadata } from 'type-fns';
|
|
3
3
|
/**
|
|
4
4
|
* .what = standardized data access interface for any resource type
|
|
5
5
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DomainEntity } from 'domain-objects';
|
|
2
|
-
import { DeclastructChange } from './DeclastructChange';
|
|
3
|
-
import { IsoTimestamp } from './IsoTimestamp';
|
|
2
|
+
import { type DeclastructChange } from './DeclastructChange';
|
|
3
|
+
import { type IsoTimestamp } from './IsoTimestamp';
|
|
4
4
|
/**
|
|
5
5
|
* .what = collection of all planned changes required to fulfill a wish
|
|
6
6
|
* .why = enables review, version control, and validation of infrastructure changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DomainLiteral } from 'domain-objects';
|
|
2
|
-
import { DeclastructDao } from './DeclastructDao';
|
|
2
|
+
import { type DeclastructDao } from './DeclastructDao';
|
|
3
3
|
export type DeclastructDaosShape<TContext> = Record<string, DeclastructDao<any, any, TContext>>;
|
|
4
4
|
/**
|
|
5
5
|
* .what = bundles all DAOs and lifecycle hooks for a specific infrastructure provider
|
|
@@ -52,14 +52,19 @@ const applyChanges = async (input, context) => {
|
|
|
52
52
|
const resourceFound = input.resources.find((candidate) => candidate.constructor.name === change.forResource.class &&
|
|
53
53
|
(0, domain_objects_1.getUniqueIdentifierSlug)(candidate) === change.forResource.slug) ??
|
|
54
54
|
helpful_errors_1.UnexpectedCodePathError.throw('could not find resource specified in plan. was it removed?', { change });
|
|
55
|
-
//
|
|
55
|
+
// log action start
|
|
56
|
+
context.log.info(`○ [${change.action}] ${change.forResource.slug}`, {});
|
|
57
|
+
// apply the change with timing
|
|
58
|
+
const startMs = Date.now();
|
|
56
59
|
const applied = await (0, applyChange_1.applyChange)({
|
|
57
60
|
change,
|
|
58
61
|
resource: resourceFound,
|
|
59
62
|
providers: input.providers,
|
|
60
63
|
});
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
const durationMs = Date.now() - startMs;
|
|
65
|
+
// log completion with duration
|
|
66
|
+
const durationSec = (durationMs / 1000).toFixed(2);
|
|
67
|
+
context.log.info(` └─ ✔ done in ${durationSec}s`, {});
|
|
63
68
|
appliedChanges.push(applied);
|
|
64
69
|
}
|
|
65
70
|
return { appliedChanges };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/apply/applyChanges.ts"],"names":[],"mappings":";;;AAAA,mDAAuE;AACvE,mDAAyD;AAIzD,8EAGgD;AAGhD,qDAAkD;AAClD,+CAAwD;AACxD,+CAA4C;AAE5C;;;;;;GAMG;AACI,MAAM,YAAY,GAAG,KAAK,EAC/B,KAIC,EACD,OAA6C,EACK,EAAE;IACpD,8BAA8B;IAC9B,MAAM,WAAW,GAAG,MAAM,IAAA,yBAAW,EACnC;QACE,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,YAAY,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,WAAW;KAClD,EACD,OAAO,CACR,CAAC;IAEF,iFAAiF;IACjF,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,IAAA,+BAAoB,EAAC;YACnB,YAAY,EAAE,KAAK,CAAC,IAAI;YACxB,WAAW;SACZ,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;IACpD,CAAC;IAED,oDAAoD;IACpD,MAAM,WAAW,GAAG,WAAW,CAAC;IAEhC,yBAAyB;IACzB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAErB,2CAA2C;IAC3C,MAAM,cAAc,GAAwB,EAAE,CAAC;IAE/C,KAAK,MAAM,MAAM,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;QACzC,4BAA4B;QAC5B,IAAI,MAAM,CAAC,MAAM,KAAK,2CAAuB,CAAC,IAAI,EAAE,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5D,SAAS;QACX,CAAC;QAED,4BAA4B;QAC5B,MAAM,aAAa,GACjB,KAAK,CAAC,SAAS,CAAC,IAAI,CAClB,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,CAAC,WAAW,CAAC,IAAI,KAAK,MAAM,CAAC,WAAW,CAAC,KAAK;YACvD,IAAA,wCAAuB,EAAC,SAAS,CAAC,KAAK,MAAM,CAAC,WAAW,CAAC,IAAI,CACjE;YACD,wCAAuB,CAAC,KAAK,CAC3B,4DAA4D,EAC5D,EAAE,MAAM,EAAE,CACX,CAAC;QAEJ,mBAAmB;QACnB,MAAM,OAAO,GAAG,MAAM,IAAA,yBAAW,EAAC;YAChC,MAAM;YACN,QAAQ,EAAE,aAAa;YACvB,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"applyChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/apply/applyChanges.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.computeChange = void 0;
|
|
4
4
|
const domain_objects_1 = require("domain-objects");
|
|
5
5
|
const helpful_errors_1 = require("helpful-errors");
|
|
6
|
-
const jest_diff_1 = require("jest-diff");
|
|
7
6
|
const DeclastructChange_1 = require("../../domain.objects/DeclastructChange");
|
|
7
|
+
const getDisplayableDiff_1 = require("./getDisplayableDiff");
|
|
8
8
|
/**
|
|
9
9
|
* .what = checks if two resources are equivalent
|
|
10
10
|
* .why = determines whether a resource needs to be updated
|
|
@@ -16,32 +16,6 @@ const checkAreResourcesEquivalent = (input) => {
|
|
|
16
16
|
const desiredSerialized = (0, domain_objects_1.serialize)((0, domain_objects_1.omitReadonly)(input.desired));
|
|
17
17
|
return remoteSerialized === desiredSerialized;
|
|
18
18
|
};
|
|
19
|
-
/**
|
|
20
|
-
* .what = computes human-readable diff between two resources
|
|
21
|
-
* .why = helps users understand what will change
|
|
22
|
-
* .note = returns null if resources are identical; for CREATE uses empty object to show all attributes; ignores readonly
|
|
23
|
-
*/
|
|
24
|
-
const computeDiff = ({ from, into, }) => {
|
|
25
|
-
// no diff if both are null
|
|
26
|
-
if (from === null && into === null)
|
|
27
|
-
return null;
|
|
28
|
-
// check if resources are equivalent after omitting readonly
|
|
29
|
-
if (from !== null && into !== null) {
|
|
30
|
-
const fromSerialized = (0, domain_objects_1.serialize)((0, domain_objects_1.omitReadonly)(from));
|
|
31
|
-
const intoSerialized = (0, domain_objects_1.serialize)((0, domain_objects_1.omitReadonly)(into));
|
|
32
|
-
if (fromSerialized === intoSerialized)
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
// omit readonly before diff
|
|
36
|
-
const fromWithoutReadonly = from === null ? {} : (0, domain_objects_1.omitReadonly)(from);
|
|
37
|
-
const intoWithoutReadonly = into === null ? {} : (0, domain_objects_1.omitReadonly)(into);
|
|
38
|
-
// compute diff using jest-diff
|
|
39
|
-
const difference = (0, jest_diff_1.diff)(fromWithoutReadonly, intoWithoutReadonly, {
|
|
40
|
-
aAnnotation: 'Remote',
|
|
41
|
-
bAnnotation: 'Desired',
|
|
42
|
-
});
|
|
43
|
-
return difference;
|
|
44
|
-
};
|
|
45
19
|
/**
|
|
46
20
|
* .what = computes a single change by comparing desired vs remote state
|
|
47
21
|
* .why = determines the action needed to achieve desired state for one resource
|
|
@@ -75,7 +49,7 @@ const computeChange = ({ desired, remote, }) => {
|
|
|
75
49
|
// compute displayable difference
|
|
76
50
|
const difference = action === DeclastructChange_1.DeclastructChangeAction.KEEP
|
|
77
51
|
? null
|
|
78
|
-
:
|
|
52
|
+
: (0, getDisplayableDiff_1.getDisplayableDiff)({ from: remote, into: desired });
|
|
79
53
|
// get resource info for change record
|
|
80
54
|
const resourceForChange = desired || remote;
|
|
81
55
|
// return change
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computeChange.js","sourceRoot":"","sources":["../../../src/domain.operations/plan/computeChange.ts"],"names":[],"mappings":";;;AAAA,mDAKwB;AACxB,mDAAyD;
|
|
1
|
+
{"version":3,"file":"computeChange.js","sourceRoot":"","sources":["../../../src/domain.operations/plan/computeChange.ts"],"names":[],"mappings":";;;AAAA,mDAKwB;AACxB,mDAAyD;AAEzD,8EAGgD;AAChD,6DAA0D;AAE1D;;;;GAIG;AACH,MAAM,2BAA2B,GAAG,CAAC,KAGpC,EAAW,EAAE;IACZ,0EAA0E;IAC1E,MAAM,gBAAgB,GAAG,IAAA,0BAAS,EAAC,IAAA,6BAAY,EAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,MAAM,iBAAiB,GAAG,IAAA,0BAAS,EAAC,IAAA,6BAAY,EAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAEjE,OAAO,gBAAgB,KAAK,iBAAiB,CAAC;AAChD,CAAC,CAAC;AAEF;;;;GAIG;AACI,MAAM,aAAa,GAAG,CAAC,EAC5B,OAAO,EACP,MAAM,GAIP,EAAqB,EAAE;IACtB,6CAA6C;IAC7C,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE;QACnB,kCAAkC;QAClC,IAAI,CAAC,MAAM;YAAE,OAAO,2CAAuB,CAAC,MAAM,CAAC;QAEnD,wCAAwC;QACxC,IAAI,CAAC,OAAO;YAAE,OAAO,2CAAuB,CAAC,OAAO,CAAC;QAErD,oBAAoB;QACpB,MAAM,sBAAsB,GAAG,wCAAuB,CAAC,IAAI,CACzD,GAAG,EAAE,CAAC,2BAA2B,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EACtD;YACE,OAAO,EAAE,uCAAuC;YAChD,QAAQ,EAAE;gBACR,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;gBAC1B,KAAK,EAAE;oBACL,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI;oBAClC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI;iBACjC;aACF;SACF,CACF,EAAE,CAAC;QACJ,IAAI,sBAAsB;YAAE,OAAO,2CAAuB,CAAC,IAAI,CAAC;QAEhE,qCAAqC;QACrC,OAAO,2CAAuB,CAAC,MAAM,CAAC;IACxC,CAAC,CAAC,EAAE,CAAC;IAEL,iCAAiC;IACjC,MAAM,UAAU,GACd,MAAM,KAAK,2CAAuB,CAAC,IAAI;QACrC,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,IAAA,uCAAkB,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAE1D,sCAAsC;IACtC,MAAM,iBAAiB,GAAG,OAAO,IAAI,MAAO,CAAC;IAE7C,gBAAgB;IAChB,OAAO,IAAI,qCAAiB,CAAC;QAC3B,WAAW,EAAE;YACX,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,IAAI;YACzC,IAAI,EAAE,wCAAuB,CAAC,IAAI,CAChC,GAAG,EAAE,CAAC,IAAA,wCAAuB,EAAC,iBAAiB,CAAC,EAChD;gBACE,OAAO,EAAE,mCAAmC;gBAC5C,QAAQ,EAAE;oBACR,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;oBAC1B,KAAK,EAAE;wBACL,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI;wBAClC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI;qBACjC;iBACF;aACF,CACF,EAAE;SACJ;QACD,MAAM;QACN,KAAK,EAAE;YACL,OAAO;YACP,MAAM;YACN,UAAU;SACX;KACF,CAAC,CAAC;AACL,CAAC,CAAC;AArEW,QAAA,aAAa,iBAqExB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DomainEntity } from 'domain-objects';
|
|
2
|
+
/**
|
|
3
|
+
* .what = computes human-readable diff between two resources
|
|
4
|
+
* .why = helps users understand what will change
|
|
5
|
+
* .note = returns null if resources are identical; for CREATE uses empty object to show all attributes; ignores readonly; preserves key order from into
|
|
6
|
+
*/
|
|
7
|
+
export declare const getDisplayableDiff: ({ from, into, }: {
|
|
8
|
+
from: DomainEntity<any> | null;
|
|
9
|
+
into: DomainEntity<any> | null;
|
|
10
|
+
}) => string | null;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDisplayableDiff = void 0;
|
|
4
|
+
const domain_objects_1 = require("domain-objects");
|
|
5
|
+
const jest_diff_1 = require("jest-diff");
|
|
6
|
+
/**
|
|
7
|
+
* .what = computes human-readable diff between two resources
|
|
8
|
+
* .why = helps users understand what will change
|
|
9
|
+
* .note = returns null if resources are identical; for CREATE uses empty object to show all attributes; ignores readonly; preserves key order from into
|
|
10
|
+
*/
|
|
11
|
+
const getDisplayableDiff = ({ from, into, }) => {
|
|
12
|
+
// no diff if both are null
|
|
13
|
+
if (from === null && into === null)
|
|
14
|
+
return null;
|
|
15
|
+
// check if resources are equivalent after omitting readonly
|
|
16
|
+
if (from !== null && into !== null) {
|
|
17
|
+
const fromSerialized = (0, domain_objects_1.serialize)((0, domain_objects_1.omitReadonly)(from));
|
|
18
|
+
const intoSerialized = (0, domain_objects_1.serialize)((0, domain_objects_1.omitReadonly)(into));
|
|
19
|
+
if (fromSerialized === intoSerialized)
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
// omit readonly before diff
|
|
23
|
+
const fromWithoutReadonly = from === null ? {} : (0, domain_objects_1.omitReadonly)(from);
|
|
24
|
+
const intoWithoutReadonly = into === null ? {} : (0, domain_objects_1.omitReadonly)(into);
|
|
25
|
+
// build key order from into (desired) for stable diff output
|
|
26
|
+
const keyOrder = Object.keys(intoWithoutReadonly);
|
|
27
|
+
// compute diff using jest-diff, sorting keys by into's order
|
|
28
|
+
const difference = (0, jest_diff_1.diff)(fromWithoutReadonly, intoWithoutReadonly, {
|
|
29
|
+
aAnnotation: 'Remote',
|
|
30
|
+
bAnnotation: 'Desired',
|
|
31
|
+
compareKeys: (a, b) => {
|
|
32
|
+
const aIdx = keyOrder.indexOf(a);
|
|
33
|
+
const bIdx = keyOrder.indexOf(b);
|
|
34
|
+
return (aIdx === -1 ? Infinity : aIdx) - (bIdx === -1 ? Infinity : bIdx);
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
return difference;
|
|
38
|
+
};
|
|
39
|
+
exports.getDisplayableDiff = getDisplayableDiff;
|
|
40
|
+
//# sourceMappingURL=getDisplayableDiff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getDisplayableDiff.js","sourceRoot":"","sources":["../../../src/domain.operations/plan/getDisplayableDiff.ts"],"names":[],"mappings":";;;AAAA,mDAAuE;AACvE,yCAAiC;AAEjC;;;;GAIG;AACI,MAAM,kBAAkB,GAAG,CAAC,EACjC,IAAI,EACJ,IAAI,GAIL,EAAiB,EAAE;IAClB,2BAA2B;IAC3B,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEhD,4DAA4D;IAC5D,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QACnC,MAAM,cAAc,GAAG,IAAA,0BAAS,EAAC,IAAA,6BAAY,EAAC,IAAI,CAAC,CAAC,CAAC;QACrD,MAAM,cAAc,GAAG,IAAA,0BAAS,EAAC,IAAA,6BAAY,EAAC,IAAI,CAAC,CAAC,CAAC;QACrD,IAAI,cAAc,KAAK,cAAc;YAAE,OAAO,IAAI,CAAC;IACrD,CAAC;IAED,4BAA4B;IAC5B,MAAM,mBAAmB,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAA,6BAAY,EAAC,IAAI,CAAC,CAAC;IACpE,MAAM,mBAAmB,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAA,6BAAY,EAAC,IAAI,CAAC,CAAC;IAEpE,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAElD,6DAA6D;IAC7D,MAAM,UAAU,GAAG,IAAA,gBAAI,EAAC,mBAAmB,EAAE,mBAAmB,EAAE;QAChE,WAAW,EAAE,QAAQ;QACrB,WAAW,EAAE,SAAS;QACtB,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACpB,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACjC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3E,CAAC;KACF,CAAC,CAAC;IAEH,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC;AApCW,QAAA,kBAAkB,sBAoC7B"}
|
package/license.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 ehmpathy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "declastruct",
|
|
3
3
|
"author": "ehmpathy",
|
|
4
4
|
"description": "Add declarative control to any resource constructs. Declare, plan, and apply within an observable pit-of-success.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.3.1",
|
|
6
6
|
"repository": "ehmpathy/declastruct",
|
|
7
7
|
"homepage": "https://github.com/ehmpathy/declastruct",
|
|
8
8
|
"keywords": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"test:types": "tsc -p ./tsconfig.build.json --noEmit",
|
|
39
39
|
"test:format:prettier": "prettier --parser typescript --check 'src/**/*.ts' --config ./prettier.config.js",
|
|
40
40
|
"test:format": "npm run test:format:prettier",
|
|
41
|
-
"test:lint:deps": "npx depcheck -c
|
|
41
|
+
"test:lint:deps": "npx depcheck -c ./.depcheckrc.yml",
|
|
42
42
|
"test:lint:eslint": "eslint -c ./.eslintrc.js src/**/*.ts",
|
|
43
43
|
"test:lint": "npm run test:lint:eslint && npm run test:lint:deps",
|
|
44
44
|
"test:unit": "jest -c ./jest.unit.config.ts --forceExit --verbose --passWithNoTests $([ -z $THOROUGH ] && echo '--changedSince=main')",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"prepublish": "npm run build",
|
|
51
51
|
"preversion": "npm run prepush",
|
|
52
52
|
"postversion": "git push origin HEAD --tags --no-verify",
|
|
53
|
-
"
|
|
54
|
-
"prepare
|
|
53
|
+
"prepare:husky": "npx husky install && chmod ug+x .husky/*",
|
|
54
|
+
"prepare": "[ -d .git ] && npm run prepare:husky || exit 0"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"bottleneck": "2.19.5",
|
|
@@ -60,41 +60,51 @@
|
|
|
60
60
|
"jest-diff": "30.0.2",
|
|
61
61
|
"simple-log-methods": "0.6.2",
|
|
62
62
|
"tsx": "4.20.6",
|
|
63
|
-
"type-fns": "1.
|
|
63
|
+
"type-fns": "1.21.0",
|
|
64
64
|
"uuid-fns": "1.0.2"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"domain-objects": "0.31.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
+
"@babel/core": "7.28.5",
|
|
71
|
+
"@babel/preset-env": "7.28.5",
|
|
70
72
|
"@commitlint/cli": "19.3.0",
|
|
71
73
|
"@commitlint/config-conventional": "13.1.0",
|
|
72
74
|
"@trivago/prettier-plugin-sort-imports": "4.3.0",
|
|
73
75
|
"@tsconfig/node-lts-strictest": "18.12.1",
|
|
74
76
|
"@types/jest": "29.2.4",
|
|
77
|
+
"@types/node": "22.15.29",
|
|
75
78
|
"@typescript-eslint/eslint-plugin": "7.8.0",
|
|
76
79
|
"@typescript-eslint/parser": "7.8.0",
|
|
80
|
+
"babel-jest": "30.2.0",
|
|
77
81
|
"core-js": "3.26.1",
|
|
78
82
|
"cz-conventional-changelog": "3.3.0",
|
|
79
|
-
"declapract": "0.12.
|
|
80
|
-
"declapract-typescript-ehmpathy": "0.
|
|
83
|
+
"declapract": "0.12.3",
|
|
84
|
+
"declapract-typescript-ehmpathy": "0.42.2",
|
|
85
|
+
"declastruct": "1.3.0",
|
|
86
|
+
"declastruct-github": "1.0.3",
|
|
81
87
|
"depcheck": "1.4.3",
|
|
82
88
|
"eslint": "8.56.0",
|
|
83
89
|
"eslint-config-airbnb-typescript": "18.0.0",
|
|
84
90
|
"eslint-config-prettier": "8.5.0",
|
|
85
91
|
"eslint-plugin-import": "2.26.0",
|
|
86
92
|
"eslint-plugin-prettier": "4.2.1",
|
|
93
|
+
"eslint-plugin-unused-imports": "4.1.4",
|
|
87
94
|
"husky": "8.0.3",
|
|
88
95
|
"jest": "29.3.1",
|
|
89
96
|
"prettier": "2.8.1",
|
|
90
97
|
"rhachet": "1.12.1",
|
|
91
98
|
"rhachet-roles-ehmpathy": "1.9.1",
|
|
92
|
-
"
|
|
99
|
+
"test-fns": "1.7.2",
|
|
100
|
+
"ts-jest": "29.4.5",
|
|
101
|
+
"tsx": "4.20.6",
|
|
93
102
|
"typescript": "5.4.5"
|
|
94
103
|
},
|
|
95
104
|
"config": {
|
|
96
105
|
"commitizen": {
|
|
97
106
|
"path": "./node_modules/cz-conventional-changelog"
|
|
98
107
|
}
|
|
99
|
-
}
|
|
108
|
+
},
|
|
109
|
+
"packageManager": "pnpm@10.24.0"
|
|
100
110
|
}
|
package/readme.md
CHANGED
|
@@ -3,20 +3,40 @@
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|
|
|
6
|
-
declarative control
|
|
6
|
+
declarative control of any resource constructs, batteries included
|
|
7
7
|
|
|
8
8
|
# intro
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Control any resource construct declaratively. Declare what you want ✨. Plan to see what must change 🔮. Apply to make it so 🪄
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## what is it?
|
|
13
13
|
|
|
14
|
+
`declastruct` is a framework to control any resource construct via **declarative instructions** — you describe **what** you want the end state to be, and the system figures out **how** to get there.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
**declarative instructions** means:
|
|
17
|
+
- you declare the desired state of your resources
|
|
18
|
+
- the system compares your desires against reality
|
|
19
|
+
- the system computes the changes required to reconcile reality with your desires
|
|
20
|
+
- you review and apply those changes
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
in contrast to **imperative instructions**, where you specify each step and _hope_ it produces what you want:
|
|
23
|
+
```ts
|
|
24
|
+
// imperative 👎 = you say HOW to do things, step by step
|
|
25
|
+
await createBucket({ name: 'my-bucket' });
|
|
26
|
+
await enableVersioning({ bucket: 'my-bucket' });
|
|
27
|
+
await setEncryption({ bucket: 'my-bucket', type: 'AES256' });
|
|
28
|
+
```
|
|
18
29
|
|
|
19
|
-
|
|
30
|
+
the advantage of **declarative instructions** is that you simply declare what you want and _know_ it will work:
|
|
31
|
+
```ts
|
|
32
|
+
// declarative 👍 = you say WHAT you want, the system figures out how
|
|
33
|
+
const bucket = DeclaredAwsS3Bucket.as({
|
|
34
|
+
name: 'my-bucket',
|
|
35
|
+
versioning: true,
|
|
36
|
+
encryption: 'AES256',
|
|
37
|
+
});
|
|
38
|
+
await apply({ resources: [bucket] });
|
|
39
|
+
```
|
|
20
40
|
|
|
21
41
|
works with:
|
|
22
42
|
- **infrastructure** — AWS, GCP, Azure resources
|
|
@@ -26,7 +46,7 @@ works with:
|
|
|
26
46
|
|
|
27
47
|
think Terraform, but:
|
|
28
48
|
- **no state files to manage** — compares directly against live remote state
|
|
29
|
-
- **no new language to learn** —
|
|
49
|
+
- **no new language to learn** — declare via TypeScript, reuse domain objects and operations
|
|
30
50
|
- **pit-of-success by default** — enforces idempotency, clear unique keys, and safe operations
|
|
31
51
|
- **not just infrastructure** — works with any resource construct (saas, databases, apis, etc)
|
|
32
52
|
|
|
@@ -42,7 +62,7 @@ npm install declastruct --save-dev
|
|
|
42
62
|
|
|
43
63
|
### 1. **declare** your desired state ✨
|
|
44
64
|
|
|
45
|
-
|
|
65
|
+
declare your wish via strongly-typed [domain-objects](https://github.com/ehmpathy/domain-objects). these are the declarative instructions that will control your resources.
|
|
46
66
|
|
|
47
67
|
```ts
|
|
48
68
|
import { getDeclastructAwsProvider, DeclaredAwsS3Bucket } from 'declastruct-aws';
|
|
@@ -78,7 +98,7 @@ export const getResources = async () => {
|
|
|
78
98
|
|
|
79
99
|
### 2. **plan** the required changes 🔮
|
|
80
100
|
|
|
81
|
-
see exactly what
|
|
101
|
+
see exactly what must change to make your wish come true, ahead of time
|
|
82
102
|
|
|
83
103
|
```sh
|
|
84
104
|
npx declastruct plan \
|
|
@@ -102,7 +122,7 @@ planned changes:
|
|
|
102
122
|
|
|
103
123
|
### 3. **apply** the plan 🪄
|
|
104
124
|
|
|
105
|
-
|
|
125
|
+
apply the plan to make your wish come true
|
|
106
126
|
|
|
107
127
|
```sh
|
|
108
128
|
npx declastruct apply --plan provision/.temp/plan.json
|
|
@@ -116,11 +136,11 @@ npx declastruct apply --plan provision/.temp/plan.json
|
|
|
116
136
|
|
|
117
137
|
✅ **type-safe** — full TypeScript support with domain objects
|
|
118
138
|
|
|
119
|
-
✅ **idempotent** — safe to
|
|
139
|
+
✅ **idempotent** — safe to plan and apply repeatedly
|
|
120
140
|
|
|
121
|
-
✅ **observable** — see exactly what
|
|
141
|
+
✅ **observable** — see exactly what would change if you apply
|
|
122
142
|
|
|
123
|
-
✅ **composable** — reuse domain objects and operations across application code and
|
|
143
|
+
✅ **composable** — reuse domain objects and operations across application code and declarative instructions
|
|
124
144
|
|
|
125
145
|
✅ **pit-of-success** — enforced best practices via idempotent dao interfaces
|
|
126
146
|
|
|
@@ -131,20 +151,20 @@ npx declastruct apply --plan provision/.temp/plan.json
|
|
|
131
151
|
|
|
132
152
|
### no state file management
|
|
133
153
|
|
|
134
|
-
traditional declarative tools (like Terraform) require
|
|
154
|
+
traditional declarative tools (like Terraform) require separate state files to track resources existence. this creates problems:
|
|
135
155
|
- state files can drift from reality
|
|
136
|
-
- state
|
|
156
|
+
- state lock issues in team environments
|
|
137
157
|
- state files must be carefully secured and backed up
|
|
138
158
|
|
|
139
|
-
**declastruct eliminates state files entirely.** it compares your
|
|
159
|
+
**declastruct eliminates state files entirely.** it compares your declared desires directly against live remote state via unique keys, so the source of truth is always reality itself.
|
|
140
160
|
|
|
141
161
|
### use your existing domain language
|
|
142
162
|
|
|
143
|
-
instead of
|
|
144
|
-
-
|
|
145
|
-
- reuse the
|
|
146
|
-
- leverage TypeScript's type safety, IDE autocomplete, and
|
|
147
|
-
- compose and test
|
|
163
|
+
instead of HCL, YAML, or another DSL:
|
|
164
|
+
- write declarative instructions via TypeScript with [`domain-objects`](https://github.com/ehmpathy/domain-objects)
|
|
165
|
+
- reuse the domain objects and domain operations across your application code and declarative instructions
|
|
166
|
+
- leverage TypeScript's type safety, IDE autocomplete, and refactor tools
|
|
167
|
+
- compose and test declarative instructions like any other code
|
|
148
168
|
|
|
149
169
|
### enforced best practices
|
|
150
170
|
|
|
@@ -153,14 +173,14 @@ declastruct providers follow a pit-of-success pattern that guarantees:
|
|
|
153
173
|
**idempotency** — all operations can be safely retried
|
|
154
174
|
- `finsert`: find-or-insert (safe create)
|
|
155
175
|
- `upsert`: update-or-insert (safe update)
|
|
156
|
-
-
|
|
176
|
+
- repeat any operation multiple times, get the same result each time
|
|
157
177
|
|
|
158
178
|
**explicit unique keys** — every resource declares how to uniquely identify it
|
|
159
179
|
- prevents accidental duplicates
|
|
160
180
|
- enables accurate comparison against live state
|
|
161
181
|
- makes resource relationships clear, typesafe, and composable
|
|
162
182
|
|
|
163
|
-
**observable change plans** — see exactly what
|
|
183
|
+
**observable change plans** — see exactly what must change before you apply
|
|
164
184
|
- diff view shows before & after for each resource
|
|
165
185
|
- change actions: CREATE, UPDATE, KEEP, DESTROY
|
|
166
186
|
- no surprises in production
|
|
@@ -175,14 +195,14 @@ declastruct is designed to support any resource construct through adapters:
|
|
|
175
195
|
- `declastruct-github` — Github resources (repos, branches, protection, etc.)
|
|
176
196
|
- etc
|
|
177
197
|
|
|
178
|
-
**build your own provider** for any resource construct (GitHub repos, Slack channels, database records, etc.)
|
|
198
|
+
**build your own provider** for any resource construct (GitHub repos, Slack channels, database records, etc.) via the `DeclastructDao` and `DeclastructProvider` interfaces.
|
|
179
199
|
|
|
180
200
|
## use cases
|
|
181
201
|
|
|
182
|
-
- **infrastructure as code** —
|
|
183
|
-
- **SaaS platform management** —
|
|
184
|
-
- **database state management** — control database resource states
|
|
185
|
-
- **api state management** — control remote resource state
|
|
202
|
+
- **infrastructure as code** — control AWS, GCP, Azure resources via declarative instructions
|
|
203
|
+
- **SaaS platform management** — control Stripe customers, GitHub repos, Slack channels via declarative instructions
|
|
204
|
+
- **database state management** — control database resource states via declarative instructions
|
|
205
|
+
- **api state management** — control remote resource state via declarative instructions
|
|
186
206
|
- **multi-platform orchestration** — coordinate resources across different providers in one plan
|
|
187
207
|
|
|
188
208
|
|
|
@@ -192,7 +212,7 @@ declastruct is designed to support any resource construct through adapters:
|
|
|
192
212
|
|
|
193
213
|
### DeclastructDao
|
|
194
214
|
|
|
195
|
-
the core abstraction that defines how to
|
|
215
|
+
the core abstraction that defines how to get and set a resource type:
|
|
196
216
|
|
|
197
217
|
```ts
|
|
198
218
|
interface DeclastructDao<TResource, TResourceClass, TContext> {
|
|
@@ -209,7 +229,7 @@ interface DeclastructDao<TResource, TResourceClass, TContext> {
|
|
|
209
229
|
}
|
|
210
230
|
```
|
|
211
231
|
|
|
212
|
-
every resource class
|
|
232
|
+
every resource class has a DeclastructDao that enforces safe, idempotent operations.
|
|
213
233
|
|
|
214
234
|
### DeclastructProvider
|
|
215
235
|
|
|
@@ -229,7 +249,7 @@ interface DeclastructProvider<TDaos, TContext> {
|
|
|
229
249
|
|
|
230
250
|
### DeclastructPlan
|
|
231
251
|
|
|
232
|
-
captures the changes needed to
|
|
252
|
+
captures the changes needed to reconcile reality with declared desires:
|
|
233
253
|
|
|
234
254
|
```ts
|
|
235
255
|
interface DeclastructPlan {
|
|
@@ -249,4 +269,4 @@ each `DeclastructChange` includes:
|
|
|
249
269
|
|
|
250
270
|
## inspiration
|
|
251
271
|
|
|
252
|
-
inspired by Terraform's declarative approach, but designed to eliminate state
|
|
272
|
+
inspired by Terraform's declarative approach, but designed to eliminate state file overhead, work with any resource construct, be reusable across both prod codepaths and cicd control, and leverage TypeScript's type system for safer declarative instructions.
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { DomainEntity } from 'domain-objects';
|
|
2
|
-
import { DeclastructDao } from '../../../domain.objects/DeclastructDao';
|
|
3
|
-
import { DeclastructProvider } from '../../../domain.objects/DeclastructProvider';
|
|
4
|
-
/**
|
|
5
|
-
* .what = demo resource for integration testing
|
|
6
|
-
*/
|
|
7
|
-
interface DemoResource {
|
|
8
|
-
exid: string;
|
|
9
|
-
name: string;
|
|
10
|
-
}
|
|
11
|
-
declare class DemoResource extends DomainEntity<DemoResource> implements DemoResource {
|
|
12
|
-
static unique: readonly ["exid"];
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* .what = demo provider with on-disk persistence
|
|
16
|
-
* .why = enables full integration testing with real CRUD operations
|
|
17
|
-
*/
|
|
18
|
-
export declare const demoProvider: DeclastructProvider<{
|
|
19
|
-
DemoResource: DeclastructDao<DemoResource, typeof DemoResource, any>;
|
|
20
|
-
}, {}>;
|
|
21
|
-
/**
|
|
22
|
-
* .what = generates a sample DemoResource with automatic unique ID
|
|
23
|
-
* .why = simplifies test resource creation without managing IDs manually
|
|
24
|
-
* .note = use resource.clone({ name: 'New Name' }) to update properties while keeping same exid
|
|
25
|
-
*/
|
|
26
|
-
export declare const genSampleDemoResource: (input: {
|
|
27
|
-
name: string;
|
|
28
|
-
}) => import("domain-objects/dist/manipulation/immute/withImmute").WithImmute<DemoResource>;
|
|
29
|
-
/**
|
|
30
|
-
* .what = export DemoResource class for test usage
|
|
31
|
-
*/
|
|
32
|
-
export { DemoResource };
|