@opensip-cli/datastore 0.1.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 (102) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/__tests__/baseline-repo.test.d.ts +2 -0
  5. package/dist/__tests__/baseline-repo.test.d.ts.map +1 -0
  6. package/dist/__tests__/baseline-repo.test.js +85 -0
  7. package/dist/__tests__/baseline-repo.test.js.map +1 -0
  8. package/dist/__tests__/data-store.test.d.ts +10 -0
  9. package/dist/__tests__/data-store.test.d.ts.map +1 -0
  10. package/dist/__tests__/data-store.test.js +68 -0
  11. package/dist/__tests__/data-store.test.js.map +1 -0
  12. package/dist/__tests__/factory.test.d.ts +2 -0
  13. package/dist/__tests__/factory.test.d.ts.map +1 -0
  14. package/dist/__tests__/factory.test.js +168 -0
  15. package/dist/__tests__/factory.test.js.map +1 -0
  16. package/dist/__tests__/migration-integrity.test.d.ts +2 -0
  17. package/dist/__tests__/migration-integrity.test.d.ts.map +1 -0
  18. package/dist/__tests__/migration-integrity.test.js +78 -0
  19. package/dist/__tests__/migration-integrity.test.js.map +1 -0
  20. package/dist/__tests__/tool-state-repo.test.d.ts +7 -0
  21. package/dist/__tests__/tool-state-repo.test.d.ts.map +1 -0
  22. package/dist/__tests__/tool-state-repo.test.js +54 -0
  23. package/dist/__tests__/tool-state-repo.test.js.map +1 -0
  24. package/dist/__tests__/version-guard.test.d.ts +2 -0
  25. package/dist/__tests__/version-guard.test.d.ts.map +1 -0
  26. package/dist/__tests__/version-guard.test.js +110 -0
  27. package/dist/__tests__/version-guard.test.js.map +1 -0
  28. package/dist/backends/memory.d.ts +3 -0
  29. package/dist/backends/memory.d.ts.map +1 -0
  30. package/dist/backends/memory.js +5 -0
  31. package/dist/backends/memory.js.map +1 -0
  32. package/dist/backends/shared.d.ts +3 -0
  33. package/dist/backends/shared.d.ts.map +1 -0
  34. package/dist/backends/shared.js +31 -0
  35. package/dist/backends/shared.js.map +1 -0
  36. package/dist/backends/sqlite.d.ts +5 -0
  37. package/dist/backends/sqlite.d.ts.map +1 -0
  38. package/dist/backends/sqlite.js +8 -0
  39. package/dist/backends/sqlite.js.map +1 -0
  40. package/dist/baseline-repo.d.ts +50 -0
  41. package/dist/baseline-repo.d.ts.map +1 -0
  42. package/dist/baseline-repo.js +159 -0
  43. package/dist/baseline-repo.js.map +1 -0
  44. package/dist/data-store.d.ts +78 -0
  45. package/dist/data-store.d.ts.map +1 -0
  46. package/dist/data-store.js +71 -0
  47. package/dist/data-store.js.map +1 -0
  48. package/dist/factory.d.ts +47 -0
  49. package/dist/factory.d.ts.map +1 -0
  50. package/dist/factory.js +151 -0
  51. package/dist/factory.js.map +1 -0
  52. package/dist/index.d.ts +10 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +11 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/schema/baseline.d.ts +178 -0
  57. package/dist/schema/baseline.d.ts.map +1 -0
  58. package/dist/schema/baseline.js +31 -0
  59. package/dist/schema/baseline.js.map +1 -0
  60. package/dist/schema/tool-state.d.ts +110 -0
  61. package/dist/schema/tool-state.d.ts.map +1 -0
  62. package/dist/schema/tool-state.js +20 -0
  63. package/dist/schema/tool-state.js.map +1 -0
  64. package/dist/schema-version.d.ts +23 -0
  65. package/dist/schema-version.d.ts.map +1 -0
  66. package/dist/schema-version.js +55 -0
  67. package/dist/schema-version.js.map +1 -0
  68. package/dist/tool-state-repo.d.ts +51 -0
  69. package/dist/tool-state-repo.d.ts.map +1 -0
  70. package/dist/tool-state-repo.js +110 -0
  71. package/dist/tool-state-repo.js.map +1 -0
  72. package/migrations/.gitkeep +0 -0
  73. package/migrations/0000_sticky_white_tiger.sql +39 -0
  74. package/migrations/0001_easy_harry_osborn.sql +18 -0
  75. package/migrations/0002_plain_amazoness.sql +5 -0
  76. package/migrations/0003_mysterious_khan.sql +6 -0
  77. package/migrations/0004_narrow_bloodscream.sql +3 -0
  78. package/migrations/0005_lying_luke_cage.sql +7 -0
  79. package/migrations/0006_mean_photon.sql +12 -0
  80. package/migrations/0007_parallel_chamber.sql +3 -0
  81. package/migrations/0008_flaky_victor_mancha.sql +7 -0
  82. package/migrations/0009_stable_tool_identity.sql +9 -0
  83. package/migrations/0010_add_timestamp_iso_and_payload_version.sql +11 -0
  84. package/migrations/0011_payload_version_safety_and_notes.sql +21 -0
  85. package/migrations/0012_overrated_talon.sql +21 -0
  86. package/migrations/0013_lovely_zarda.sql +1 -0
  87. package/migrations/meta/0000_snapshot.json +269 -0
  88. package/migrations/meta/0001_snapshot.json +369 -0
  89. package/migrations/meta/0002_snapshot.json +400 -0
  90. package/migrations/meta/0003_snapshot.json +441 -0
  91. package/migrations/meta/0004_snapshot.json +270 -0
  92. package/migrations/meta/0005_snapshot.json +315 -0
  93. package/migrations/meta/0006_snapshot.json +382 -0
  94. package/migrations/meta/0007_snapshot.json +303 -0
  95. package/migrations/meta/0008_snapshot.json +346 -0
  96. package/migrations/meta/0009_snapshot.json +367 -0
  97. package/migrations/meta/0010_snapshot.json +382 -0
  98. package/migrations/meta/0011_snapshot.json +382 -0
  99. package/migrations/meta/0012_snapshot.json +512 -0
  100. package/migrations/meta/0013_snapshot.json +458 -0
  101. package/migrations/meta/_journal.json +104 -0
  102. package/package.json +56 -0
