@serve.zone/gitops 32.1.0 → 32.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/changelog.md +18 -0
- package/deno.json +1 -1
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes/actionlog.d.ts +1 -1
- package/dist_ts/classes/actionlog.js +1 -1
- package/dist_ts/classes/connectionmanager.d.ts +1 -5
- package/dist_ts/classes/connectionmanager.js +5 -28
- package/dist_ts/classes/gitopsapp.d.ts +8 -3
- package/dist_ts/classes/gitopsapp.js +29 -18
- package/dist_ts/{cache/classes.secrets.scan.service.d.ts → classes/secrets.scan.service.d.ts} +1 -1
- package/dist_ts/{cache/classes.secrets.scan.service.js → classes/secrets.scan.service.js} +3 -3
- package/dist_ts/{cache → db}/classes.cache.cleaner.d.ts +1 -3
- package/dist_ts/db/classes.cache.cleaner.js +59 -0
- package/dist_ts/{cache → db}/classes.cached.document.d.ts +1 -1
- package/dist_ts/{cache → db}/classes.cached.document.js +2 -2
- package/dist_ts/db/classes.gitops-db.d.ts +34 -0
- package/dist_ts/db/classes.gitops-db.js +77 -0
- package/dist_ts/{cache → db}/documents/classes.cached.project.js +3 -3
- package/dist_ts/{cache → db}/documents/classes.cached.secret.js +3 -3
- package/dist_ts/db/documents/classes.storage.record.d.ts +14 -0
- package/dist_ts/db/documents/classes.storage.record.js +82 -0
- package/dist_ts/{cache → db}/documents/index.d.ts +1 -0
- package/dist_ts/db/documents/index.js +4 -0
- package/dist_ts/db/index.d.ts +5 -0
- package/dist_ts/db/index.js +5 -0
- package/dist_ts/paths.d.ts +2 -2
- package/dist_ts/paths.js +2 -3
- package/dist_ts/plugins.d.ts +2 -3
- package/dist_ts/plugins.js +6 -4
- package/dist_ts/storage/classes.storagemanager.d.ts +7 -16
- package/dist_ts/storage/classes.storagemanager.js +54 -94
- package/dist_ts/storage/index.d.ts +0 -1
- package/dist_ts_migrations/classes.migration-record.d.ts +11 -0
- package/dist_ts_migrations/classes.migration-record.js +80 -0
- package/dist_ts_migrations/import-filesystem-records.d.ts +9 -0
- package/dist_ts_migrations/import-filesystem-records.js +74 -0
- package/dist_ts_migrations/index.d.ts +12 -0
- package/dist_ts_migrations/index.js +24 -0
- package/dist_ts_migrations/interfaces.d.ts +16 -0
- package/dist_ts_migrations/interfaces.js +2 -0
- package/package.json +6 -4
- package/readme.md +21 -14
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes/actionlog.ts +1 -1
- package/ts/classes/connectionmanager.ts +4 -27
- package/ts/classes/gitopsapp.ts +36 -17
- package/ts/{cache/classes.secrets.scan.service.ts → classes/secrets.scan.service.ts} +3 -3
- package/ts/{cache → db}/classes.cache.cleaner.ts +1 -4
- package/ts/{cache → db}/classes.cached.document.ts +1 -1
- package/ts/db/classes.gitops-db.ts +92 -0
- package/ts/{cache → db}/documents/classes.cached.project.ts +2 -2
- package/ts/{cache → db}/documents/classes.cached.secret.ts +2 -2
- package/ts/db/documents/classes.storage.record.ts +26 -0
- package/ts/{cache → db}/documents/index.ts +1 -0
- package/ts/db/index.ts +5 -0
- package/ts/paths.ts +3 -4
- package/ts/plugins.ts +5 -3
- package/ts/storage/classes.storagemanager.ts +59 -95
- package/ts/storage/index.ts +0 -1
- package/ts_migrations/classes.migration-record.ts +23 -0
- package/ts_migrations/import-filesystem-records.ts +79 -0
- package/ts_migrations/index.ts +31 -0
- package/ts_migrations/interfaces.ts +18 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/dist_ts/cache/classes.cache.cleaner.js +0 -61
- package/dist_ts/cache/classes.cachedb.d.ts +0 -22
- package/dist_ts/cache/classes.cachedb.js +0 -58
- package/dist_ts/cache/documents/index.js +0 -3
- package/dist_ts/cache/index.d.ts +0 -7
- package/dist_ts/cache/index.js +0 -6
- package/ts/cache/classes.cachedb.ts +0 -72
- package/ts/cache/index.ts +0 -7
- /package/dist_ts/{cache → db}/documents/classes.cached.project.d.ts +0 -0
- /package/dist_ts/{cache → db}/documents/classes.cached.secret.d.ts +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { logger } from '../logging.js';
|
|
3
|
+
const requireEnv = (keyArg) => {
|
|
4
|
+
const value = process.env[keyArg];
|
|
5
|
+
if (!value) {
|
|
6
|
+
throw new Error(`GitOps requires ${keyArg} to be set and non-empty.`);
|
|
7
|
+
}
|
|
8
|
+
if (value.trim() !== value) {
|
|
9
|
+
throw new Error(`GitOps requires ${keyArg} to be canonical without surrounding whitespace.`);
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Reads the database binding from the process environment. There is no default and no
|
|
15
|
+
* embedded fallback: gitops keeps every durable record — connections, jobs, sync
|
|
16
|
+
* configuration, managed secrets, the action log and the provider caches — in this one
|
|
17
|
+
* database, so a missing binding has to stop startup rather than silently produce an
|
|
18
|
+
* instance that forgets everything it was told.
|
|
19
|
+
*/
|
|
20
|
+
export const readGitopsDbOptionsFromEnvironment = () => ({
|
|
21
|
+
mongoDbUrl: requireEnv('GITOPS_MONGODB_URL'),
|
|
22
|
+
// An explicitly set but empty name is a misconfiguration, not a request for the default.
|
|
23
|
+
mongoDbName: process.env.GITOPS_MONGODB_NAME === undefined ? 'gitops' : requireEnv('GITOPS_MONGODB_NAME'),
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* The single document database behind gitops.
|
|
27
|
+
*
|
|
28
|
+
* Every model binds its collection through `GitopsDb.getInstance().getDb()`, so the
|
|
29
|
+
* singleton is the only place that knows the connection. Tests construct it with an
|
|
30
|
+
* explicit binding to an isolated server; the application reads the binding from the
|
|
31
|
+
* environment.
|
|
32
|
+
*/
|
|
33
|
+
export class GitopsDb {
|
|
34
|
+
static instance = null;
|
|
35
|
+
smartdataDb = null;
|
|
36
|
+
options;
|
|
37
|
+
constructor(options) {
|
|
38
|
+
this.options = options;
|
|
39
|
+
}
|
|
40
|
+
static getInstance(options) {
|
|
41
|
+
if (!GitopsDb.instance) {
|
|
42
|
+
if (!options) {
|
|
43
|
+
throw new Error('GitopsDb has no instance yet — the first call must supply its options.');
|
|
44
|
+
}
|
|
45
|
+
GitopsDb.instance = new GitopsDb(options);
|
|
46
|
+
}
|
|
47
|
+
return GitopsDb.instance;
|
|
48
|
+
}
|
|
49
|
+
static resetInstance() {
|
|
50
|
+
GitopsDb.instance = null;
|
|
51
|
+
}
|
|
52
|
+
async start() {
|
|
53
|
+
logger.info('Connecting to the gitops database...');
|
|
54
|
+
const smartdataDb = new plugins.smartdata.SmartdataDb({
|
|
55
|
+
mongoDbUrl: this.options.mongoDbUrl,
|
|
56
|
+
mongoDbName: this.options.mongoDbName,
|
|
57
|
+
});
|
|
58
|
+
await smartdataDb.init();
|
|
59
|
+
this.smartdataDb = smartdataDb;
|
|
60
|
+
logger.success(`Connected to the gitops database (db: ${this.options.mongoDbName})`);
|
|
61
|
+
}
|
|
62
|
+
async stop() {
|
|
63
|
+
if (!this.smartdataDb)
|
|
64
|
+
return;
|
|
65
|
+
const smartdataDb = this.smartdataDb;
|
|
66
|
+
this.smartdataDb = null;
|
|
67
|
+
await smartdataDb.close();
|
|
68
|
+
logger.success('Disconnected from the gitops database');
|
|
69
|
+
}
|
|
70
|
+
getDb() {
|
|
71
|
+
if (!this.smartdataDb) {
|
|
72
|
+
throw new Error('GitopsDb not started. Call start() first.');
|
|
73
|
+
}
|
|
74
|
+
return this.smartdataDb;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5naXRvcHMtZGIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9kYi9jbGFzc2VzLmdpdG9wcy1kYi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBU3ZDLE1BQU0sVUFBVSxHQUFHLENBQUMsTUFBYyxFQUFVLEVBQUU7SUFDNUMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNsQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixNQUFNLDJCQUEyQixDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUNELElBQUksS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLEtBQUssRUFBRSxDQUFDO1FBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsbUJBQW1CLE1BQU0sa0RBQWtELENBQUMsQ0FBQztJQUMvRixDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDLENBQUM7QUFFRjs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSxrQ0FBa0MsR0FBRyxHQUFxQixFQUFFLENBQUMsQ0FBQztJQUN6RSxVQUFVLEVBQUUsVUFBVSxDQUFDLG9CQUFvQixDQUFDO0lBQzVDLHlGQUF5RjtJQUN6RixXQUFXLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLHFCQUFxQixDQUFDO0NBQzFHLENBQUMsQ0FBQztBQUVIOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLE9BQU8sUUFBUTtJQUNYLE1BQU0sQ0FBQyxRQUFRLEdBQW9CLElBQUksQ0FBQztJQUV4QyxXQUFXLEdBQXlDLElBQUksQ0FBQztJQUNoRCxPQUFPLENBQW1CO0lBRTNDLFlBQW9CLE9BQXlCO1FBQzNDLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO0lBQ3pCLENBQUM7SUFFRCxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQTBCO1FBQzNDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDdkIsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsd0VBQXdFLENBQUMsQ0FBQztZQUM1RixDQUFDO1lBQ0QsUUFBUSxDQUFDLFFBQVEsR0FBRyxJQUFJLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1QyxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUMsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFRCxNQUFNLENBQUMsYUFBYTtRQUNsQixRQUFRLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztJQUMzQixDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUs7UUFDVCxNQUFNLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxDQUFDLENBQUM7UUFDcEQsTUFBTSxXQUFXLEdBQUcsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQztZQUNwRCxVQUFVLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVO1lBQ25DLFdBQVcsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVc7U0FDdEMsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFDL0IsTUFBTSxDQUFDLE9BQU8sQ0FBQyx5Q0FBeUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZGLENBQUM7SUFFRCxLQUFLLENBQUMsSUFBSTtRQUNSLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVztZQUFFLE9BQU87UUFDOUIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQztRQUNyQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztRQUN4QixNQUFNLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMxQixNQUFNLENBQUMsT0FBTyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVELEtBQUs7UUFDSCxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkNBQTJDLENBQUMsQ0FBQztRQUMvRCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFCLENBQUMifQ==
|
|
@@ -33,13 +33,13 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
35
|
import * as plugins from '../../plugins.js';
|
|
36
|
-
import {
|
|
36
|
+
import { GitopsDb } from '../classes.gitops-db.js';
|
|
37
37
|
import { CachedDocument, TTL } from '../classes.cached.document.js';
|
|
38
38
|
/**
|
|
39
39
|
* Cached project data from git providers. TTL: 5 minutes.
|
|
40
40
|
*/
|
|
41
41
|
let CachedProject = (() => {
|
|
42
|
-
let _classDecorators = [plugins.smartdata.Collection(() =>
|
|
42
|
+
let _classDecorators = [plugins.smartdata.Collection(() => GitopsDb.getInstance().getDb())];
|
|
43
43
|
let _classDescriptor;
|
|
44
44
|
let _classExtraInitializers = [];
|
|
45
45
|
let _classThis;
|
|
@@ -98,4 +98,4 @@ let CachedProject = (() => {
|
|
|
98
98
|
return CachedProject = _classThis;
|
|
99
99
|
})();
|
|
100
100
|
export { CachedProject };
|
|
101
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
101
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jYWNoZWQucHJvamVjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL2RiL2RvY3VtZW50cy9jbGFzc2VzLmNhY2hlZC5wcm9qZWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsY0FBYyxFQUFFLEdBQUcsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRXBFOztHQUVHO0lBRVUsYUFBYTs0QkFEekIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDOzs7O3NCQUNoQyxjQUFjOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OzZCQUF0QixTQUFRLFdBQTZCOzs7OzhCQUM3RCxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRTt3Q0FHdkIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUU7dUNBR3hCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFO3NDQUd4QixPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRTt1Q0FHeEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUU7eUNBR3hCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFO1lBZHpCLHdKQUFPLEVBQUUsNkJBQUYsRUFBRSwrRUFBYztZQUd2QixzTEFBTyxZQUFZLDZCQUFaLFlBQVksbUdBQWM7WUFHakMsbUxBQU8sV0FBVyw2QkFBWCxXQUFXLGlHQUFjO1lBR2hDLGdMQUFPLFVBQVUsNkJBQVYsVUFBVSwrRkFBYztZQUcvQixtTEFBTyxXQUFXLDZCQUFYLFdBQVcsaUdBQWM7WUFHaEMseUxBQU8sYUFBYSw2QkFBYixhQUFhLHFHQUFjO1lBakJwQyw2S0F1QkM7OztZQXZCWSx1REFBYTs7UUFFakIsRUFBRSw2Q0FBVyxFQUFFLEVBQUM7UUFHaEIsWUFBWSx3R0FBVyxFQUFFLEdBQUM7UUFHMUIsV0FBVyxpSEFBVyxFQUFFLEdBQUM7UUFHekIsVUFBVSwrR0FBVyxFQUFFLEdBQUM7UUFHeEIsV0FBVywrR0FBVyxFQUFFLEdBQUM7UUFHekIsYUFBYSxrSEFBVyxFQUFFLEdBQUM7UUFFbEM7WUFDRSxLQUFLLEVBQUUsQ0FBQzs7WUFDUixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztTQUM1Qjs7OztTQXRCVSxhQUFhIn0=
|
|
@@ -33,13 +33,13 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
35
|
import * as plugins from '../../plugins.js';
|
|
36
|
-
import {
|
|
36
|
+
import { GitopsDb } from '../classes.gitops-db.js';
|
|
37
37
|
import { CachedDocument, TTL } from '../classes.cached.document.js';
|
|
38
38
|
/**
|
|
39
39
|
* Cached secret data from git providers. TTL: 24 hours.
|
|
40
40
|
*/
|
|
41
41
|
let CachedSecret = (() => {
|
|
42
|
-
let _classDecorators = [plugins.smartdata.Collection(() =>
|
|
42
|
+
let _classDecorators = [plugins.smartdata.Collection(() => GitopsDb.getInstance().getDb())];
|
|
43
43
|
let _classDescriptor;
|
|
44
44
|
let _classExtraInitializers = [];
|
|
45
45
|
let _classThis;
|
|
@@ -155,4 +155,4 @@ let CachedSecret = (() => {
|
|
|
155
155
|
return CachedSecret = _classThis;
|
|
156
156
|
})();
|
|
157
157
|
export { CachedSecret };
|
|
158
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
158
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jYWNoZWQuc2VjcmV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvZGIvZG9jdW1lbnRzL2NsYXNzZXMuY2FjaGVkLnNlY3JldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDbkQsT0FBTyxFQUFFLGNBQWMsRUFBRSxHQUFHLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUdwRTs7R0FFRztJQUVVLFlBQVk7NEJBRHhCLE9BQU8sQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxLQUFLLEVBQUUsQ0FBQzs7OztzQkFDakMsY0FBYzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs0QkFBdEIsU0FBUSxXQUE0Qjs7Ozs4QkFDM0QsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7d0NBR3ZCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFO2lDQUd4QixPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRTttQ0FHeEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUU7cUNBR3hCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFOytCQUd4QixPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRTtpQ0FHeEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUU7cUNBR3hCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFO2tDQUd4QixPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRTt1Q0FHeEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUU7WUExQnpCLHdKQUFPLEVBQUUsNkJBQUYsRUFBRSwr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
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* One durable key/value record.
|
|
4
|
+
*
|
|
5
|
+
* `key` owns the stored `_id`, so the primary key is the single uniqueness authority: a
|
|
6
|
+
* write is one identity-anchored upsert with no second index to disagree with, and a
|
|
7
|
+
* prefix listing is answered by the `_id` index instead of a collection scan. That is what
|
|
8
|
+
* `identityAsDocumentId: 'key'` declares, and it holds for every record this collection
|
|
9
|
+
* ever received, because the store below has always derived `_id` from the key.
|
|
10
|
+
*/
|
|
11
|
+
export declare class StorageRecord extends plugins.smartdata.SmartDataDbDoc<StorageRecord, StorageRecord> {
|
|
12
|
+
key: string;
|
|
13
|
+
value: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
import * as plugins from '../../plugins.js';
|
|
36
|
+
import { GitopsDb } from '../classes.gitops-db.js';
|
|
37
|
+
const getDb = () => GitopsDb.getInstance().getDb();
|
|
38
|
+
/**
|
|
39
|
+
* One durable key/value record.
|
|
40
|
+
*
|
|
41
|
+
* `key` owns the stored `_id`, so the primary key is the single uniqueness authority: a
|
|
42
|
+
* write is one identity-anchored upsert with no second index to disagree with, and a
|
|
43
|
+
* prefix listing is answered by the `_id` index instead of a collection scan. That is what
|
|
44
|
+
* `identityAsDocumentId: 'key'` declares, and it holds for every record this collection
|
|
45
|
+
* ever received, because the store below has always derived `_id` from the key.
|
|
46
|
+
*/
|
|
47
|
+
let StorageRecord = (() => {
|
|
48
|
+
let _classDecorators = [plugins.smartdata.Collection(() => getDb(), { identityAsDocumentId: 'key' })];
|
|
49
|
+
let _classDescriptor;
|
|
50
|
+
let _classExtraInitializers = [];
|
|
51
|
+
let _classThis;
|
|
52
|
+
let _classSuper = plugins.smartdata.SmartDataDbDoc;
|
|
53
|
+
let _key_decorators;
|
|
54
|
+
let _key_initializers = [];
|
|
55
|
+
let _key_extraInitializers = [];
|
|
56
|
+
let _value_decorators;
|
|
57
|
+
let _value_initializers = [];
|
|
58
|
+
let _value_extraInitializers = [];
|
|
59
|
+
var StorageRecord = class extends _classSuper {
|
|
60
|
+
static { _classThis = this; }
|
|
61
|
+
static {
|
|
62
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
63
|
+
_key_decorators = [plugins.smartdata.unI(), plugins.smartdata.svDb()];
|
|
64
|
+
_value_decorators = [plugins.smartdata.svDb()];
|
|
65
|
+
__esDecorate(null, null, _key_decorators, { kind: "field", name: "key", static: false, private: false, access: { has: obj => "key" in obj, get: obj => obj.key, set: (obj, value) => { obj.key = value; } }, metadata: _metadata }, _key_initializers, _key_extraInitializers);
|
|
66
|
+
__esDecorate(null, null, _value_decorators, { kind: "field", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
|
|
67
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
68
|
+
StorageRecord = _classThis = _classDescriptor.value;
|
|
69
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
70
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
71
|
+
}
|
|
72
|
+
key = __runInitializers(this, _key_initializers, void 0);
|
|
73
|
+
value = (__runInitializers(this, _key_extraInitializers), __runInitializers(this, _value_initializers, void 0));
|
|
74
|
+
constructor() {
|
|
75
|
+
super(...arguments);
|
|
76
|
+
__runInitializers(this, _value_extraInitializers);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
return StorageRecord = _classThis;
|
|
80
|
+
})();
|
|
81
|
+
export { StorageRecord };
|
|
82
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zdG9yYWdlLnJlY29yZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL2RiL2RvY3VtZW50cy9jbGFzc2VzLnN0b3JhZ2UucmVjb3JkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVuRCxNQUFNLEtBQUssR0FBRyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7QUFFbkQ7Ozs7Ozs7O0dBUUc7SUFFVSxhQUFhOzRCQUR6QixPQUFPLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLG9CQUFvQixFQUFFLEtBQUssRUFBRSxDQUFDOzs7O3NCQUMxQyxPQUFPLENBQUMsU0FBUyxDQUFDLGNBQWM7Ozs7Ozs7NkJBQXhDLFNBQVEsV0FHbEM7Ozs7K0JBQ0UsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsRUFDdkIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUU7aUNBR3hCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFO1lBRnpCLDJKQUFPLEdBQUcsNkJBQUgsR0FBRyxpRkFBVTtZQUdwQixpS0FBTyxLQUFLLDZCQUFMLEtBQUsscUZBQVU7WUFUeEIsNktBVUM7OztZQVZZLHVEQUFhOztRQU1qQixHQUFHLHNEQUFVO1FBR2IsS0FBSywyR0FBVTs7Ozs7Ozs7U0FUWCxhQUFhIn0=
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { CachedProject } from './classes.cached.project.js';
|
|
2
|
+
export { CachedSecret } from './classes.cached.secret.js';
|
|
3
|
+
export { StorageRecord } from './classes.storage.record.js';
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9kYi9kb2N1bWVudHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzVELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sNkJBQTZCLENBQUMifQ==
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { GitopsDb, readGitopsDbOptionsFromEnvironment } from './classes.gitops-db.js';
|
|
2
|
+
export type { IGitopsDbOptions } from './classes.gitops-db.js';
|
|
3
|
+
export { CachedDocument, TTL } from './classes.cached.document.js';
|
|
4
|
+
export { CacheCleaner } from './classes.cache.cleaner.js';
|
|
5
|
+
export * from './documents/index.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { GitopsDb, readGitopsDbOptionsFromEnvironment } from './classes.gitops-db.js';
|
|
2
|
+
export { CachedDocument, TTL } from './classes.cached.document.js';
|
|
3
|
+
export { CacheCleaner } from './classes.cache.cleaner.js';
|
|
4
|
+
export * from './documents/index.js';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9kYi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLGtDQUFrQyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFdEYsT0FBTyxFQUFFLGNBQWMsRUFBRSxHQUFHLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNuRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDMUQsY0FBYyxzQkFBc0IsQ0FBQyJ9
|
package/dist_ts/paths.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface IGitopsPaths {
|
|
2
2
|
gitopsHomeDir: string;
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/** Directory the releases before the document database wrote key/value records into. */
|
|
4
|
+
legacyStoragePath: string;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Resolve gitops paths. Accepts optional baseDir for test isolation.
|
package/dist_ts/paths.js
CHANGED
|
@@ -6,8 +6,7 @@ export function resolvePaths(baseDir) {
|
|
|
6
6
|
const home = baseDir ?? plugins.path.join(process.env.HOME ?? '/tmp', '.serve.zone', 'gitops');
|
|
7
7
|
return {
|
|
8
8
|
gitopsHomeDir: home,
|
|
9
|
-
|
|
10
|
-
defaultTsmDbPath: plugins.path.join(home, 'tsmdb'),
|
|
9
|
+
legacyStoragePath: plugins.path.join(home, 'storage'),
|
|
11
10
|
};
|
|
12
11
|
}
|
|
13
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9wYXRocy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQVF4Qzs7R0FFRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsT0FBZ0I7SUFDM0MsTUFBTSxJQUFJLEdBQUcsT0FBTyxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLE1BQU0sRUFBRSxhQUFhLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDL0YsT0FBTztRQUNMLGFBQWEsRUFBRSxJQUFJO1FBQ25CLGlCQUFpQixFQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxTQUFTLENBQUM7S0FDdEQsQ0FBQztBQUNKLENBQUMifQ==
|
package/dist_ts/plugins.d.ts
CHANGED
|
@@ -19,8 +19,7 @@ import * as giteaClient from '@apiclient.xyz/gitea';
|
|
|
19
19
|
import * as gitlabClient from '@apiclient.xyz/gitlab';
|
|
20
20
|
import * as bookstackClient from '@apiclient.xyz/bookstack';
|
|
21
21
|
export { giteaClient, gitlabClient, bookstackClient };
|
|
22
|
-
import * as
|
|
23
|
-
|
|
24
|
-
export { smartmongo, smartdata };
|
|
22
|
+
import * as smartdata from '@lossless.org/client/nosqldb';
|
|
23
|
+
export { smartdata };
|
|
25
24
|
import * as smartsecret from '@push.rocks/smartsecret';
|
|
26
25
|
export { smartsecret };
|
package/dist_ts/plugins.js
CHANGED
|
@@ -24,10 +24,12 @@ import * as gitlabClient from '@apiclient.xyz/gitlab';
|
|
|
24
24
|
import * as bookstackClient from '@apiclient.xyz/bookstack';
|
|
25
25
|
export { giteaClient, gitlabClient, bookstackClient };
|
|
26
26
|
// Database
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
// The document ORM. Exported as `smartdata` because that is the name every call site uses and
|
|
28
|
+
// because `@lossless.org/client/nosqldb` supersedes `@push.rocks/smartdata` with an identical
|
|
29
|
+
// API surface; the persisted shape is unchanged.
|
|
30
|
+
import * as smartdata from '@lossless.org/client/nosqldb';
|
|
31
|
+
export { smartdata };
|
|
30
32
|
// Secrets
|
|
31
33
|
import * as smartsecret from '@push.rocks/smartsecret';
|
|
32
34
|
export { smartsecret };
|
|
33
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
35
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3BsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLElBQUksTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN2QyxPQUFPLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUM5QixPQUFPLEtBQUssT0FBTyxNQUFNLFVBQVUsQ0FBQztBQUNwQyxPQUFPLEtBQUssWUFBWSxNQUFNLG9CQUFvQixDQUFDO0FBQ25ELE9BQU8sS0FBSyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFckMsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFDO0FBRS9ELDBDQUEwQztBQUMxQyxPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUVyQyxnQkFBZ0I7QUFDaEIsT0FBTyxLQUFLLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRCxPQUFPLEtBQUssUUFBUSxNQUFNLHNCQUFzQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLENBQUM7QUFFaEMsY0FBYztBQUNkLE9BQU8sS0FBSyxXQUFXLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxLQUFLLFlBQVksTUFBTSx1QkFBdUIsQ0FBQztBQUN0RCxPQUFPLEtBQUssZUFBZSxNQUFNLDBCQUEwQixDQUFDO0FBQzVELE9BQU8sRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxDQUFDO0FBRXRELFdBQVc7QUFDWCw4RkFBOEY7QUFDOUYsOEZBQThGO0FBQzlGLGlEQUFpRDtBQUNqRCxPQUFPLEtBQUssU0FBUyxNQUFNLDhCQUE4QixDQUFDO0FBQzFELE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQztBQUVyQixVQUFVO0FBQ1YsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsV0FBVyxFQUFFLENBQUMifQ==
|
|
@@ -1,31 +1,22 @@
|
|
|
1
|
-
export type TStorageBackend = 'filesystem' | 'memory';
|
|
2
|
-
export interface IStorageConfig {
|
|
3
|
-
backend?: TStorageBackend;
|
|
4
|
-
fsPath?: string;
|
|
5
|
-
}
|
|
6
1
|
/**
|
|
7
|
-
* Key-value storage
|
|
8
|
-
*
|
|
2
|
+
* Key-value storage for gitops' durable records, kept in the `StorageRecord` collection.
|
|
3
|
+
*
|
|
4
|
+
* Keys must start with '/' and are normalized (no '..', no double slashes). Listing is
|
|
5
|
+
* non-recursive: it returns the direct children of a prefix, which is what every caller
|
|
6
|
+
* relies on to keep neighbouring key spaces apart.
|
|
9
7
|
*/
|
|
10
8
|
export declare class StorageManager {
|
|
11
|
-
private backend;
|
|
12
|
-
private fsPath;
|
|
13
|
-
private memoryStore;
|
|
14
|
-
constructor(config?: IStorageConfig);
|
|
15
9
|
/**
|
|
16
10
|
* Normalize and validate a storage key.
|
|
17
11
|
*/
|
|
18
12
|
private normalizeKey;
|
|
19
|
-
/**
|
|
20
|
-
* Resolve a key to a filesystem path.
|
|
21
|
-
*/
|
|
22
|
-
private keyToPath;
|
|
23
13
|
get(key: string): Promise<string | null>;
|
|
24
14
|
set(key: string, value: string): Promise<void>;
|
|
25
15
|
delete(key: string): Promise<boolean>;
|
|
26
16
|
exists(key: string): Promise<boolean>;
|
|
27
17
|
/**
|
|
28
|
-
* List keys
|
|
18
|
+
* List the keys directly below a given prefix. Records deeper in the subtree are read by
|
|
19
|
+
* the range scan and then dropped, mirroring the directory listing this replaced.
|
|
29
20
|
*/
|
|
30
21
|
list(prefix: string): Promise<string[]>;
|
|
31
22
|
getJSON<T>(key: string): Promise<T | null>;
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
const isNotFoundError = (error) => {
|
|
3
|
-
return error instanceof Error && error.code === 'ENOENT';
|
|
4
|
-
};
|
|
1
|
+
import { StorageRecord } from '../db/documents/classes.storage.record.js';
|
|
5
2
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
* The upper bound of the key range scanned for a prefix listing. `` is above every
|
|
4
|
+
* character a normalized key may contain, so `[prefix/, prefix/)` covers the whole
|
|
5
|
+
* subtree of a prefix and nothing beyond it.
|
|
6
|
+
*/
|
|
7
|
+
const KEY_RANGE_END = '';
|
|
8
|
+
/**
|
|
9
|
+
* The key is the record's primary key, and MongoDB indexes a primary key of at most
|
|
10
|
+
* 1024 bytes; the bound is stated here so an oversized key is refused by name instead of
|
|
11
|
+
* surfacing as a driver index error on write.
|
|
12
|
+
*/
|
|
13
|
+
const MAX_KEY_BYTES = 1024;
|
|
14
|
+
/**
|
|
15
|
+
* Key-value storage for gitops' durable records, kept in the `StorageRecord` collection.
|
|
16
|
+
*
|
|
17
|
+
* Keys must start with '/' and are normalized (no '..', no double slashes). Listing is
|
|
18
|
+
* non-recursive: it returns the direct children of a prefix, which is what every caller
|
|
19
|
+
* relies on to keep neighbouring key spaces apart.
|
|
8
20
|
*/
|
|
9
21
|
export class StorageManager {
|
|
10
|
-
backend;
|
|
11
|
-
fsPath;
|
|
12
|
-
memoryStore;
|
|
13
|
-
constructor(config = {}) {
|
|
14
|
-
this.backend = config.backend ?? 'filesystem';
|
|
15
|
-
this.fsPath = config.fsPath ?? './storage';
|
|
16
|
-
this.memoryStore = new Map();
|
|
17
|
-
}
|
|
18
22
|
/**
|
|
19
23
|
* Normalize and validate a storage key.
|
|
20
24
|
*/
|
|
@@ -24,103 +28,59 @@ export class StorageManager {
|
|
|
24
28
|
}
|
|
25
29
|
// Strip '..' segments and normalize double slashes
|
|
26
30
|
const segments = key.split('/').filter((s) => s !== '' && s !== '..');
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
keyToPath(key) {
|
|
33
|
-
const normalized = this.normalizeKey(key);
|
|
34
|
-
return plugins.path.join(this.fsPath, ...normalized.split('/').filter(Boolean));
|
|
31
|
+
const normalized = '/' + segments.join('/');
|
|
32
|
+
if (Buffer.byteLength(normalized, 'utf8') > MAX_KEY_BYTES) {
|
|
33
|
+
throw new Error(`Storage key exceeds ${MAX_KEY_BYTES} bytes: ${normalized.slice(0, 64)}…`);
|
|
34
|
+
}
|
|
35
|
+
return normalized;
|
|
35
36
|
}
|
|
36
37
|
async get(key) {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
return await plugins.fs.readFile(this.keyToPath(normalized), 'utf8');
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
if (isNotFoundError(err))
|
|
46
|
-
return null;
|
|
47
|
-
throw err;
|
|
48
|
-
}
|
|
38
|
+
const record = await StorageRecord.getInstance({
|
|
39
|
+
key: this.normalizeKey(key),
|
|
40
|
+
});
|
|
41
|
+
return record ? record.value : null;
|
|
49
42
|
}
|
|
50
43
|
async set(key, value) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
const filePath = this.keyToPath(normalized);
|
|
57
|
-
const dir = plugins.path.dirname(filePath);
|
|
58
|
-
await plugins.fs.mkdir(dir, { recursive: true });
|
|
59
|
-
// Atomic write: write to temp then rename
|
|
60
|
-
const tmpPath = filePath + '.tmp';
|
|
61
|
-
await plugins.fs.writeFile(tmpPath, value, 'utf8');
|
|
62
|
-
await plugins.fs.rename(tmpPath, filePath);
|
|
44
|
+
// The equality anchor on `key` is what makes this a single race-free upsert: the
|
|
45
|
+
// primary key is derived from the filter, and the client seeds the immutable identity
|
|
46
|
+
// from that same anchor, so the key is never restated in the update document.
|
|
47
|
+
await StorageRecord.atomicUpdate({ key: this.normalizeKey(key) }, { $set: { value } }, { upsert: true });
|
|
63
48
|
}
|
|
64
49
|
async delete(key) {
|
|
65
50
|
const normalized = this.normalizeKey(key);
|
|
66
|
-
if (
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
try {
|
|
70
|
-
await plugins.fs.rm(this.keyToPath(normalized));
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
catch (err) {
|
|
74
|
-
if (isNotFoundError(err))
|
|
75
|
-
return false;
|
|
76
|
-
throw err;
|
|
51
|
+
if (!(await StorageRecord.exists({ key: normalized }))) {
|
|
52
|
+
return false;
|
|
77
53
|
}
|
|
54
|
+
// The identity pins a single document, which is what a singular delete requires.
|
|
55
|
+
await StorageRecord.atomicDelete({ key: normalized });
|
|
56
|
+
return true;
|
|
78
57
|
}
|
|
79
58
|
async exists(key) {
|
|
80
|
-
|
|
81
|
-
if (this.backend === 'memory') {
|
|
82
|
-
return this.memoryStore.has(normalized);
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
await plugins.fs.stat(this.keyToPath(normalized));
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
catch (err) {
|
|
89
|
-
if (isNotFoundError(err))
|
|
90
|
-
return false;
|
|
91
|
-
throw err;
|
|
92
|
-
}
|
|
59
|
+
return StorageRecord.exists({ key: this.normalizeKey(key) });
|
|
93
60
|
}
|
|
94
61
|
/**
|
|
95
|
-
* List keys
|
|
62
|
+
* List the keys directly below a given prefix. Records deeper in the subtree are read by
|
|
63
|
+
* the range scan and then dropped, mirroring the directory listing this replaced.
|
|
96
64
|
*/
|
|
97
65
|
async list(prefix) {
|
|
98
66
|
const normalized = this.normalizeKey(prefix);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return keys.sort();
|
|
107
|
-
}
|
|
108
|
-
const dirPath = this.keyToPath(normalized);
|
|
109
|
-
const keys = [];
|
|
67
|
+
// Normalization leaves the root as '/', which is already its own child prefix.
|
|
68
|
+
const childPrefix = normalized.endsWith('/') ? normalized : `${normalized}/`;
|
|
69
|
+
const cursor = await StorageRecord.getCursor({ key: { $gte: childPrefix, $lt: `${childPrefix}${KEY_RANGE_END}` } },
|
|
70
|
+
// Only the keys are wanted here; leaving the values in the database keeps a listing
|
|
71
|
+
// independent of how much each record holds.
|
|
72
|
+
{ projection: { key: 1 } });
|
|
73
|
+
let records;
|
|
110
74
|
try {
|
|
111
|
-
|
|
112
|
-
for (const entry of entries) {
|
|
113
|
-
if (entry.isFile()) {
|
|
114
|
-
keys.push(normalized.replace(/\/$/, '') + '/' + entry.name);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
75
|
+
records = await cursor.toArray();
|
|
117
76
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return [];
|
|
121
|
-
throw err;
|
|
77
|
+
finally {
|
|
78
|
+
await cursor.close();
|
|
122
79
|
}
|
|
123
|
-
return
|
|
80
|
+
return records
|
|
81
|
+
.map((recordArg) => recordArg.key)
|
|
82
|
+
.filter((keyArg) => !keyArg.slice(childPrefix.length).includes('/'))
|
|
83
|
+
.sort();
|
|
124
84
|
}
|
|
125
85
|
async getJSON(key) {
|
|
126
86
|
const raw = await this.get(key);
|
|
@@ -132,4 +92,4 @@ export class StorageManager {
|
|
|
132
92
|
await this.set(key, JSON.stringify(value, null, 2));
|
|
133
93
|
}
|
|
134
94
|
}
|
|
135
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
95
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zdG9yYWdlbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3N0b3JhZ2UvY2xhc3Nlcy5zdG9yYWdlbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFFMUU7Ozs7R0FJRztBQUNILE1BQU0sYUFBYSxHQUFHLEdBQUcsQ0FBQztBQUUxQjs7OztHQUlHO0FBQ0gsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDO0FBRTNCOzs7Ozs7R0FNRztBQUNILE1BQU0sT0FBTyxjQUFjO0lBQ3pCOztPQUVHO0lBQ0ssWUFBWSxDQUFDLEdBQVc7UUFDOUIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQzdELENBQUM7UUFDRCxtREFBbUQ7UUFDbkQsTUFBTSxRQUFRLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFDO1FBQ3RFLE1BQU0sVUFBVSxHQUFHLEdBQUcsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzVDLElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLEdBQUcsYUFBYSxFQUFFLENBQUM7WUFDMUQsTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsYUFBYSxXQUFXLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM3RixDQUFDO1FBQ0QsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUVELEtBQUss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
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as plugins from '../dist_ts/plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* The ledger of migrations that have run to completion.
|
|
4
|
+
*
|
|
5
|
+
* `migration` owns the stored `_id`, so a migration is looked up by primary key and can
|
|
6
|
+
* only ever be recorded once.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MigrationRecord extends plugins.smartdata.SmartDataDbDoc<MigrationRecord, MigrationRecord> {
|
|
9
|
+
migration: string;
|
|
10
|
+
completedAt: number;
|
|
11
|
+
}
|