@dereekb/dbx-cli 14.1.0 → 14.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/eslint/index.esm.js +0 -195
- package/eslint/package.json +4 -3
- package/firebase-api-manifest/main.js +124 -13
- package/firebase-api-manifest/package.json +4 -3
- package/firestore-query-manifest/main.js +4 -3
- package/firestore-query-manifest/package.json +4 -3
- package/generate-firestore-indexes/main.js +3 -2
- package/generate-firestore-indexes/package.json +3 -2
- package/generate-mcp-manifest/package.json +4 -3
- package/generate-route-manifest/package.json +3 -2
- package/index.esm.js +3036 -881
- package/lint-cache/package.json +3 -2
- package/manifest-extract/index.esm.js +113 -7
- package/manifest-extract/package.json +8 -8
- package/manifest-extract/src/lib/types.d.ts +10 -0
- package/model-test/package.json +2 -2
- package/package.json +6 -6
- package/route/package.json +7 -7
- package/src/lib/cache/cache.command.factory.d.ts +44 -0
- package/src/lib/cache/data-cache.codec.d.ts +36 -0
- package/src/lib/cache/data-cache.d.ts +272 -0
- package/src/lib/cache/data-cache.fingerprint.d.ts +109 -0
- package/src/lib/cache/data-cache.options.d.ts +98 -0
- package/src/lib/cache/index.d.ts +5 -0
- package/src/lib/config/paths.d.ts +11 -1
- package/src/lib/firestore/firestore-query.command.d.ts +25 -1
- package/src/lib/index.d.ts +1 -0
- package/src/lib/runner/run.d.ts +11 -0
- package/test/package.json +10 -9
- package/validate/package.json +3 -3
package/lint-cache/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli-lint-cache",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.0",
|
|
4
|
+
"sideEffects": false,
|
|
4
5
|
"private": true,
|
|
5
6
|
"type": "module",
|
|
6
7
|
"devDependencies": {
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
"eslint": "10.9.1"
|
|
9
10
|
},
|
|
10
11
|
"peerDependencies": {
|
|
11
|
-
"@dereekb/util": "14.
|
|
12
|
+
"@dereekb/util": "14.2.0",
|
|
12
13
|
"yargs": "^18.0.0"
|
|
13
14
|
}
|
|
14
15
|
}
|
|
@@ -696,6 +696,10 @@ var MCP_TOOL_NAME_SEGMENT_TAG = 'dbxModelMcpToolNameSegment';
|
|
|
696
696
|
var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
|
|
697
697
|
var TOOL_NAME_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_$]*$/;
|
|
698
698
|
var IDENTITY_FN = 'firestoreModelIdentity';
|
|
699
|
+
// the declared-type counterparts of IDENTITY_FN, which is all a .d.ts retains of the call
|
|
700
|
+
var IDENTITY_TYPE = 'FirestoreModelIdentity';
|
|
701
|
+
var ROOT_IDENTITY_TYPE = 'RootFirestoreModelIdentity';
|
|
702
|
+
var IDENTITY_WITH_PARENT_TYPE = 'FirestoreModelIdentityWithParent';
|
|
699
703
|
var SINGLE_ITEM_COLLECTION_FN = 'singleItemFirestoreCollection';
|
|
700
704
|
var ROOT_SINGLE_ITEM_COLLECTION_FN = 'rootSingleItemFirestoreCollection';
|
|
701
705
|
var SINGLE_ITEM_COLLECTION_FN_NAMES = [
|
|
@@ -763,13 +767,25 @@ function readIdentities(sourceFile) {
|
|
|
763
767
|
for(var _iterator1 = statement.getDeclarations()[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
|
|
764
768
|
var decl = _step1.value;
|
|
765
769
|
var initializer = decl.getInitializer();
|
|
766
|
-
if (
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
770
|
+
if (initializer && Node.isCallExpression(initializer)) {
|
|
771
|
+
if (initializer.getExpression().getText() !== IDENTITY_FN) continue;
|
|
772
|
+
var parsed = parseFirestoreModelIdentityArgs(initializer.getArguments());
|
|
773
|
+
if (parsed) {
|
|
774
|
+
out.push(_object_spread_props(_object_spread({
|
|
775
|
+
identityConst: decl.getName()
|
|
776
|
+
}, parsed), {
|
|
777
|
+
parentModelType: undefined
|
|
778
|
+
}));
|
|
779
|
+
}
|
|
780
|
+
} else {
|
|
781
|
+
// A declaration file has no initializer to read — the identity survives only in the declared
|
|
782
|
+
// type, which is the whole reason a node_modules-installed package can contribute models at all.
|
|
783
|
+
var parsed1 = parseDeclaredIdentityType(decl.getTypeNode());
|
|
784
|
+
if (parsed1) {
|
|
785
|
+
out.push(_object_spread({
|
|
786
|
+
identityConst: decl.getName()
|
|
787
|
+
}, parsed1));
|
|
788
|
+
}
|
|
773
789
|
}
|
|
774
790
|
}
|
|
775
791
|
} catch (err) {
|
|
@@ -803,6 +819,96 @@ function readIdentities(sourceFile) {
|
|
|
803
819
|
}
|
|
804
820
|
return out;
|
|
805
821
|
}
|
|
822
|
+
/**
|
|
823
|
+
* Reads an identity out of the DECLARED TYPE of an initializer-less export.
|
|
824
|
+
*
|
|
825
|
+
* The three shapes `@dereekb/firebase` declares, after a `.d.ts` rewrites every import as an inline
|
|
826
|
+
* `import("…").` qualifier:
|
|
827
|
+
*
|
|
828
|
+
* - `RootFirestoreModelIdentity<"worker", "wk">`
|
|
829
|
+
* - `FirestoreModelIdentity<"worker", "wk">`
|
|
830
|
+
* - `FirestoreModelIdentityWithParent<RootFirestoreModelIdentity<"prompt", "orp">, "version", "orpv">`
|
|
831
|
+
*
|
|
832
|
+
* @param typeNode - The declared type node, when the declaration carries one.
|
|
833
|
+
* @returns The identity parts, or undefined when the type is not one of the identity shapes.
|
|
834
|
+
*/ function parseDeclaredIdentityType(typeNode) {
|
|
835
|
+
var result;
|
|
836
|
+
var named = readNamedTypeNode(typeNode);
|
|
837
|
+
if (named) {
|
|
838
|
+
var typeName = named.typeName, args = named.args;
|
|
839
|
+
if (typeName === IDENTITY_WITH_PARENT_TYPE && args.length >= 3) {
|
|
840
|
+
var _readLiteralTypeText;
|
|
841
|
+
var parent = parseDeclaredIdentityType(args[0]);
|
|
842
|
+
result = {
|
|
843
|
+
modelType: (_readLiteralTypeText = readLiteralTypeText(args[1])) !== null && _readLiteralTypeText !== void 0 ? _readLiteralTypeText : '',
|
|
844
|
+
collectionPrefix: readLiteralTypeText(args[2]),
|
|
845
|
+
parentIdentityConst: undefined,
|
|
846
|
+
parentModelType: parent === null || parent === void 0 ? void 0 : parent.modelType
|
|
847
|
+
};
|
|
848
|
+
} else if ((typeName === ROOT_IDENTITY_TYPE || typeName === IDENTITY_TYPE) && args.length >= 2) {
|
|
849
|
+
var _readLiteralTypeText1;
|
|
850
|
+
result = {
|
|
851
|
+
modelType: (_readLiteralTypeText1 = readLiteralTypeText(args[0])) !== null && _readLiteralTypeText1 !== void 0 ? _readLiteralTypeText1 : '',
|
|
852
|
+
collectionPrefix: readLiteralTypeText(args[1]),
|
|
853
|
+
parentIdentityConst: undefined,
|
|
854
|
+
parentModelType: undefined
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
// a default-parameterized identity carries no literals, so it names no model
|
|
858
|
+
if (result && !result.modelType) {
|
|
859
|
+
result = undefined;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
return result;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Normalizes a type node to its name and type arguments.
|
|
866
|
+
*
|
|
867
|
+
* Two shapes, because a `.d.ts` does not write the one the source did: source that imported the type
|
|
868
|
+
* normally leaves a `TypeReference` (`RootFirestoreModelIdentity<…>`), while a declaration file inlines
|
|
869
|
+
* the import and leaves an `ImportType` (`import("@dereekb/firebase").RootFirestoreModelIdentity<…>`),
|
|
870
|
+
* whose name is its QUALIFIER rather than its type name. Reading only the first is what made a
|
|
871
|
+
* declaration-sourced identity invisible.
|
|
872
|
+
*
|
|
873
|
+
* @param typeNode - The type node to read.
|
|
874
|
+
* @returns The unqualified type name and its type arguments, or undefined when the node is neither shape.
|
|
875
|
+
*/ function readNamedTypeNode(typeNode) {
|
|
876
|
+
var result;
|
|
877
|
+
if (typeNode) {
|
|
878
|
+
if (Node.isImportTypeNode(typeNode)) {
|
|
879
|
+
var qualifier = typeNode.getQualifier();
|
|
880
|
+
if (qualifier) {
|
|
881
|
+
var _qualifier_getText_split_pop;
|
|
882
|
+
result = {
|
|
883
|
+
typeName: (_qualifier_getText_split_pop = qualifier.getText().split('.').pop()) !== null && _qualifier_getText_split_pop !== void 0 ? _qualifier_getText_split_pop : '',
|
|
884
|
+
args: typeNode.getTypeArguments()
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
} else if (Node.isTypeReference(typeNode)) {
|
|
888
|
+
var _typeNode_getTypeName_getText_split_pop;
|
|
889
|
+
result = {
|
|
890
|
+
typeName: (_typeNode_getTypeName_getText_split_pop = typeNode.getTypeName().getText().split('.').pop()) !== null && _typeNode_getTypeName_getText_split_pop !== void 0 ? _typeNode_getTypeName_getText_split_pop : '',
|
|
891
|
+
args: typeNode.getTypeArguments()
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return result;
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Reads the text of a string-literal type node (`"wk"` → `wk`).
|
|
899
|
+
*
|
|
900
|
+
* @param node - The type node to read.
|
|
901
|
+
* @returns The literal's text, or undefined when the node is not a string literal type.
|
|
902
|
+
*/ function readLiteralTypeText(node) {
|
|
903
|
+
var result;
|
|
904
|
+
if (node && Node.isLiteralTypeNode(node)) {
|
|
905
|
+
var literal = node.getLiteral();
|
|
906
|
+
if (Node.isStringLiteral(literal)) {
|
|
907
|
+
result = literal.getLiteralText();
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
return result;
|
|
911
|
+
}
|
|
806
912
|
function readInterfaces(sourceFile) {
|
|
807
913
|
var out = [];
|
|
808
914
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli/manifest-extract",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"peerDependencies": {
|
|
7
|
-
"@dereekb/date": "14.
|
|
8
|
-
"@dereekb/dbx-cli": "14.
|
|
9
|
-
"@dereekb/firebase": "14.
|
|
10
|
-
"@dereekb/model": "14.
|
|
11
|
-
"@dereekb/nestjs": "14.
|
|
12
|
-
"@dereekb/rxjs": "14.
|
|
13
|
-
"@dereekb/util": "14.
|
|
7
|
+
"@dereekb/date": "14.2.0",
|
|
8
|
+
"@dereekb/dbx-cli": "14.2.0",
|
|
9
|
+
"@dereekb/firebase": "14.2.0",
|
|
10
|
+
"@dereekb/model": "14.2.0",
|
|
11
|
+
"@dereekb/nestjs": "14.2.0",
|
|
12
|
+
"@dereekb/rxjs": "14.2.0",
|
|
13
|
+
"@dereekb/util": "14.2.0",
|
|
14
14
|
"ts-morph": "^28.0.0"
|
|
15
15
|
},
|
|
16
16
|
"exports": {
|
|
@@ -119,6 +119,16 @@ export interface ModelExtractionIdentity {
|
|
|
119
119
|
readonly modelType: string;
|
|
120
120
|
readonly collectionPrefix: string | undefined;
|
|
121
121
|
readonly parentIdentityConst: string | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Model type of the parent, when the identity was read from a DECLARATION rather than a call.
|
|
124
|
+
*
|
|
125
|
+
* A `.d.ts` spells the parent as an inline type (`FirestoreModelIdentityWithParent<
|
|
126
|
+
* RootFirestoreModelIdentity<"openRouterPrompt", "orp">, …>`) rather than by naming the const the
|
|
127
|
+
* source called `firestoreModelIdentity` with, so the const name the parent chain is walked by is not
|
|
128
|
+
* present to read. The model type is, and it identifies the same parent — the orchestrator resolves
|
|
129
|
+
* one to the other against the global identity registry.
|
|
130
|
+
*/
|
|
131
|
+
readonly parentModelType: string | undefined;
|
|
122
132
|
}
|
|
123
133
|
/**
|
|
124
134
|
* One property on a `@dbxModel`-tagged interface.
|
package/model-test/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli/model-test",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"peerDependencies": {
|
|
7
|
-
"@dereekb/util": "14.
|
|
7
|
+
"@dereekb/util": "14.2.0",
|
|
8
8
|
"ts-morph": "^28.0.0"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"bin": {
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@dereekb/date": "14.
|
|
70
|
-
"@dereekb/firebase": "14.
|
|
71
|
-
"@dereekb/model": "14.
|
|
72
|
-
"@dereekb/nestjs": "14.
|
|
73
|
-
"@dereekb/util": "14.
|
|
69
|
+
"@dereekb/date": "14.2.0",
|
|
70
|
+
"@dereekb/firebase": "14.2.0",
|
|
71
|
+
"@dereekb/model": "14.2.0",
|
|
72
|
+
"@dereekb/nestjs": "14.2.0",
|
|
73
|
+
"@dereekb/util": "14.2.0",
|
|
74
74
|
"@nestjs/common": "^12.0.1",
|
|
75
75
|
"arktype": "^2.2.0",
|
|
76
76
|
"firebase": "^12.18.0",
|
package/route/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/dbx-cli/route",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"peerDependencies": {
|
|
7
|
-
"@dereekb/date": "14.
|
|
8
|
-
"@dereekb/dbx-cli": "14.
|
|
9
|
-
"@dereekb/firebase": "14.
|
|
10
|
-
"@dereekb/model": "14.
|
|
11
|
-
"@dereekb/nestjs": "14.
|
|
12
|
-
"@dereekb/util": "14.
|
|
7
|
+
"@dereekb/date": "14.2.0",
|
|
8
|
+
"@dereekb/dbx-cli": "14.2.0",
|
|
9
|
+
"@dereekb/firebase": "14.2.0",
|
|
10
|
+
"@dereekb/model": "14.2.0",
|
|
11
|
+
"@dereekb/nestjs": "14.2.0",
|
|
12
|
+
"@dereekb/util": "14.2.0"
|
|
13
13
|
},
|
|
14
14
|
"exports": {
|
|
15
15
|
"./package.json": "./package.json",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import type { CommandModule } from 'yargs';
|
|
3
|
+
import { type CliDataCache } from './data-cache';
|
|
4
|
+
/**
|
|
5
|
+
* Default command name for the data-cache management command.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_CLI_DATA_CACHE_COMMAND_NAME = "cache";
|
|
8
|
+
export interface CreateCacheCommandInput {
|
|
9
|
+
readonly cliName: string;
|
|
10
|
+
/**
|
|
11
|
+
* Override for the cache the command manages. Defaults to the CLI's own
|
|
12
|
+
* `<configDir>/cache` directory.
|
|
13
|
+
*/
|
|
14
|
+
readonly cache?: Maybe<CliDataCache>;
|
|
15
|
+
/**
|
|
16
|
+
* The current CLI build stamp. When supplied, `cache list` marks entries recorded by a different
|
|
17
|
+
* build, which is the one staleness signal the fingerprint deliberately does not cover.
|
|
18
|
+
*/
|
|
19
|
+
readonly cliBuildStamp?: Maybe<string>;
|
|
20
|
+
readonly commandName?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Factory for the `cache` command.
|
|
24
|
+
*
|
|
25
|
+
* Registered as a CONFIG command, not an API command: inspecting or clearing a LOCAL cache must work
|
|
26
|
+
* offline and without a token — which is precisely the situation in which a cache matters. Mirrors
|
|
27
|
+
* the `firestore-queries` (config) vs `firestore-query` (api) split.
|
|
28
|
+
*
|
|
29
|
+
* Subcommands:
|
|
30
|
+
* - `cache list [--env <env>] [--dataset <id>] [--json]`
|
|
31
|
+
* - `cache show <dataset> [--env <env>] [--fingerprint <fp>] [--data]`
|
|
32
|
+
* - `cache clear [--env <env>] [--dataset <id>] [--all]`
|
|
33
|
+
* - `cache prune --older-than <hours> [--env <env>] [--dataset <id>]`
|
|
34
|
+
*
|
|
35
|
+
* @param input - Factory configuration.
|
|
36
|
+
* @param input.cliName - The CLI's binary name, used to derive the default cache directory.
|
|
37
|
+
* @param input.cache - Optional cache override (tests point this at a temp dir).
|
|
38
|
+
* @param input.cliBuildStamp - The current build stamp, for marking entries from another build.
|
|
39
|
+
* @param input.commandName - Optional command-name override.
|
|
40
|
+
* @returns A yargs `CommandModule` for `runCli({ configCommands })`.
|
|
41
|
+
*
|
|
42
|
+
* @__NO_SIDE_EFFECTS__
|
|
43
|
+
*/
|
|
44
|
+
export declare function createCacheCommand(input: CreateCacheCommandInput): CommandModule;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error code thrown when a value handed to {@link toCliCacheJson} contains a reference cycle.
|
|
3
|
+
*/
|
|
4
|
+
export declare const CLI_DATA_CACHE_CYCLE_ERROR_CODE = "CLI_DATA_CACHE_CYCLE";
|
|
5
|
+
/**
|
|
6
|
+
* Error code thrown when a value handed to {@link toCliCacheJson} holds something that cannot be
|
|
7
|
+
* persisted and re-read at all — a function or a symbol.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CLI_DATA_CACHE_UNSUPPORTED_VALUE_ERROR_CODE = "CLI_DATA_CACHE_UNSUPPORTED_VALUE";
|
|
10
|
+
/**
|
|
11
|
+
* Converts a value into a JSON-safe tree, tagging the types a plain `JSON.stringify` round trip
|
|
12
|
+
* would lose.
|
|
13
|
+
*
|
|
14
|
+
* This is a PRE-WALK rather than a `JSON.stringify` replacer, and that is load-bearing:
|
|
15
|
+
* `Date.prototype.toJSON` runs BEFORE a replacer sees the value, so a replacer is handed an ISO
|
|
16
|
+
* string and cannot tell a `Date` from a string that merely looks like one. Every model in a
|
|
17
|
+
* dbx-components app persists its dates through `firestoreDate` (an ISO string on the wire, a live
|
|
18
|
+
* `Date` in memory), so that distinction is the whole problem.
|
|
19
|
+
*
|
|
20
|
+
* Handled: `Date`, `Map`, `Set`, `undefined`, non-finite numbers, `bigint`, arrays, plain objects,
|
|
21
|
+
* and the JSON primitives. A class instance that is none of the above is FLATTENED to its own
|
|
22
|
+
* enumerable properties — the one lossy case, and the reason a stage whose output holds a class
|
|
23
|
+
* instance must supply its own codec.
|
|
24
|
+
*
|
|
25
|
+
* @param value - The value to encode.
|
|
26
|
+
* @returns A tree containing only values `JSON.stringify` renders losslessly.
|
|
27
|
+
* @throws {CliError} On a reference cycle, or on a function/symbol anywhere in the tree.
|
|
28
|
+
*/
|
|
29
|
+
export declare function toCliCacheJson(value: unknown): unknown;
|
|
30
|
+
/**
|
|
31
|
+
* Rebuilds a value encoded by {@link toCliCacheJson}, restoring the tagged types.
|
|
32
|
+
*
|
|
33
|
+
* @param raw - The JSON-parsed tree written by {@link toCliCacheJson}.
|
|
34
|
+
* @returns The decoded value.
|
|
35
|
+
*/
|
|
36
|
+
export declare function fromCliCacheJson(raw: unknown): unknown;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { type ArrayOrValue, type Maybe, type Milliseconds } from '@dereekb/util';
|
|
2
|
+
import { type CliDataCacheOptions } from './data-cache.options';
|
|
3
|
+
/**
|
|
4
|
+
* Version of the on-disk index and payload envelopes.
|
|
5
|
+
*
|
|
6
|
+
* Bumped when the envelope shape itself changes. A payload written under a different schema version
|
|
7
|
+
* is a miss, not an error — see {@link CliDataCache.loadData}.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CLI_DATA_CACHE_SCHEMA_VERSION = 1;
|
|
10
|
+
/**
|
|
11
|
+
* Name of the index file inside the cache directory.
|
|
12
|
+
*/
|
|
13
|
+
export declare const CLI_DATA_CACHE_INDEX_FILE_NAME = "index.json";
|
|
14
|
+
/**
|
|
15
|
+
* One recorded build of one dataset, as held in the index.
|
|
16
|
+
*
|
|
17
|
+
* The payload lives in its own file (see {@link file}) so listing the cache never has to read the
|
|
18
|
+
* data — mirroring the lint cache's per-project files plus an index roll-up.
|
|
19
|
+
*/
|
|
20
|
+
export interface CliDataCacheEntry {
|
|
21
|
+
/**
|
|
22
|
+
* Identifier of the cached pipeline stage, e.g. `worker.lineDetails`.
|
|
23
|
+
*/
|
|
24
|
+
readonly dataset: string;
|
|
25
|
+
/**
|
|
26
|
+
* The stage version this build was produced by. An entry whose version no longer matches the
|
|
27
|
+
* caller's is a miss.
|
|
28
|
+
*/
|
|
29
|
+
readonly datasetVersion: number;
|
|
30
|
+
/**
|
|
31
|
+
* The env the data was read from.
|
|
32
|
+
*/
|
|
33
|
+
readonly env: string;
|
|
34
|
+
readonly fingerprint: string;
|
|
35
|
+
/**
|
|
36
|
+
* The NORMALIZED filter this build covers, stored verbatim so `cache list` can show what an entry
|
|
37
|
+
* is a build OF rather than just its digest.
|
|
38
|
+
*/
|
|
39
|
+
readonly filter: unknown;
|
|
40
|
+
/**
|
|
41
|
+
* When the build was recorded, as an ISO string.
|
|
42
|
+
*/
|
|
43
|
+
readonly builtAt: string;
|
|
44
|
+
/**
|
|
45
|
+
* Number of rows, when the cached value was an array. Absent for a non-array payload.
|
|
46
|
+
*/
|
|
47
|
+
readonly itemCount?: Maybe<number>;
|
|
48
|
+
/**
|
|
49
|
+
* Size of the payload file in bytes.
|
|
50
|
+
*/
|
|
51
|
+
readonly bytes: number;
|
|
52
|
+
/**
|
|
53
|
+
* Absolute path of the payload file.
|
|
54
|
+
*/
|
|
55
|
+
readonly file: string;
|
|
56
|
+
/**
|
|
57
|
+
* The CLI build that produced the entry, when known.
|
|
58
|
+
*
|
|
59
|
+
* Recorded but deliberately NOT part of the fingerprint: fingerprinting on it would invalidate the
|
|
60
|
+
* whole cache on every rebuild of the CLI, which is exactly the workflow this feature is meant to
|
|
61
|
+
* speed up. `cache list` surfaces it so an entry from a different build is visible.
|
|
62
|
+
*/
|
|
63
|
+
readonly cliBuildStamp?: Maybe<string>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The persisted payload envelope.
|
|
67
|
+
*/
|
|
68
|
+
export interface CliDataCachePayloadFile {
|
|
69
|
+
readonly schemaVersion: number;
|
|
70
|
+
readonly dataset: string;
|
|
71
|
+
readonly datasetVersion: number;
|
|
72
|
+
readonly env: string;
|
|
73
|
+
readonly fingerprint: string;
|
|
74
|
+
readonly builtAt: string;
|
|
75
|
+
/**
|
|
76
|
+
* The cached value, encoded by the entry's codec.
|
|
77
|
+
*/
|
|
78
|
+
readonly payload: unknown;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* How a cached value is converted to and from the JSON written on disk.
|
|
82
|
+
*
|
|
83
|
+
* Defaults to the tagged structured codec, which needs no per-dataset work. A dataset whose value
|
|
84
|
+
* holds something the tagged codec cannot represent — a class instance whose identity matters —
|
|
85
|
+
* supplies its own.
|
|
86
|
+
*/
|
|
87
|
+
export interface CliDataCacheCodec<T> {
|
|
88
|
+
readonly toJson: (data: T) => unknown;
|
|
89
|
+
readonly fromJson: (raw: unknown) => T;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The default codec: the tagged structured JSON walk.
|
|
93
|
+
*/
|
|
94
|
+
export declare const DEFAULT_CLI_DATA_CACHE_CODEC: CliDataCacheCodec<any>;
|
|
95
|
+
/**
|
|
96
|
+
* Narrowing filter accepted by {@link CliDataCache.listEntries} and {@link CliDataCache.removeEntries}.
|
|
97
|
+
*/
|
|
98
|
+
export interface CliDataCacheEntryFilter {
|
|
99
|
+
readonly env?: Maybe<string>;
|
|
100
|
+
readonly dataset?: Maybe<string>;
|
|
101
|
+
readonly fingerprint?: Maybe<string>;
|
|
102
|
+
/**
|
|
103
|
+
* Keep only entries built longer ago than this. Used by `cache prune`.
|
|
104
|
+
*/
|
|
105
|
+
readonly olderThanMs?: Maybe<Milliseconds>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Input for {@link CliDataCache.saveData}.
|
|
109
|
+
*/
|
|
110
|
+
export interface SaveCliDataCacheInput<T> {
|
|
111
|
+
readonly dataset: string;
|
|
112
|
+
readonly datasetVersion: number;
|
|
113
|
+
readonly env: string;
|
|
114
|
+
readonly filter?: Maybe<unknown>;
|
|
115
|
+
readonly data: T;
|
|
116
|
+
readonly codec?: Maybe<CliDataCacheCodec<T>>;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Input for {@link CliDataCache.loadData}.
|
|
120
|
+
*/
|
|
121
|
+
export interface LoadCliDataCacheInput<T> {
|
|
122
|
+
readonly dataset: string;
|
|
123
|
+
readonly datasetVersion: number;
|
|
124
|
+
readonly env: string;
|
|
125
|
+
readonly filter?: Maybe<unknown>;
|
|
126
|
+
readonly codec?: Maybe<CliDataCacheCodec<T>>;
|
|
127
|
+
/**
|
|
128
|
+
* Reject an entry built longer ago than this. Omit for no age limit.
|
|
129
|
+
*/
|
|
130
|
+
readonly maxAgeMs?: Maybe<Milliseconds>;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* A hit returned by {@link CliDataCache.loadData}.
|
|
134
|
+
*/
|
|
135
|
+
export interface CliDataCacheHit<T> {
|
|
136
|
+
readonly data: T;
|
|
137
|
+
readonly entry: CliDataCacheEntry;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* On-disk store of recorded dataset builds.
|
|
141
|
+
*/
|
|
142
|
+
export interface CliDataCache {
|
|
143
|
+
/**
|
|
144
|
+
* The directory holding the index and every payload file.
|
|
145
|
+
*/
|
|
146
|
+
readonly dataCacheDir: string;
|
|
147
|
+
/**
|
|
148
|
+
* Returns every recorded entry matching `filter`, newest build first.
|
|
149
|
+
*/
|
|
150
|
+
listEntries(filter?: Maybe<CliDataCacheEntryFilter>): Promise<CliDataCacheEntry[]>;
|
|
151
|
+
/**
|
|
152
|
+
* Reads a recorded build, or `undefined` when there is no usable one.
|
|
153
|
+
*
|
|
154
|
+
* Any reason the entry cannot be used — absent, wrong `datasetVersion`, wrong schema version, past
|
|
155
|
+
* `maxAgeMs`, payload file missing, payload unparsable — is reported the same way: a miss, so the
|
|
156
|
+
* caller rebuilds. A cache is never allowed to turn into a failure.
|
|
157
|
+
*/
|
|
158
|
+
loadData<T>(input: LoadCliDataCacheInput<T>): Promise<Maybe<CliDataCacheHit<T>>>;
|
|
159
|
+
/**
|
|
160
|
+
* Records a build, replacing any previous build of the same dataset + filter.
|
|
161
|
+
*/
|
|
162
|
+
saveData<T>(input: SaveCliDataCacheInput<T>): Promise<CliDataCacheEntry>;
|
|
163
|
+
/**
|
|
164
|
+
* Removes every entry matching `filter` (and its payload file). Returns what was removed.
|
|
165
|
+
*/
|
|
166
|
+
removeEntries(filter?: Maybe<CliDataCacheEntryFilter>): Promise<CliDataCacheEntry[]>;
|
|
167
|
+
}
|
|
168
|
+
export interface CreateCliDataCacheInput {
|
|
169
|
+
/**
|
|
170
|
+
* Directory holding the index and payload files, e.g. `~/.<cliName>/cache`.
|
|
171
|
+
*/
|
|
172
|
+
readonly dataCacheDir: string;
|
|
173
|
+
/**
|
|
174
|
+
* Optional stamp identifying the CLI build, recorded on every entry it writes.
|
|
175
|
+
*/
|
|
176
|
+
readonly cliBuildStamp?: Maybe<string>;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Creates the on-disk dataset cache.
|
|
180
|
+
*
|
|
181
|
+
* Layout, mirroring the lint cache's per-key files plus a versioned index roll-up:
|
|
182
|
+
*
|
|
183
|
+
* ```
|
|
184
|
+
* <dataCacheDir>/index.json the CliDataCacheEntry roll-up
|
|
185
|
+
* <dataCacheDir>/<env>/<dataset>/<fingerprint>.json one CliDataCachePayloadFile per build
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* Everything is written mode 0600. A cached export holds production rows — worker names, emails,
|
|
189
|
+
* billing lines — so the files are readable by the owning user only, the same posture as the token
|
|
190
|
+
* and Firestore-session caches next to them.
|
|
191
|
+
*
|
|
192
|
+
* @param input - The cache inputs.
|
|
193
|
+
* @param input.dataCacheDir - Directory holding the index and payload files.
|
|
194
|
+
* @param input.cliBuildStamp - Optional stamp identifying the CLI build, recorded on written entries.
|
|
195
|
+
* @returns The cache.
|
|
196
|
+
*
|
|
197
|
+
* @__NO_SIDE_EFFECTS__
|
|
198
|
+
*/
|
|
199
|
+
export declare function createCliDataCache(input: CreateCliDataCacheInput): CliDataCache;
|
|
200
|
+
/**
|
|
201
|
+
* Whether a recorded build is too old to satisfy a read.
|
|
202
|
+
*
|
|
203
|
+
* @param entry - The entry to test.
|
|
204
|
+
* @param maxAgeMs - The age limit. `null`/`undefined` means no limit.
|
|
205
|
+
* @returns Whether the entry is past the limit.
|
|
206
|
+
*
|
|
207
|
+
* @__NO_SIDE_EFFECTS__
|
|
208
|
+
*/
|
|
209
|
+
export declare function isEntryExpired(entry: CliDataCacheEntry, maxAgeMs: Maybe<Milliseconds>): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* The outcome of {@link loadOrBuildCliCachedData}.
|
|
212
|
+
*/
|
|
213
|
+
export interface CliCachedDataResult<T> {
|
|
214
|
+
readonly data: T;
|
|
215
|
+
/**
|
|
216
|
+
* Whether `data` came off disk rather than from `build()`.
|
|
217
|
+
*/
|
|
218
|
+
readonly fromCache: boolean;
|
|
219
|
+
readonly dataset: string;
|
|
220
|
+
readonly fingerprint: string;
|
|
221
|
+
readonly builtAt: Date;
|
|
222
|
+
/**
|
|
223
|
+
* How old the data is. Zero for a fresh build.
|
|
224
|
+
*/
|
|
225
|
+
readonly ageMs: Milliseconds;
|
|
226
|
+
readonly itemCount?: Maybe<number>;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Input for {@link loadOrBuildCliCachedData}.
|
|
230
|
+
*/
|
|
231
|
+
export interface LoadOrBuildCliCachedDataInput<T> {
|
|
232
|
+
readonly cache: CliDataCache;
|
|
233
|
+
readonly dataset: string;
|
|
234
|
+
readonly datasetVersion: number;
|
|
235
|
+
readonly env: string;
|
|
236
|
+
/**
|
|
237
|
+
* The inputs this stage's contents depend on — and ONLY those. Anything applied after the stage
|
|
238
|
+
* (output format, export flavour, a row filter the pipeline applies downstream) must be left out,
|
|
239
|
+
* or changing it will needlessly miss.
|
|
240
|
+
*/
|
|
241
|
+
readonly filter?: Maybe<unknown>;
|
|
242
|
+
/**
|
|
243
|
+
* The invocation's cache policy. Defaults to {@link DEFAULT_CLI_DATA_CACHE_OPTIONS} (record only).
|
|
244
|
+
*/
|
|
245
|
+
readonly options?: Maybe<CliDataCacheOptions>;
|
|
246
|
+
readonly codec?: Maybe<CliDataCacheCodec<T>>;
|
|
247
|
+
/**
|
|
248
|
+
* Produces the data when no recorded build satisfies the run. Only called on a miss, which is what
|
|
249
|
+
* makes nesting these calls resolve a stage chain back-to-front: a hit on a late stage never runs
|
|
250
|
+
* the earlier stages at all.
|
|
251
|
+
*/
|
|
252
|
+
readonly build: () => Promise<T>;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Reads a recorded build of a dataset, or produces and records one.
|
|
256
|
+
*
|
|
257
|
+
* @param input - The lookup + build inputs.
|
|
258
|
+
* @returns The data plus where it came from.
|
|
259
|
+
*/
|
|
260
|
+
export declare function loadOrBuildCliCachedData<T>(input: LoadOrBuildCliCachedDataInput<T>): Promise<CliCachedDataResult<T>>;
|
|
261
|
+
/**
|
|
262
|
+
* Builds the `cache` provenance block for an output envelope's `meta`.
|
|
263
|
+
*
|
|
264
|
+
* Emitting it on every cached command is what lets a reader tell whether the bytes in front of them
|
|
265
|
+
* came off disk, and how old they are, without re-running anything.
|
|
266
|
+
*
|
|
267
|
+
* @param results - One result, or the per-stage results of a pipeline.
|
|
268
|
+
* @returns The meta block: one object for a single result, an array for several.
|
|
269
|
+
*
|
|
270
|
+
* @__NO_SIDE_EFFECTS__
|
|
271
|
+
*/
|
|
272
|
+
export declare function cliDataCacheMeta(results: ArrayOrValue<CliCachedDataResult<unknown>>): Record<string, unknown>;
|