@terraforge/core 0.0.19 → 0.0.20
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.mts +70 -13
- package/dist/index.mjs +125 -33
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S3Client } from "@aws-sdk/client-s3";
|
|
2
1
|
import { DynamoDB } from "@aws-sdk/client-dynamodb";
|
|
2
|
+
import { S3Client } from "@aws-sdk/client-s3";
|
|
3
3
|
import { UUID } from "node:crypto";
|
|
4
4
|
import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from "@aws-sdk/types";
|
|
5
5
|
|
|
@@ -208,6 +208,20 @@ type StateBackend = {
|
|
|
208
208
|
delete(urn: URN): Promise<void>;
|
|
209
209
|
};
|
|
210
210
|
//#endregion
|
|
211
|
+
//#region src/backend/activity-log.d.ts
|
|
212
|
+
type LogProps = {
|
|
213
|
+
action: 'deploy' | 'delete';
|
|
214
|
+
filters?: string[];
|
|
215
|
+
};
|
|
216
|
+
type Log = LogProps & {
|
|
217
|
+
user?: string;
|
|
218
|
+
date?: number;
|
|
219
|
+
};
|
|
220
|
+
type ActivityLogBackend = {
|
|
221
|
+
log(urn: URN, log: LogProps): Promise<void>;
|
|
222
|
+
tail(urn: URN): Promise<Log[]>;
|
|
223
|
+
};
|
|
224
|
+
//#endregion
|
|
211
225
|
//#region src/provider.d.ts
|
|
212
226
|
type CreateProps<T = State> = {
|
|
213
227
|
type: string;
|
|
@@ -319,6 +333,7 @@ type WorkSpaceOptions = {
|
|
|
319
333
|
backend: {
|
|
320
334
|
state: StateBackend;
|
|
321
335
|
lock: LockBackend;
|
|
336
|
+
activityLog?: ActivityLogBackend;
|
|
322
337
|
};
|
|
323
338
|
hooks?: Hooks;
|
|
324
339
|
};
|
|
@@ -367,6 +382,19 @@ declare class AppError extends Error {
|
|
|
367
382
|
declare class ResourceNotFound extends Error {}
|
|
368
383
|
declare class ResourceAlreadyExists extends Error {}
|
|
369
384
|
//#endregion
|
|
385
|
+
//#region src/backend/memory/activity-log.d.ts
|
|
386
|
+
type Props$4 = {
|
|
387
|
+
user?: string;
|
|
388
|
+
};
|
|
389
|
+
declare class MemoryActivityLogBackend implements ActivityLogBackend {
|
|
390
|
+
private props;
|
|
391
|
+
protected groups: Map<`urn:${string}`, Log[]>;
|
|
392
|
+
constructor(props?: Props$4);
|
|
393
|
+
log(urn: URN, log: LogProps): Promise<void>;
|
|
394
|
+
private getLogGroup;
|
|
395
|
+
tail(urn: URN, limit?: number): Promise<Log[]>;
|
|
396
|
+
}
|
|
397
|
+
//#endregion
|
|
370
398
|
//#region src/backend/memory/state.d.ts
|
|
371
399
|
declare class MemoryStateBackend implements StateBackend {
|
|
372
400
|
protected states: Map<`urn:${string}`, AppState>;
|
|
@@ -385,6 +413,20 @@ declare class MemoryLockBackend implements LockBackend {
|
|
|
385
413
|
clear(): void;
|
|
386
414
|
}
|
|
387
415
|
//#endregion
|
|
416
|
+
//#region src/backend/file/activity-log.d.ts
|
|
417
|
+
type Props$3 = {
|
|
418
|
+
user?: string;
|
|
419
|
+
dir: string;
|
|
420
|
+
};
|
|
421
|
+
declare class FileActivityLogBackend implements ActivityLogBackend {
|
|
422
|
+
private props;
|
|
423
|
+
constructor(props: Props$3);
|
|
424
|
+
private logFile;
|
|
425
|
+
private mkdir;
|
|
426
|
+
log(urn: URN, log: LogProps): Promise<void>;
|
|
427
|
+
tail(urn: URN, limit?: number): Promise<Log[]>;
|
|
428
|
+
}
|
|
429
|
+
//#endregion
|
|
388
430
|
//#region src/backend/file/state.d.ts
|
|
389
431
|
declare class FileStateBackend implements StateBackend {
|
|
390
432
|
private props;
|
|
@@ -411,23 +453,23 @@ declare class FileLockBackend implements LockBackend {
|
|
|
411
453
|
lock(urn: URN): Promise<() => Promise<void>>;
|
|
412
454
|
}
|
|
413
455
|
//#endregion
|
|
414
|
-
//#region src/backend/aws/
|
|
415
|
-
type Props$
|
|
456
|
+
//#region src/backend/aws/dynamodb-activity-log.d.ts
|
|
457
|
+
type Props$2 = {
|
|
416
458
|
credentials: AwsCredentialIdentity | AwsCredentialIdentityProvider;
|
|
417
459
|
region: string;
|
|
418
|
-
|
|
460
|
+
tableName: string;
|
|
461
|
+
user?: string;
|
|
419
462
|
};
|
|
420
|
-
declare class
|
|
463
|
+
declare class DynamoDBActivityLogBackend implements ActivityLogBackend {
|
|
421
464
|
private props;
|
|
422
|
-
protected client:
|
|
423
|
-
constructor(props: Props$
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
delete(urn: URN): Promise<void>;
|
|
465
|
+
protected client: DynamoDB;
|
|
466
|
+
constructor(props: Props$2);
|
|
467
|
+
log(urn: URN, log: LogProps): Promise<void>;
|
|
468
|
+
tail(urn: URN, limit?: number): Promise<Log[]>;
|
|
427
469
|
}
|
|
428
470
|
//#endregion
|
|
429
471
|
//#region src/backend/aws/dynamodb-lock.d.ts
|
|
430
|
-
type Props = {
|
|
472
|
+
type Props$1 = {
|
|
431
473
|
credentials: AwsCredentialIdentity | AwsCredentialIdentityProvider;
|
|
432
474
|
region: string;
|
|
433
475
|
tableName: string;
|
|
@@ -435,12 +477,27 @@ type Props = {
|
|
|
435
477
|
declare class DynamoLockBackend implements LockBackend {
|
|
436
478
|
private props;
|
|
437
479
|
protected client: DynamoDB;
|
|
438
|
-
constructor(props: Props);
|
|
480
|
+
constructor(props: Props$1);
|
|
439
481
|
insecureReleaseLock(urn: URN): Promise<void>;
|
|
440
482
|
locked(urn: URN): Promise<boolean>;
|
|
441
483
|
lock(urn: URN): Promise<() => Promise<void>>;
|
|
442
484
|
}
|
|
443
485
|
//#endregion
|
|
486
|
+
//#region src/backend/aws/s3-state.d.ts
|
|
487
|
+
type Props = {
|
|
488
|
+
credentials: AwsCredentialIdentity | AwsCredentialIdentityProvider;
|
|
489
|
+
region: string;
|
|
490
|
+
bucket: string;
|
|
491
|
+
};
|
|
492
|
+
declare class S3StateBackend implements StateBackend {
|
|
493
|
+
private props;
|
|
494
|
+
protected client: S3Client;
|
|
495
|
+
constructor(props: Props);
|
|
496
|
+
get(urn: URN): Promise<any>;
|
|
497
|
+
update(urn: URN, state: AppState): Promise<void>;
|
|
498
|
+
delete(urn: URN): Promise<void>;
|
|
499
|
+
}
|
|
500
|
+
//#endregion
|
|
444
501
|
//#region src/helpers.d.ts
|
|
445
502
|
declare const file: (path: string, encoding?: BufferEncoding) => Future<string>;
|
|
446
503
|
declare const hash: (path: string, algo?: string) => Future<string>;
|
|
@@ -471,4 +528,4 @@ type CustomResourceProvider = Partial<{
|
|
|
471
528
|
}>;
|
|
472
529
|
declare const createCustomProvider: (providerId: string, resourceProviders: Record<string, CustomResourceProvider>) => Provider;
|
|
473
530
|
//#endregion
|
|
474
|
-
export { App, AppError, type Config, type CreateProps, type CustomResourceProvider, type DataSource, type DataSourceFunction, type DataSourceMeta, type DeleteProps, DynamoLockBackend, FileLockBackend, FileStateBackend, Future, type GetDataProps, type GetProps, Group, type Input, LockBackend, MemoryLockBackend, MemoryStateBackend, type Meta, type Node, type OptionalInput, type OptionalOutput, Output, type PlanProps, type ProcedureOptions, type Provider, type Resource, ResourceAlreadyExists, type ResourceClass, type ResourceConfig, ResourceError, type ResourceMeta, ResourceNotFound, type ResourceStatus, type ResourceStatusInfo, S3StateBackend, Stack, type StackStatusInfo, type State, StateBackend, type Tag, type URN, type UpdateProps, WorkSpace, type WorkSpaceOptions, createCustomProvider, createCustomResourceClass, createDebugger, createMeta, deferredOutput, enableDebug, findInputDeps, getMeta, isDataSource, isNode, isResource, nodeMetaSymbol, output, resolveInputs };
|
|
531
|
+
export { ActivityLogBackend, App, AppError, type Config, type CreateProps, type CustomResourceProvider, type DataSource, type DataSourceFunction, type DataSourceMeta, type DeleteProps, DynamoDBActivityLogBackend, DynamoLockBackend, FileActivityLogBackend, FileLockBackend, FileStateBackend, Future, type GetDataProps, type GetProps, Group, type Input, LockBackend, Log, LogProps, MemoryActivityLogBackend, MemoryLockBackend, MemoryStateBackend, type Meta, type Node, type OptionalInput, type OptionalOutput, Output, type PlanProps, type ProcedureOptions, type Provider, type Resource, ResourceAlreadyExists, type ResourceClass, type ResourceConfig, ResourceError, type ResourceMeta, ResourceNotFound, type ResourceStatus, type ResourceStatusInfo, S3StateBackend, Stack, type StackStatusInfo, type State, StateBackend, type Tag, type URN, type UpdateProps, WorkSpace, type WorkSpaceOptions, createCustomProvider, createCustomResourceClass, createDebugger, createMeta, deferredOutput, enableDebug, findInputDeps, getMeta, isDataSource, isNode, isResource, nodeMetaSymbol, output, resolveInputs };
|
package/dist/index.mjs
CHANGED
|
@@ -4,12 +4,12 @@ import { DirectedGraph } from "graphology";
|
|
|
4
4
|
import { topologicalGenerations, willCreateCycle } from "graphology-dag";
|
|
5
5
|
import { v5 } from "uuid";
|
|
6
6
|
import { get } from "get-wild";
|
|
7
|
-
import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
7
|
+
import { appendFile, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { lock } from "proper-lockfile";
|
|
10
|
-
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
11
10
|
import { DynamoDB } from "@aws-sdk/client-dynamodb";
|
|
12
11
|
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
|
|
12
|
+
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
13
13
|
import { createHash } from "node:crypto";
|
|
14
14
|
|
|
15
15
|
//#region src/node.ts
|
|
@@ -605,6 +605,10 @@ const deleteResource = async (appToken, urn, state, opt) => {
|
|
|
605
605
|
//#endregion
|
|
606
606
|
//#region src/workspace/procedure/delete-app.ts
|
|
607
607
|
const deleteApp = async (app, opt) => {
|
|
608
|
+
await opt.backend.activityLog?.log(app.urn, {
|
|
609
|
+
action: "delete",
|
|
610
|
+
filters: opt.filters
|
|
611
|
+
});
|
|
608
612
|
const latestState = await opt.backend.state.get(app.urn);
|
|
609
613
|
if (!latestState) throw new AppError(app.name, [], `App already deleted: ${app.name}`);
|
|
610
614
|
const appState = migrateAppState(latestState);
|
|
@@ -863,6 +867,10 @@ const updateResource = async (resource, appToken, priorInputState, priorOutputSt
|
|
|
863
867
|
const debug$1 = createDebugger("Deploy App");
|
|
864
868
|
const deployApp = async (app, opt) => {
|
|
865
869
|
debug$1(app.name, "start");
|
|
870
|
+
await opt.backend.activityLog?.log(app.urn, {
|
|
871
|
+
action: "deploy",
|
|
872
|
+
filters: opt.filters
|
|
873
|
+
});
|
|
866
874
|
const appState = migrateAppState(await opt.backend.state.get(app.urn) ?? {
|
|
867
875
|
name: app.name,
|
|
868
876
|
stacks: {}
|
|
@@ -1304,6 +1312,29 @@ var WorkSpace = class {
|
|
|
1304
1312
|
}
|
|
1305
1313
|
};
|
|
1306
1314
|
|
|
1315
|
+
//#endregion
|
|
1316
|
+
//#region src/backend/memory/activity-log.ts
|
|
1317
|
+
var MemoryActivityLogBackend = class {
|
|
1318
|
+
groups = /* @__PURE__ */ new Map();
|
|
1319
|
+
constructor(props = {}) {
|
|
1320
|
+
this.props = props;
|
|
1321
|
+
}
|
|
1322
|
+
async log(urn, log) {
|
|
1323
|
+
this.getLogGroup(urn).push({
|
|
1324
|
+
user: this.props.user,
|
|
1325
|
+
date: Date.now(),
|
|
1326
|
+
...log
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
getLogGroup(urn) {
|
|
1330
|
+
if (!this.groups.has(urn)) this.groups.set(urn, []);
|
|
1331
|
+
return this.groups.get(urn);
|
|
1332
|
+
}
|
|
1333
|
+
async tail(urn, limit = 10) {
|
|
1334
|
+
return this.getLogGroup(urn).slice(-limit);
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
|
|
1307
1338
|
//#endregion
|
|
1308
1339
|
//#region src/backend/memory/state.ts
|
|
1309
1340
|
var MemoryStateBackend = class {
|
|
@@ -1345,6 +1376,34 @@ var MemoryLockBackend = class {
|
|
|
1345
1376
|
}
|
|
1346
1377
|
};
|
|
1347
1378
|
|
|
1379
|
+
//#endregion
|
|
1380
|
+
//#region src/backend/file/activity-log.ts
|
|
1381
|
+
var FileActivityLogBackend = class {
|
|
1382
|
+
constructor(props) {
|
|
1383
|
+
this.props = props;
|
|
1384
|
+
}
|
|
1385
|
+
logFile(urn) {
|
|
1386
|
+
return join(this.props.dir, `${urn}.log.jsonl`);
|
|
1387
|
+
}
|
|
1388
|
+
async mkdir() {
|
|
1389
|
+
await mkdir(this.props.dir, { recursive: true });
|
|
1390
|
+
}
|
|
1391
|
+
async log(urn, log) {
|
|
1392
|
+
const json = JSON.stringify({
|
|
1393
|
+
user: this.props.user,
|
|
1394
|
+
date: Date.now(),
|
|
1395
|
+
...log
|
|
1396
|
+
});
|
|
1397
|
+
await this.mkdir();
|
|
1398
|
+
await appendFile(this.logFile(urn), `${json}\n`);
|
|
1399
|
+
}
|
|
1400
|
+
async tail(urn, limit = 10) {
|
|
1401
|
+
const file$1 = this.logFile(urn);
|
|
1402
|
+
if (!(await stat(file$1)).isFile()) return [];
|
|
1403
|
+
return (await readFile(file$1, "utf8")).split("\n").filter(Boolean).slice(-limit).map((line) => JSON.parse(line));
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1348
1407
|
//#endregion
|
|
1349
1408
|
//#region src/backend/file/state.ts
|
|
1350
1409
|
const debug = createDebugger("State");
|
|
@@ -1353,7 +1412,7 @@ var FileStateBackend = class {
|
|
|
1353
1412
|
this.props = props;
|
|
1354
1413
|
}
|
|
1355
1414
|
stateFile(urn) {
|
|
1356
|
-
return join(this.props.dir, `${urn}.json`);
|
|
1415
|
+
return join(this.props.dir, `${urn}.state.json`);
|
|
1357
1416
|
}
|
|
1358
1417
|
async mkdir() {
|
|
1359
1418
|
await mkdir(this.props.dir, { recursive: true });
|
|
@@ -1405,40 +1464,35 @@ var FileLockBackend = class {
|
|
|
1405
1464
|
};
|
|
1406
1465
|
|
|
1407
1466
|
//#endregion
|
|
1408
|
-
//#region src/backend/aws/
|
|
1409
|
-
var
|
|
1467
|
+
//#region src/backend/aws/dynamodb-activity-log.ts
|
|
1468
|
+
var DynamoDBActivityLogBackend = class {
|
|
1410
1469
|
client;
|
|
1411
1470
|
constructor(props) {
|
|
1412
1471
|
this.props = props;
|
|
1413
|
-
this.client = new
|
|
1414
|
-
}
|
|
1415
|
-
async get(urn) {
|
|
1416
|
-
let result;
|
|
1417
|
-
try {
|
|
1418
|
-
result = await this.client.send(new GetObjectCommand({
|
|
1419
|
-
Bucket: this.props.bucket,
|
|
1420
|
-
Key: `${urn}.state`
|
|
1421
|
-
}));
|
|
1422
|
-
} catch (error) {
|
|
1423
|
-
if (error instanceof S3ServiceException && error.name === "NoSuchKey") return;
|
|
1424
|
-
throw error;
|
|
1425
|
-
}
|
|
1426
|
-
if (!result.Body) return;
|
|
1427
|
-
const body = await result.Body.transformToString("utf8");
|
|
1428
|
-
return JSON.parse(body);
|
|
1472
|
+
this.client = new DynamoDB(props);
|
|
1429
1473
|
}
|
|
1430
|
-
async
|
|
1431
|
-
await this.client.
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1474
|
+
async log(urn, log) {
|
|
1475
|
+
await this.client.putItem({
|
|
1476
|
+
TableName: this.props.tableName,
|
|
1477
|
+
Item: marshall({
|
|
1478
|
+
urn,
|
|
1479
|
+
user: this.props.user,
|
|
1480
|
+
date: Date.now(),
|
|
1481
|
+
...log
|
|
1482
|
+
})
|
|
1483
|
+
});
|
|
1436
1484
|
}
|
|
1437
|
-
async
|
|
1438
|
-
await this.client.
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1485
|
+
async tail(urn, limit = 10) {
|
|
1486
|
+
return (await this.client.query({
|
|
1487
|
+
TableName: this.props.tableName,
|
|
1488
|
+
KeyConditionExpression: "#urn = :urn",
|
|
1489
|
+
ExpressionAttributeNames: { "#urn": "urn" },
|
|
1490
|
+
ExpressionAttributeValues: { ":urn": marshall(urn) },
|
|
1491
|
+
ScanIndexForward: false,
|
|
1492
|
+
Limit: limit
|
|
1493
|
+
})).Items?.map((item) => {
|
|
1494
|
+
return unmarshall(item);
|
|
1495
|
+
}) ?? [];
|
|
1442
1496
|
}
|
|
1443
1497
|
};
|
|
1444
1498
|
|
|
@@ -1489,6 +1543,44 @@ var DynamoLockBackend = class {
|
|
|
1489
1543
|
}
|
|
1490
1544
|
};
|
|
1491
1545
|
|
|
1546
|
+
//#endregion
|
|
1547
|
+
//#region src/backend/aws/s3-state.ts
|
|
1548
|
+
var S3StateBackend = class {
|
|
1549
|
+
client;
|
|
1550
|
+
constructor(props) {
|
|
1551
|
+
this.props = props;
|
|
1552
|
+
this.client = new S3Client(props);
|
|
1553
|
+
}
|
|
1554
|
+
async get(urn) {
|
|
1555
|
+
let result;
|
|
1556
|
+
try {
|
|
1557
|
+
result = await this.client.send(new GetObjectCommand({
|
|
1558
|
+
Bucket: this.props.bucket,
|
|
1559
|
+
Key: `${urn}.state`
|
|
1560
|
+
}));
|
|
1561
|
+
} catch (error) {
|
|
1562
|
+
if (error instanceof S3ServiceException && error.name === "NoSuchKey") return;
|
|
1563
|
+
throw error;
|
|
1564
|
+
}
|
|
1565
|
+
if (!result.Body) return;
|
|
1566
|
+
const body = await result.Body.transformToString("utf8");
|
|
1567
|
+
return JSON.parse(body);
|
|
1568
|
+
}
|
|
1569
|
+
async update(urn, state) {
|
|
1570
|
+
await this.client.send(new PutObjectCommand({
|
|
1571
|
+
Bucket: this.props.bucket,
|
|
1572
|
+
Key: `${urn}.state`,
|
|
1573
|
+
Body: JSON.stringify(state)
|
|
1574
|
+
}));
|
|
1575
|
+
}
|
|
1576
|
+
async delete(urn) {
|
|
1577
|
+
await this.client.send(new DeleteObjectCommand({
|
|
1578
|
+
Bucket: this.props.bucket,
|
|
1579
|
+
Key: `${urn}.state`
|
|
1580
|
+
}));
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1492
1584
|
//#endregion
|
|
1493
1585
|
//#region src/helpers.ts
|
|
1494
1586
|
const file = (path, encoding = "utf8") => {
|
|
@@ -1599,4 +1691,4 @@ const createCustomProvider = (providerId, resourceProviders) => {
|
|
|
1599
1691
|
};
|
|
1600
1692
|
|
|
1601
1693
|
//#endregion
|
|
1602
|
-
export { App, AppError, DynamoLockBackend, FileLockBackend, FileStateBackend, Future, Group, MemoryLockBackend, MemoryStateBackend, Output, ResourceAlreadyExists, ResourceError, ResourceNotFound, S3StateBackend, Stack, WorkSpace, createCustomProvider, createCustomResourceClass, createDebugger, createMeta, deferredOutput, enableDebug, findInputDeps, getMeta, isDataSource, isNode, isResource, nodeMetaSymbol, output, resolveInputs };
|
|
1694
|
+
export { App, AppError, DynamoDBActivityLogBackend, DynamoLockBackend, FileActivityLogBackend, FileLockBackend, FileStateBackend, Future, Group, MemoryActivityLogBackend, MemoryLockBackend, MemoryStateBackend, Output, ResourceAlreadyExists, ResourceError, ResourceNotFound, S3StateBackend, Stack, WorkSpace, createCustomProvider, createCustomResourceClass, createDebugger, createMeta, deferredOutput, enableDebug, findInputDeps, getMeta, isDataSource, isNode, isResource, nodeMetaSymbol, output, resolveInputs };
|