@dereekb/dbx-cli 14.1.0 → 14.3.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.
Files changed (38) hide show
  1. package/eslint/index.esm.js +0 -195
  2. package/eslint/package.json +4 -3
  3. package/firebase-api-manifest/main.js +124 -13
  4. package/firebase-api-manifest/package.json +4 -3
  5. package/firestore-indexes/src/model-firebase-index-schema.d.ts +4 -4
  6. package/firestore-query-manifest/main.js +4 -3
  7. package/firestore-query-manifest/package.json +4 -3
  8. package/generate-firestore-indexes/main.js +3 -2
  9. package/generate-firestore-indexes/package.json +3 -2
  10. package/generate-mcp-manifest/package.json +4 -3
  11. package/generate-route-manifest/package.json +3 -2
  12. package/index.esm.js +4228 -1344
  13. package/lint-cache/package.json +3 -2
  14. package/manifest-extract/index.esm.js +113 -7
  15. package/manifest-extract/package.json +8 -8
  16. package/manifest-extract/src/lib/types.d.ts +10 -0
  17. package/model-test/package.json +2 -2
  18. package/package.json +6 -6
  19. package/route/package.json +7 -7
  20. package/src/lib/auth/index.d.ts +1 -0
  21. package/src/lib/auth/oidc.loopback.d.ts +127 -0
  22. package/src/lib/cache/cache.command.factory.d.ts +44 -0
  23. package/src/lib/cache/data-cache.codec.d.ts +36 -0
  24. package/src/lib/cache/data-cache.d.ts +272 -0
  25. package/src/lib/cache/data-cache.fingerprint.d.ts +109 -0
  26. package/src/lib/cache/data-cache.options.d.ts +98 -0
  27. package/src/lib/cache/index.d.ts +5 -0
  28. package/src/lib/config/env.d.ts +43 -7
  29. package/src/lib/config/env.resolve.d.ts +4 -3
  30. package/src/lib/config/paths.d.ts +11 -1
  31. package/src/lib/firestore/firestore-query.command.d.ts +25 -1
  32. package/src/lib/index.d.ts +1 -0
  33. package/src/lib/runner/run.d.ts +11 -0
  34. package/src/lib/util/browser.d.ts +23 -0
  35. package/src/lib/util/index.d.ts +1 -0
  36. package/src/lib/util/interactive.d.ts +10 -1
  37. package/test/package.json +10 -9
  38. package/validate/package.json +3 -3
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli-lint-cache",
3
- "version": "14.1.0",
3
+ "version": "14.3.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.1.0",
12
+ "@dereekb/util": "14.3.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 (!initializer || !Node.isCallExpression(initializer)) continue;
767
- if (initializer.getExpression().getText() !== IDENTITY_FN) continue;
768
- var parsed = parseFirestoreModelIdentityArgs(initializer.getArguments());
769
- if (parsed) {
770
- out.push(_object_spread({
771
- identityConst: decl.getName()
772
- }, parsed));
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.1.0",
3
+ "version": "14.3.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
- "@dereekb/date": "14.1.0",
8
- "@dereekb/dbx-cli": "14.1.0",
9
- "@dereekb/firebase": "14.1.0",
10
- "@dereekb/model": "14.1.0",
11
- "@dereekb/nestjs": "14.1.0",
12
- "@dereekb/rxjs": "14.1.0",
13
- "@dereekb/util": "14.1.0",
7
+ "@dereekb/date": "14.3.0",
8
+ "@dereekb/dbx-cli": "14.3.0",
9
+ "@dereekb/firebase": "14.3.0",
10
+ "@dereekb/model": "14.3.0",
11
+ "@dereekb/nestjs": "14.3.0",
12
+ "@dereekb/rxjs": "14.3.0",
13
+ "@dereekb/util": "14.3.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.
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli/model-test",
3
- "version": "14.1.0",
3
+ "version": "14.3.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
- "@dereekb/util": "14.1.0",
7
+ "@dereekb/util": "14.3.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.1.0",
3
+ "version": "14.3.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.1.0",
70
- "@dereekb/firebase": "14.1.0",
71
- "@dereekb/model": "14.1.0",
72
- "@dereekb/nestjs": "14.1.0",
73
- "@dereekb/util": "14.1.0",
69
+ "@dereekb/date": "14.3.0",
70
+ "@dereekb/firebase": "14.3.0",
71
+ "@dereekb/model": "14.3.0",
72
+ "@dereekb/nestjs": "14.3.0",
73
+ "@dereekb/util": "14.3.0",
74
74
  "@nestjs/common": "^12.0.1",
75
75
  "arktype": "^2.2.0",
76
76
  "firebase": "^12.18.0",
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli/route",
3
- "version": "14.1.0",
3
+ "version": "14.3.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
- "@dereekb/date": "14.1.0",
8
- "@dereekb/dbx-cli": "14.1.0",
9
- "@dereekb/firebase": "14.1.0",
10
- "@dereekb/model": "14.1.0",
11
- "@dereekb/nestjs": "14.1.0",
12
- "@dereekb/util": "14.1.0"
7
+ "@dereekb/date": "14.3.0",
8
+ "@dereekb/dbx-cli": "14.3.0",
9
+ "@dereekb/firebase": "14.3.0",
10
+ "@dereekb/model": "14.3.0",
11
+ "@dereekb/nestjs": "14.3.0",
12
+ "@dereekb/util": "14.3.0"
13
13
  },