@@ -0,0 +1,78 @@
1
+ import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
2
+ export type DrizzleHandle<TSchema extends Record<string, unknown> = Record<string, unknown>> = BetterSQLite3Database<TSchema>;
3
+ /** Public persistence handle: lifecycle plus transaction, but no raw query escape hatch. */
4
+ export interface DataStore<TSchema extends Record<string, unknown> = Record<string, unknown>> {
5
+ close(): void;
6
+ transaction<T>(fn: (tx: DrizzleHandle<TSchema>) => T): T;
7
+ }
8
+ /**
9
+ * Persistence-layer handle that exposes the raw Drizzle DB. Repository modules
10
+ * can narrow to this shape when they own the table boundary; general consumers
11
+ * should stay on {@link DataStore}.
12
+ *
13
+ * Direct query calls must stay inside `src/persistence/`, `session-store`, or
14
+ * `datastore`. Cross-module business code should go through the owning
15
+ * repository/API; `restrict-raw-db-access` guards that boundary.
16
+ */
17
+ export interface DrizzleDataStore<TSchema extends Record<string, unknown> = Record<string, unknown>> extends DataStore<TSchema> {
18
+ readonly db: DrizzleHandle<TSchema>;
19
+ }
20
+ /**
21
+ * A SQLite-backed {@link DrizzleDataStore} that also exposes its built-in
22
+ * `PRAGMA user_version` schema-stamp. Internal to the datastore package — the
23
+ * factory uses it to read/write the version guard before and after migrating.
24
+ * General consumers stay on {@link DataStore} / {@link DrizzleDataStore}.
25
+ */
26
+ export interface SqliteBackendHandle<TSchema extends Record<string, unknown> = Record<string, unknown>> extends DrizzleDataStore<TSchema> {
27
+ /** Read SQLite's `PRAGMA user_version` (0 on a fresh or pre-guard database). */
28
+ readUserVersion(): number;
29
+ /** Write SQLite's `PRAGMA user_version` schema-stamp. */
30
+ writeUserVersion(version: number): void;
31
+ }
32
+ export declare function isDrizzleDataStore(value: unknown): value is DrizzleDataStore;
33
+ /**
34
+ * Narrow a {@link DataStore} to a {@link DrizzleDataStore}, requiring the raw
35
+ * Drizzle handle to be present.
36
+ *
37
+ * @throws {Error} when `datastore` is not Drizzle-backed (general callers should
38
+ * use repository APIs instead of the raw datastore handle).
39
+ */
40
+ export declare function requireDrizzleDataStore(datastore: DataStore): DrizzleDataStore;
41
+ /** Options for opening a {@link DataStore}: backend choice and optional file path. */
42
+ export interface DataStoreOpenOptions {
43
+ backend: 'sqlite' | 'memory';
44
+ path?: string;
45
+ }
46
+ /** Thrown when a Drizzle schema migration fails to apply; carries the offending file name. */
47
+ export declare class DataStoreMigrationError extends Error {
48
+ readonly migrationFile: string | undefined;
49
+ constructor(message: string, options?: {
50
+ migrationFile?: string;
51
+ cause?: unknown;
52
+ });
53
+ }
54
+ /** Inputs describing an incompatible (future) on-disk database. */
55
+ export interface DataStoreVersionMismatch {
56
+ readonly path: string;
57
+ /** The `user_version` stamp found on disk. */
58
+ readonly dbVersion: number;
59
+ /** The highest schema version this CLI supports. */
60
+ readonly supportedVersion: number;
61
+ }
62
+ /**
63
+ * Thrown when the on-disk SQLite cache was written by a NEWER opensip-cli than
64
+ * the one now opening it (`dbVersion > supportedVersion`). Drizzle's migrator
65
+ * cannot detect this direction — the older CLI's migrations are all a prefix of
66
+ * what was applied, so `migrate()` would no-op and later queries would hit
67
+ * missing/renamed columns with a confusing error. This guard fails fast instead,
68
+ * with an actionable message symmetric to the config-schema "upgrade your CLI"
69
+ * bailout. The `.runtime/` cache is disposable, so deleting it is offered as the
70
+ * fallback for users who intend to stay on the older CLI.
71
+ */
72
+ export declare class DataStoreVersionError extends Error {
73
+ readonly path: string;
74
+ readonly dbVersion: number;
75
+ readonly supportedVersion: number;
76
+ constructor(mismatch: DataStoreVersionMismatch);
77
+ }
78
+ //# sourceMappingURL=data-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-store.d.ts","sourceRoot":"","sources":["../src/data-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,MAAM,MAAM,aAAa,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IACzF,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAEjC,4FAA4F;AAC5F,MAAM,WAAW,SAAS,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1F,KAAK,IAAI,IAAI,CAAC;IACd,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;CAC1D;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB,CAC/B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACjE,SAAQ,SAAS,CAAC,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACrC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB,CAClC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CACjE,SAAQ,gBAAgB,CAAC,OAAO,CAAC;IACjC,gFAAgF;IAChF,eAAe,IAAI,MAAM,CAAC;IAC1B,yDAAyD;IACzD,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAU5E;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,SAAS,GAAG,gBAAgB,CAK9E;AAED,sFAAsF;AACtF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,8FAA8F;AAC9F,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;gBAE/B,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAQvF;AAED,mEAAmE;AACnE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,oDAAoD;IACpD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;GASG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;gBAEtB,QAAQ,EAAE,wBAAwB;CAO/C"}
@@ -0,0 +1,71 @@
1
+ export function isDrizzleDataStore(value) {
2
+ return (typeof value === 'object' &&
3
+ value !== null &&
4
+ 'db' in value &&
5
+ 'transaction' in value &&
6
+ typeof value.transaction === 'function' &&
7
+ 'close' in value &&
8
+ typeof value.close === 'function');
9
+ }
10
+ /**
11
+ * Narrow a {@link DataStore} to a {@link DrizzleDataStore}, requiring the raw
12
+ * Drizzle handle to be present.
13
+ *
14
+ * @throws {Error} when `datastore` is not Drizzle-backed (general callers should
15
+ * use repository APIs instead of the raw datastore handle).
16
+ */
17
+ export function requireDrizzleDataStore(datastore) {
18
+ if (isDrizzleDataStore(datastore))
19
+ return datastore;
20
+ throw new Error('A Drizzle-backed DataStore is required for repository access. General callers should use repository APIs instead of the raw datastore handle.');
21
+ }
22
+ /** Thrown when a Drizzle schema migration fails to apply; carries the offending file name. */
23
+ export class DataStoreMigrationError extends Error {
24
+ migrationFile;
25
+ constructor(message, options = {}) {
26
+ // Pass cause to super so it lands on the standard Error.cause slot
27
+ // (ES2022). Don't redeclare the field — that would shadow it with a
28
+ // writable class-field property and bypass native engine handling.
29
+ super(message, options.cause === undefined ? undefined : { cause: options.cause });
30
+ this.name = 'DataStoreMigrationError';
31
+ this.migrationFile = options.migrationFile;
32
+ }
33
+ }
34
+ /**
35
+ * Thrown when the on-disk SQLite cache was written by a NEWER opensip-cli than
36
+ * the one now opening it (`dbVersion > supportedVersion`). Drizzle's migrator
37
+ * cannot detect this direction — the older CLI's migrations are all a prefix of
38
+ * what was applied, so `migrate()` would no-op and later queries would hit
39
+ * missing/renamed columns with a confusing error. This guard fails fast instead,
40
+ * with an actionable message symmetric to the config-schema "upgrade your CLI"
41
+ * bailout. The `.runtime/` cache is disposable, so deleting it is offered as the
42
+ * fallback for users who intend to stay on the older CLI.
43
+ */
44
+ export class DataStoreVersionError extends Error {
45
+ path;
46
+ dbVersion;
47
+ supportedVersion;
48
+ constructor(mismatch) {
49
+ super(formatVersionErrorMessage(mismatch));
50
+ this.name = 'DataStoreVersionError';
51
+ this.path = mismatch.path;
52
+ this.dbVersion = mismatch.dbVersion;
53
+ this.supportedVersion = mismatch.supportedVersion;
54
+ }
55
+ }
56
+ function formatVersionErrorMessage(mismatch) {
57
+ return [
58
+ `This project's opensip-cli cache was written by a newer version of opensip-cli than this CLI supports.`,
59
+ ``,
60
+ ` Cache: ${mismatch.path}`,
61
+ ` Cache schema: v${mismatch.dbVersion}`,
62
+ ` CLI supports: v${mismatch.supportedVersion}`,
63
+ ``,
64
+ ` Update your CLI to continue:`,
65
+ ` curl -fsSL https://opensip.ai/cli/install.sh | bash`,
66
+ ``,
67
+ ` (Or delete ${mismatch.path} to discard the local cache and continue with`,
68
+ ` this older CLI — session history will be lost; the cache rebuilds on next run.)`,
69
+ ].join('\n');
70
+ }
71
+ //# sourceMappingURL=data-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-store.js","sourceRoot":"","sources":["../src/data-store.ts"],"names":[],"mappings":"AAyCA,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,IAAI,IAAI,KAAK;QACb,aAAa,IAAI,KAAK;QACtB,OAAO,KAAK,CAAC,WAAW,KAAK,UAAU;QACvC,OAAO,IAAI,KAAK;QAChB,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU,CAClC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAoB;IAC1D,IAAI,kBAAkB,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,IAAI,KAAK,CACb,+IAA+I,CAChJ,CAAC;AACJ,CAAC;AAQD,8FAA8F;AAC9F,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACvC,aAAa,CAAqB;IAE3C,YAAY,OAAe,EAAE,UAAuD,EAAE;QACpF,mEAAmE;QACnE,oEAAoE;QACpE,mEAAmE;QACnE,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAC7C,CAAC;CACF;AAWD;;;;;;;;;GASG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACrC,IAAI,CAAS;IACb,SAAS,CAAS;IAClB,gBAAgB,CAAS;IAElC,YAAY,QAAkC;QAC5C,KAAK,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;QACpC,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,CAAC;IACpD,CAAC;CACF;AAED,SAAS,yBAAyB,CAAC,QAAkC;IACnE,OAAO;QACL,wGAAwG;QACxG,EAAE;QACF,qBAAqB,QAAQ,CAAC,IAAI,EAAE;QACpC,sBAAsB,QAAQ,CAAC,SAAS,EAAE;QAC1C,sBAAsB,QAAQ,CAAC,gBAAgB,EAAE;QACjD,EAAE;QACF,gCAAgC;QAChC,yDAAyD;QACzD,EAAE;QACF,gBAAgB,QAAQ,CAAC,IAAI,+CAA+C;QAC5E,mFAAmF;KACpF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type { DataStoreOpenOptions, DrizzleDataStore } from './data-store.js';
2
+ export declare const DataStoreFactory: {
3
+ /**
4
+ * Open a DataStore (SQLite or in-memory) and run pending migrations.
5
+ *
6
+ * For SQLite, a version guard runs first: if the file was stamped by a NEWER
7
+ * CLI than this one (`PRAGMA user_version` ahead of the bundled migration
8
+ * count), it throws {@link DataStoreVersionError} instead of letting Drizzle
9
+ * silently no-op into a runtime column error. After a successful migrate, the
10
+ * stamp is refreshed to this CLI's supported version.
11
+ *
12
+ * @throws {DataStoreVersionError} When the SQLite file was written by a newer
13
+ * opensip-cli than this CLI supports (the downgrade direction).
14
+ * @throws {DataStoreMigrationError} When the SQLite file cannot be opened
15
+ * (corrupt header, missing parent directory, permission errors), when the
16
+ * native `better-sqlite3` binding fails to load (an ABI mismatch — the file
17
+ * is fine, the addon was built for a different Node.js version), or when
18
+ * running the migrations folder fails. The original cause is preserved via
19
+ * the `cause` field; the message distinguishes the binding case so callers
20
+ * are not told to delete a healthy data store.
21
+ */
22
+ open(opts: DataStoreOpenOptions & {
23
+ migrationsFolder?: string;
24
+ }): DrizzleDataStore;
25
+ };
26
+ /**
27
+ * Detect a native-binding load failure: `better-sqlite3`'s compiled addon was
28
+ * built for a different Node.js ABI than the one now running (e.g. the binding
29
+ * was compiled under Node 22 and the CLI is run under Node 24). This is NOT a
30
+ * data problem — the SQLite file is intact and must not be deleted; the fix is
31
+ * to rebuild the native module for the current Node.js.
32
+ *
33
+ * Identified by the Node loader's `ERR_DLOPEN_FAILED` code or the
34
+ * `NODE_MODULE_VERSION` / "compiled against a different Node.js version" text,
35
+ * scanned across the whole `cause` chain (the error may be wrapped).
36
+ */
37
+ export declare function isNativeBindingError(error: unknown): boolean;
38
+ /**
39
+ * Build the user-facing message for a data-store open failure, choosing the
40
+ * remediation that matches the actual cause: a native-binding ABI mismatch
41
+ * (rebuild the addon — the data is fine) vs a genuine corrupt/permission/
42
+ * non-writable SQLite file (delete to start fresh) vs an in-memory programming
43
+ * error. Separated from the throw site so the cause→message mapping is unit
44
+ * testable without exercising the real binding.
45
+ */
46
+ export declare function openFailureMessage(opts: DataStoreOpenOptions, error: unknown): string;
47
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAM9E,eAAO,MAAM,gBAAgB;IAC3B;;;;;;;;;;;;;;;;;;OAkBG;eACQ,oBAAoB,GAAG;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,gBAAgB;CAwCnF,CAAC;AA8BF;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAU5D;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAWrF"}
@@ -0,0 +1,151 @@
1
+ import { join } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { ConfigurationError } from '@opensip-cli/core';
4
+ import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
5
+ import { openMemoryBackend } from './backends/memory.js';
6
+ import { openSqliteBackend } from './backends/sqlite.js';
7
+ import { DataStoreMigrationError, DataStoreVersionError } from './data-store.js';
8
+ import { isDbNewerThanCli, readSupportedDbVersion } from './schema-version.js';
9
+ function defaultMigrationsFolder() {
10
+ return join(fileURLToPath(new URL('.', import.meta.url)), '..', 'migrations');
11
+ }
12
+ export const DataStoreFactory = {
13
+ /**
14
+ * Open a DataStore (SQLite or in-memory) and run pending migrations.
15
+ *
16
+ * For SQLite, a version guard runs first: if the file was stamped by a NEWER
17
+ * CLI than this one (`PRAGMA user_version` ahead of the bundled migration
18
+ * count), it throws {@link DataStoreVersionError} instead of letting Drizzle
19
+ * silently no-op into a runtime column error. After a successful migrate, the
20
+ * stamp is refreshed to this CLI's supported version.
21
+ *
22
+ * @throws {DataStoreVersionError} When the SQLite file was written by a newer
23
+ * opensip-cli than this CLI supports (the downgrade direction).
24
+ * @throws {DataStoreMigrationError} When the SQLite file cannot be opened
25
+ * (corrupt header, missing parent directory, permission errors), when the
26
+ * native `better-sqlite3` binding fails to load (an ABI mismatch — the file
27
+ * is fine, the addon was built for a different Node.js version), or when
28
+ * running the migrations folder fails. The original cause is preserved via
29
+ * the `cause` field; the message distinguishes the binding case so callers
30
+ * are not told to delete a healthy data store.
31
+ */
32
+ open(opts) {
33
+ const migrationsFolder = opts.migrationsFolder ?? defaultMigrationsFolder();
34
+ if (opts.backend === 'memory') {
35
+ return openAndMigrate(opts, migrationsFolder, () => openMemoryBackend());
36
+ }
37
+ const path = requireSqlitePath(opts);
38
+ let handle;
39
+ try {
40
+ handle = openSqliteBackend({ path });
41
+ }
42
+ catch (error) {
43
+ // Corrupted file (bad SQLite header), missing dir, permission errors, or a
44
+ // native-binding ABI mismatch (better-sqlite3 built for another Node.js).
45
+ throw new DataStoreMigrationError(openFailureMessage(opts, error), { cause: error });
46
+ }
47
+ // `undefined` (unreadable journal) means "skip the guard" — migrate() reads
48
+ // the same journal and will surface the canonical failure loudly.
49
+ const supportedVersion = readSupportedDbVersion(migrationsFolder);
50
+ if (supportedVersion !== undefined) {
51
+ const dbVersion = handle.readUserVersion();
52
+ if (isDbNewerThanCli(dbVersion, supportedVersion)) {
53
+ handle.close();
54
+ throw new DataStoreVersionError({ path, dbVersion, supportedVersion });
55
+ }
56
+ }
57
+ try {
58
+ migrate(handle.db, { migrationsFolder });
59
+ }
60
+ catch (error) {
61
+ handle.close();
62
+ throw new DataStoreMigrationError(migrateFailureMessage(opts), { cause: error });
63
+ }
64
+ // Re-stamp on every successful open: a fresh (0) or pre-guard "legacy" DB
65
+ // gets adopted to the current version; an already-current DB is a no-op write.
66
+ if (supportedVersion !== undefined)
67
+ handle.writeUserVersion(supportedVersion);
68
+ return handle;
69
+ },
70
+ };
71
+ /**
72
+ * Open a backend and run migrations, mapping both failures to
73
+ * {@link DataStoreMigrationError}. Used for the in-memory path (which needs no
74
+ * version guard — it is ephemeral) and shared message handling.
75
+ *
76
+ * @throws {DataStoreMigrationError} When the backend cannot be opened or the
77
+ * migrations folder fails to apply; the original cause is preserved.
78
+ */
79
+ function openAndMigrate(opts, migrationsFolder, openBackend) {
80
+ let datastore;
81
+ try {
82
+ datastore = openBackend();
83
+ }
84
+ catch (error) {
85
+ throw new DataStoreMigrationError(openFailureMessage(opts, error), { cause: error });
86
+ }
87
+ try {
88
+ migrate(datastore.db, { migrationsFolder });
89
+ }
90
+ catch (error) {
91
+ datastore.close();
92
+ throw new DataStoreMigrationError(migrateFailureMessage(opts), { cause: error });
93
+ }
94
+ return datastore;
95
+ }
96
+ /**
97
+ * Detect a native-binding load failure: `better-sqlite3`'s compiled addon was
98
+ * built for a different Node.js ABI than the one now running (e.g. the binding
99
+ * was compiled under Node 22 and the CLI is run under Node 24). This is NOT a
100
+ * data problem — the SQLite file is intact and must not be deleted; the fix is
101
+ * to rebuild the native module for the current Node.js.
102
+ *
103
+ * Identified by the Node loader's `ERR_DLOPEN_FAILED` code or the
104
+ * `NODE_MODULE_VERSION` / "compiled against a different Node.js version" text,
105
+ * scanned across the whole `cause` chain (the error may be wrapped).
106
+ */
107
+ export function isNativeBindingError(error) {
108
+ for (let current = error; current instanceof Error; current = current.cause) {
109
+ if (current.code === 'ERR_DLOPEN_FAILED')
110
+ return true;
111
+ if (/NODE_MODULE_VERSION|compiled against a different Node\.js version/i.test(current.message)) {
112
+ return true;
113
+ }
114
+ }
115
+ return false;
116
+ }
117
+ /**
118
+ * Build the user-facing message for a data-store open failure, choosing the
119
+ * remediation that matches the actual cause: a native-binding ABI mismatch
120
+ * (rebuild the addon — the data is fine) vs a genuine corrupt/permission/
121
+ * non-writable SQLite file (delete to start fresh) vs an in-memory programming
122
+ * error. Separated from the throw site so the cause→message mapping is unit
123
+ * testable without exercising the real binding.
124
+ */
125
+ export function openFailureMessage(opts, error) {
126
+ // A native-binding ABI mismatch is not a corrupt/missing file — telling the
127
+ // user to delete the data store would destroy healthy session history for no
128
+ // reason. Steer them to rebuild the addon instead, regardless of backend.
129
+ if (isNativeBindingError(error)) {
130
+ return `Failed to load the native SQLite module (better-sqlite3): its compiled binding was built for a different Node.js version than the one now running. Your data store is NOT corrupt — do not delete it. Rebuild the native module for your current Node.js with \`pnpm rebuild better-sqlite3\`, and run opensip on the Node.js version this project targets (see \`.nvmrc\` / the package.json \`engines\` field).`;
131
+ }
132
+ if (opts.backend === 'sqlite' && opts.path) {
133
+ return `Failed to open SQLite data store at \`${opts.path}\` — the file may be corrupted, missing permissions, or in a non-writable directory. Delete \`${opts.path}\` to start fresh (cache will rebuild on next run; session history will be lost).`;
134
+ }
135
+ return 'Failed to open in-memory data store; this is likely a programming error.';
136
+ }
137
+ function migrateFailureMessage(opts) {
138
+ if (opts.backend === 'sqlite' && opts.path) {
139
+ return `Schema migration failed against \`${opts.path}\`; the local cache may be from an incompatible version. Delete \`${opts.path}\` to start fresh (cache will rebuild on next run; session history will be lost).`;
140
+ }
141
+ return 'Schema migration failed against the in-memory backend; this is likely a programming error.';
142
+ }
143
+ function requireSqlitePath(opts) {
144
+ if (!opts.path) {
145
+ throw new ConfigurationError('DataStoreFactory.open: SQLite backend requires a `path` option', {
146
+ code: 'CONFIGURATION.DATASTORE.MISSING_PATH',
147
+ });
148
+ }
149
+ return opts.path;
150
+ }
151
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type { DataStore, DataStoreOpenOptions, DataStoreVersionMismatch, DrizzleDataStore, DrizzleHandle, SqliteBackendHandle, } from './data-store.js';
2
+ export { DataStoreMigrationError, DataStoreVersionError, isDrizzleDataStore, requireDrizzleDataStore, } from './data-store.js';
3
+ export { DataStoreFactory } from './factory.js';
4
+ export { isDbNewerThanCli, readSupportedDbVersion } from './schema-version.js';
5
+ export { toolBaselineEntries, toolBaselineMeta } from './schema/baseline.js';
6
+ export { BaselineRepo } from './baseline-repo.js';
7
+ export { toolState } from './schema/tool-state.js';
8
+ export { ToolStateRepo, TOOL_STATE_MAX_PAYLOAD_BYTES } from './tool-state-repo.js';
9
+ export type { BaselineEntry, BaselineRow } from './baseline-repo.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,SAAS,EACT,oBAAoB,EACpB,wBAAwB,EACxB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAG/E,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACnF,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { DataStoreMigrationError, DataStoreVersionError, isDrizzleDataStore, requireDrizzleDataStore, } from './data-store.js';
2
+ export { DataStoreFactory } from './factory.js';
3
+ export { isDbNewerThanCli, readSupportedDbVersion } from './schema-version.js';
4
+ // Generic host-owned baseline/ratchet plane (ADR-0036): the shared table pair
5
+ // + the per-tool repo over them.
6
+ export { toolBaselineEntries, toolBaselineMeta } from './schema/baseline.js';
7
+ export { BaselineRepo } from './baseline-repo.js';
8
+ // ADR-0042: the generic keyed tool-state table + repo (the cli.toolState seams).
9
+ export { toolState } from './schema/tool-state.js';
10
+ export { ToolStateRepo, TOOL_STATE_MAX_PAYLOAD_BYTES } from './tool-state-repo.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,8EAA8E;AAC9E,iCAAiC;AACjC,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,iFAAiF;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Generic host-owned baseline entries (ADR-0036). ONE table pair replaces the
3
+ * per-tool baseline tables (`graph_baseline_signals`, `fit_baseline`, …): each
4
+ * row is one finding's fingerprint + its full `Signal` payload, scoped by the
5
+ * `tool` column so tools share the table but never see each other's rows.
6
+ *
7
+ * The composite primary key `(tool, fingerprint)` makes save a per-tool
8
+ * delete-all + bulk-insert (atomic replace), and the `payload` column supplies
9
+ * the full-object `resolved` diff bucket AND the SARIF re-render
10
+ * (synthetic envelope → `formatSignalSarif`).
11
+ */
12
+ export declare const toolBaselineEntries: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
13
+ name: "tool_baseline_entries";
14
+ schema: undefined;
15
+ columns: {
16
+ tool: import("drizzle-orm/sqlite-core").SQLiteColumn<{
17
+ name: "tool";
18
+ tableName: "tool_baseline_entries";
19
+ dataType: "string";
20
+ columnType: "SQLiteText";
21
+ data: string;
22
+ driverParam: string;
23
+ notNull: true;
24
+ hasDefault: false;
25
+ isPrimaryKey: false;
26
+ isAutoincrement: false;
27
+ hasRuntimeDefault: false;
28
+ enumValues: [string, ...string[]];
29
+ baseColumn: never;
30
+ identity: undefined;
31
+ generated: undefined;
32
+ }, {}, {
33
+ length: number | undefined;
34
+ }>;
35
+ stableId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
36
+ name: "stable_id";
37
+ tableName: "tool_baseline_entries";
38
+ dataType: "string";
39
+ columnType: "SQLiteText";
40
+ data: string;
41
+ driverParam: string;
42
+ notNull: false;
43
+ hasDefault: false;
44
+ isPrimaryKey: false;
45
+ isAutoincrement: false;
46
+ hasRuntimeDefault: false;
47
+ enumValues: [string, ...string[]];
48
+ baseColumn: never;
49
+ identity: undefined;
50
+ generated: undefined;
51
+ }, {}, {
52
+ length: number | undefined;
53
+ }>;
54
+ fingerprint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
55
+ name: "fingerprint";
56
+ tableName: "tool_baseline_entries";
57
+ dataType: "string";
58
+ columnType: "SQLiteText";
59
+ data: string;
60
+ driverParam: string;
61
+ notNull: true;
62
+ hasDefault: false;
63
+ isPrimaryKey: false;
64
+ isAutoincrement: false;
65
+ hasRuntimeDefault: false;
66
+ enumValues: [string, ...string[]];
67
+ baseColumn: never;
68
+ identity: undefined;
69
+ generated: undefined;
70
+ }, {}, {
71
+ length: number | undefined;
72
+ }>;
73
+ payload: import("drizzle-orm/sqlite-core").SQLiteColumn<{
74
+ name: "payload";
75
+ tableName: "tool_baseline_entries";
76
+ dataType: "json";
77
+ columnType: "SQLiteTextJson";
78
+ data: unknown;
79
+ driverParam: string;
80
+ notNull: false;
81
+ hasDefault: false;
82
+ isPrimaryKey: false;
83
+ isAutoincrement: false;
84
+ hasRuntimeDefault: false;
85
+ enumValues: undefined;
86
+ baseColumn: never;
87
+ identity: undefined;
88
+ generated: undefined;
89
+ }, {}, {}>;
90
+ capturedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
91
+ name: "captured_at";
92
+ tableName: "tool_baseline_entries";
93
+ dataType: "number";
94
+ columnType: "SQLiteInteger";
95
+ data: number;
96
+ driverParam: number;
97
+ notNull: true;
98
+ hasDefault: false;
99
+ isPrimaryKey: false;
100
+ isAutoincrement: false;
101
+ hasRuntimeDefault: false;
102
+ enumValues: undefined;
103
+ baseColumn: never;
104
+ identity: undefined;
105
+ generated: undefined;
106
+ }, {}, {}>;
107
+ };
108
+ dialect: "sqlite";
109
+ }>;
110
+ /**
111
+ * Per-tool baseline existence marker + capture timestamp (ADR-0036). Keyed by
112
+ * `tool`, separate from the entries so an empty-but-saved baseline (a clean
113
+ * codebase) still reports `exists() === true` — distinguishing "saved, no
114
+ * findings" from "never saved". `capturedAt` feeds the JSON export's timestamp.
115
+ */
116
+ export declare const toolBaselineMeta: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
117
+ name: "tool_baseline_meta";
118
+ schema: undefined;
119
+ columns: {
120
+ tool: import("drizzle-orm/sqlite-core").SQLiteColumn<{
121
+ name: "tool";
122
+ tableName: "tool_baseline_meta";
123
+ dataType: "string";
124
+ columnType: "SQLiteText";
125
+ data: string;
126
+ driverParam: string;
127
+ notNull: true;
128
+ hasDefault: false;
129
+ isPrimaryKey: true;
130
+ isAutoincrement: false;
131
+ hasRuntimeDefault: false;
132
+ enumValues: [string, ...string[]];
133
+ baseColumn: never;
134
+ identity: undefined;
135
+ generated: undefined;
136
+ }, {}, {
137
+ length: number | undefined;
138
+ }>;
139
+ stableId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
140
+ name: "stable_id";
141
+ tableName: "tool_baseline_meta";
142
+ dataType: "string";
143
+ columnType: "SQLiteText";
144
+ data: string;
145
+ driverParam: string;
146
+ notNull: false;
147
+ hasDefault: false;
148
+ isPrimaryKey: false;
149
+ isAutoincrement: false;
150
+ hasRuntimeDefault: false;
151
+ enumValues: [string, ...string[]];
152
+ baseColumn: never;
153
+ identity: undefined;
154
+ generated: undefined;
155
+ }, {}, {
156
+ length: number | undefined;
157
+ }>;
158
+ capturedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
159
+ name: "captured_at";
160
+ tableName: "tool_baseline_meta";
161
+ dataType: "number";
162
+ columnType: "SQLiteInteger";
163
+ data: number;
164
+ driverParam: number;
165
+ notNull: true;
166
+ hasDefault: false;
167
+ isPrimaryKey: false;
168
+ isAutoincrement: false;
169
+ hasRuntimeDefault: false;
170
+ enumValues: undefined;
171
+ baseColumn: never;
172
+ identity: undefined;
173
+ generated: undefined;
174
+ }, {}, {}>;
175
+ };
176
+ dialect: "sqlite";
177
+ }>;
178
+ //# sourceMappingURL=baseline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../src/schema/baseline.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI3B,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { integer, primaryKey, sqliteTable, text } from 'drizzle-orm/sqlite-core';
2
+ /**
3
+ * Generic host-owned baseline entries (ADR-0036). ONE table pair replaces the
4
+ * per-tool baseline tables (`graph_baseline_signals`, `fit_baseline`, …): each
5
+ * row is one finding's fingerprint + its full `Signal` payload, scoped by the
6
+ * `tool` column so tools share the table but never see each other's rows.
7
+ *
8
+ * The composite primary key `(tool, fingerprint)` makes save a per-tool
9
+ * delete-all + bulk-insert (atomic replace), and the `payload` column supplies
10
+ * the full-object `resolved` diff bucket AND the SARIF re-render
11
+ * (synthetic envelope → `formatSignalSarif`).
12
+ */
13
+ export const toolBaselineEntries = sqliteTable('tool_baseline_entries', {
14
+ tool: text('tool').notNull(), // human `name` value (for compat + current queries)
15
+ stableId: text('stable_id'), // tool stable UUID (additive per ADR-0048; null for legacy rows)
16
+ fingerprint: text('fingerprint').notNull(),
17
+ payload: text('payload', { mode: 'json' }), // the Signal as JSON
18
+ capturedAt: integer('captured_at').notNull(),
19
+ }, (t) => [primaryKey({ columns: [t.tool, t.fingerprint] })]);
20
+ /**
21
+ * Per-tool baseline existence marker + capture timestamp (ADR-0036). Keyed by
22
+ * `tool`, separate from the entries so an empty-but-saved baseline (a clean
23
+ * codebase) still reports `exists() === true` — distinguishing "saved, no
24
+ * findings" from "never saved". `capturedAt` feeds the JSON export's timestamp.
25
+ */
26
+ export const toolBaselineMeta = sqliteTable('tool_baseline_meta', {
27
+ tool: text('tool').primaryKey(), // human `name` value (for compat)
28
+ stableId: text('stable_id'), // tool stable UUID (additive)
29
+ capturedAt: integer('captured_at').notNull(),
30
+ });
31
+ //# sourceMappingURL=baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../src/schema/baseline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEjF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAC5C,uBAAuB,EACvB;IACE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,oDAAoD;IAClF,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,iEAAiE;IAC9F,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;IAC1C,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,qBAAqB;IACjE,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;CAC7C,EACD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAC1D,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC,oBAAoB,EAAE;IAChE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,kCAAkC;IACnE,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE,8BAA8B;IAC3D,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;CAC7C,CAAC,CAAC"}