14
14
  "exports": {
15
15
  "./package.json": "./package.json",
@@ -1,3 +1,4 @@
1
1
  export * from './auth.command.factory';
2
2
  export * from './oidc.client';
3
3
  export * from './oidc.flow';
4
+ export * from './oidc.loopback';
@@ -0,0 +1,127 @@
1
+ import { type Maybe, type PortNumber, type WebsiteUrl } from '@dereekb/util';
2
+ /**
3
+ * Hostnames RFC 8252 §7.3 treats as the loopback interface, and the exact set `oidc-provider`
4
+ * recognizes as a loopback redirect host.
5
+ *
6
+ * `[::1]` carries its brackets because that is what `URL.hostname` returns for an IPv6 literal —
7
+ * the brackets are stripped again before the address is handed to `server.listen`.
8
+ */
9
+ export declare const LOOPBACK_REDIRECT_HOSTNAMES: readonly string[];
10
+ /**
11
+ * The loopback port the CLI suggests when the configured redirect URI has no bindable port.
12
+ *
13
+ * Deliberately outside the 9900-9910 block the Firebase emulators occupy, so a suggested redirect
14
+ * URI never collides with a running emulator.
15
+ */
16
+ export declare const SUGGESTED_CLI_LOOPBACK_REDIRECT_PORT: PortNumber;
17
+ /**
18
+ * Error code raised when the loopback listener cannot bind the redirect URI's port (e.g. the port
19
+ * is already in use, or is privileged).
20
+ */
21
+ export declare const LOOPBACK_REDIRECT_LISTEN_FAILED_ERROR_CODE = "AUTH_REDIRECT_LISTEN_FAILED";
22
+ /**
23
+ * Error code raised when no redirect reached the loopback listener within the allotted time.
24
+ */
25
+ export declare const LOOPBACK_REDIRECT_TIMEOUT_ERROR_CODE = "AUTH_REDIRECT_TIMEOUT";
26
+ /**
27
+ * A redirect URI the CLI can bind a local HTTP listener to, decomposed into its parts.
28
+ */
29
+ export interface LoopbackRedirectTarget {
30
+ /**
31
+ * The normalized redirect URI to send as `redirect_uri`. Identical to the configured URI unless a
32
+ * port override was applied.
33
+ */
34
+ readonly redirectUri: WebsiteUrl;
35
+ /**
36
+ * The loopback hostname, as `URL.hostname` reports it (so `[::1]` keeps its brackets).
37
+ */
38
+ readonly hostname: string;
39
+ /**
40
+ * The port to bind. Always a positive integer — a `0`/absent port is not a capturable target.
41
+ */
42
+ readonly port: PortNumber;
43
+ /**
44
+ * The path the provider redirects to. Requests to any other path are answered `404` so a stray
45
+ * `/favicon.ico` cannot be mistaken for the authorization redirect.
46
+ */
47
+ readonly pathname: string;
48
+ }
49
+ export interface ParseLoopbackRedirectUriInput {
50
+ /**
51
+ * The configured redirect URI.
52
+ */
53
+ readonly redirectUri: Maybe<string>;
54
+ /**
55
+ * Optional port override, replacing whatever port the redirect URI carries.
56
+ *
57
+ * The resulting URI is what gets sent as `redirect_uri`, so it must be registered with the OAuth
58
+ * client just like the configured one.
59
+ */
60
+ readonly port?: Maybe<PortNumber>;
61
+ }
62
+ /**
63
+ * Decomposes a redirect URI into a {@link LoopbackRedirectTarget} when the CLI can bind a local
64
+ * listener for it.
65
+ *
66
+ * A target is only produced for an `http:` loopback URI carrying a concrete, non-zero port. The
67
+ * conventional `http://127.0.0.1:0/callback` placeholder is deliberately NOT capturable: binding an
68
+ * ephemeral port would mean sending a `redirect_uri` that differs from the registered one, which
69
+ * every OAuth provider rejects unless the client is registered as a native app (where loopback
70
+ * ports are compared port-insensitively).
71
+ *
72
+ * @param input - The parse inputs.
73
+ * @param input.redirectUri - The configured redirect URI.
74
+ * @param input.port - Optional port override applied to the parsed URI.
75
+ * @returns The bindable target, or `undefined` when the URI cannot be captured locally.
76
+ * @__NO_SIDE_EFFECTS__
77
+ */
78
+ export declare function parseLoopbackRedirectUri(input: ParseLoopbackRedirectUriInput): Maybe<LoopbackRedirectTarget>;
79
+ export interface StartLoopbackRedirectCaptureInput {
80
+ /**
81
+ * The bindable target, from {@link parseLoopbackRedirectUri}.
82
+ */
83
+ readonly target: LoopbackRedirectTarget;
84
+ /**
85
+ * Text shown in the browser tab once the redirect is captured.
86
+ */
87
+ readonly successMessage?: Maybe<string>;
88
+ }
89
+ export interface LoopbackRedirectCapture {
90
+ /**
91
+ * The `redirect_uri` the listener is bound to. Send this value in the authorization request.
92
+ */
93
+ readonly redirectUri: WebsiteUrl;
94
+ /**
95
+ * The bound port.
96
+ */
97
+ readonly port: PortNumber;
98
+ /**
99
+ * Resolves with the full redirect URL (query string included) the browser was sent to.
100
+ *
101
+ * A provider error redirect resolves rather than rejects — the returned URL carries the `error`
102
+ * params, which the shared redirect parser already turns into an `AUTH_PROVIDER_ERROR`.
103
+ *
104
+ * @param timeoutMs - Optional milliseconds to wait before rejecting with
105
+ * {@link LOOPBACK_REDIRECT_TIMEOUT_ERROR_CODE}. Waits indefinitely when omitted.
106
+ */
107
+ readonly waitForRedirect: (timeoutMs?: Maybe<number>) => Promise<WebsiteUrl>;
108
+ /**
109
+ * Closes the listener and destroys any open sockets, so the CLI's event loop can drain.
110
+ */
111
+ readonly close: () => Promise<void>;
112
+ }
113
+ /**
114
+ * Binds a local HTTP listener to a loopback redirect URI so the authorization code can be read
115
+ * straight out of the browser redirect instead of being pasted back by hand.
116
+ *
117
+ * The listener answers exactly one path — the redirect URI's own — and serves a short "you can close
118
+ * this tab" page. Everything else is answered `404`, which is what keeps the browser's automatic
119
+ * `/favicon.ico` request from being mistaken for the redirect.
120
+ *
121
+ * @param input - The capture inputs.
122
+ * @param input.target - The bindable target, from {@link parseLoopbackRedirectUri}.
123
+ * @param input.successMessage - Optional override for the browser success page's body line.
124
+ * @returns The started {@link LoopbackRedirectCapture}.
125
+ * @throws {CliError} `AUTH_REDIRECT_LISTEN_FAILED` when the port cannot be bound.
126
+ */
127
+ export declare function startLoopbackRedirectCapture(input: StartLoopbackRedirectCaptureInput): Promise<LoopbackRedirectCapture>;
@@ -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;