@rocicorp/zero 1.0.0 → 1.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 (126) hide show
  1. package/out/_virtual/{_@oxc-project_runtime@0.115.0 → _@oxc-project_runtime@0.122.0}/helpers/usingCtx.js +1 -1
  2. package/out/analyze-query/src/bin-analyze.js +19 -7
  3. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  4. package/out/replicache/src/mutation-recovery.js +0 -3
  5. package/out/zero/package.js +7 -6
  6. package/out/zero/package.js.map +1 -1
  7. package/out/zero-cache/src/config/zero-config.d.ts +6 -0
  8. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  9. package/out/zero-cache/src/config/zero-config.js +12 -0
  10. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  11. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
  12. package/out/zero-cache/src/server/anonymous-otel-start.js +1 -14
  13. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  14. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  15. package/out/zero-cache/src/server/change-streamer.js +2 -2
  16. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  17. package/out/zero-cache/src/services/analyze.js +2 -2
  18. package/out/zero-cache/src/services/change-source/change-source.d.ts +7 -0
  19. package/out/zero-cache/src/services/change-source/change-source.d.ts.map +1 -1
  20. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +1 -1
  21. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +1 -1
  22. package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
  23. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  24. package/out/zero-cache/src/services/change-source/custom/change-source.js +3 -0
  25. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  26. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +9 -1
  27. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  28. package/out/zero-cache/src/services/change-source/pg/change-source.js +172 -46
  29. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  30. package/out/zero-cache/src/services/change-source/pg/lsn.js +1 -1
  31. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +8 -0
  32. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  33. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +26 -1
  34. package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
  35. package/out/zero-cache/src/services/change-source/protocol/current/status.js +7 -2
  36. package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
  37. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +8 -0
  38. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  39. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  40. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +10 -2
  41. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  42. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +25 -0
  43. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  44. package/out/zero-cache/src/services/change-streamer/change-streamer.js +8 -1
  45. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  46. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +2 -0
  47. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  48. package/out/zero-cache/src/services/change-streamer/forwarder.js +3 -0
  49. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  50. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +3 -2
  51. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  52. package/out/zero-cache/src/services/change-streamer/subscriber.js +17 -8
  53. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  54. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  55. package/out/zero-cache/src/services/life-cycle.js +6 -2
  56. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  57. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +2 -2
  58. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  59. package/out/zero-cache/src/services/replicator/incremental-sync.js +19 -4
  60. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  61. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  62. package/out/zero-cache/src/services/replicator/replicator.js +2 -2
  63. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  64. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +12 -0
  65. package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +1 -0
  66. package/out/zero-cache/src/services/replicator/reporter/recorder.js +58 -0
  67. package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -0
  68. package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts +35 -0
  69. package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts.map +1 -0
  70. package/out/zero-cache/src/services/replicator/reporter/report-schema.js +20 -0
  71. package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -0
  72. package/out/zero-cache/src/services/run-ast.js +1 -1
  73. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +1 -1
  74. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  75. package/out/zero-cache/src/types/pg.js +2 -0
  76. package/out/zero-cache/src/types/pg.js.map +1 -1
  77. package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
  78. package/out/zero-cache/src/workers/replicator.js +1 -0
  79. package/out/zero-cache/src/workers/replicator.js.map +1 -1
  80. package/out/zero-client/src/client/version.js +1 -1
  81. package/out/zql/src/builder/builder.d.ts.map +1 -1
  82. package/out/zql/src/builder/builder.js +15 -5
  83. package/out/zql/src/builder/builder.js.map +1 -1
  84. package/out/zql/src/ivm/cap.d.ts +32 -0
  85. package/out/zql/src/ivm/cap.d.ts.map +1 -0
  86. package/out/zql/src/ivm/cap.js +226 -0
  87. package/out/zql/src/ivm/cap.js.map +1 -0
  88. package/out/zql/src/ivm/join-utils.d.ts +2 -0
  89. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  90. package/out/zql/src/ivm/join-utils.js +35 -1
  91. package/out/zql/src/ivm/join-utils.js.map +1 -1
  92. package/out/zql/src/ivm/join.d.ts.map +1 -1
  93. package/out/zql/src/ivm/join.js +6 -2
  94. package/out/zql/src/ivm/join.js.map +1 -1
  95. package/out/zql/src/ivm/memory-source.d.ts +15 -2
  96. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  97. package/out/zql/src/ivm/memory-source.js +69 -8
  98. package/out/zql/src/ivm/memory-source.js.map +1 -1
  99. package/out/zql/src/ivm/schema.d.ts +1 -1
  100. package/out/zql/src/ivm/schema.d.ts.map +1 -1
  101. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  102. package/out/zql/src/ivm/skip.js +3 -0
  103. package/out/zql/src/ivm/skip.js.map +1 -1
  104. package/out/zql/src/ivm/source.d.ts +1 -1
  105. package/out/zql/src/ivm/source.d.ts.map +1 -1
  106. package/out/zql/src/ivm/take.d.ts +4 -1
  107. package/out/zql/src/ivm/take.d.ts.map +1 -1
  108. package/out/zql/src/ivm/take.js +4 -2
  109. package/out/zql/src/ivm/take.js.map +1 -1
  110. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  111. package/out/zql/src/ivm/union-fan-in.js +1 -0
  112. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  113. package/out/zqlite/src/query-builder.d.ts +1 -1
  114. package/out/zqlite/src/query-builder.d.ts.map +1 -1
  115. package/out/zqlite/src/query-builder.js +7 -2
  116. package/out/zqlite/src/query-builder.js.map +1 -1
  117. package/out/zqlite/src/table-source.d.ts +1 -1
  118. package/out/zqlite/src/table-source.d.ts.map +1 -1
  119. package/out/zqlite/src/table-source.js +15 -10
  120. package/out/zqlite/src/table-source.js.map +1 -1
  121. package/package.json +7 -6
  122. package/out/analyze-query/src/run-ast.d.ts +0 -22
  123. package/out/analyze-query/src/run-ast.d.ts.map +0 -1
  124. package/out/analyze-query/src/run-ast.js +0 -75
  125. package/out/analyze-query/src/run-ast.js.map +0 -1
  126. package/out/replicache/src/mutation-recovery.js.map +0 -1
@@ -1,22 +0,0 @@
1
- import type { LogContext } from '@rocicorp/logger';
2
- import type { LiteAndZqlSpec } from '../../zero-cache/src/db/specs.ts';
3
- import type { AnalyzeQueryResult } from '../../zero-protocol/src/analyze-query-result.ts';
4
- import type { AST } from '../../zero-protocol/src/ast.ts';
5
- import type { ClientSchema } from '../../zero-protocol/src/client-schema.ts';
6
- import type { PermissionsConfig } from '../../zero-schema/src/compiled-permissions.ts';
7
- import type { NameMapper } from '../../zero-schema/src/name-mapper.ts';
8
- import { type BuilderDelegate } from '../../zql/src/builder/builder.ts';
9
- import type { Database } from '../../zqlite/src/db.ts';
10
- export type RunAstOptions = {
11
- applyPermissions?: boolean | undefined;
12
- authData?: string | undefined;
13
- clientToServerMapper?: NameMapper | undefined;
14
- db: Database;
15
- host: BuilderDelegate;
16
- permissions?: PermissionsConfig | undefined;
17
- syncedRows?: boolean | undefined;
18
- tableSpecs: Map<string, LiteAndZqlSpec>;
19
- vendedRows?: boolean | undefined;
20
- };
21
- export declare function runAst(lc: LogContext, clientSchema: ClientSchema, ast: AST, isTransformed: boolean, options: RunAstOptions): Promise<AnalyzeQueryResult>;
22
- //# sourceMappingURL=run-ast.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-ast.d.ts","sourceRoot":"","sources":["../../../../analyze-query/src/run-ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAQjD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AAErE,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iDAAiD,CAAC;AACxF,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,gCAAgC,CAAC;AAExD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,0CAA0C,CAAC;AAG3E,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,+CAA+C,CAAC;AACrF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG;IAC1B,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,oBAAoB,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC9C,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC5C,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF,wBAAsB,MAAM,CAC1B,EAAE,EAAE,UAAU,EACd,YAAY,EAAE,YAAY,EAC1B,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,OAAO,EACtB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,kBAAkB,CAAC,CAyG7B"}
@@ -1,75 +0,0 @@
1
- import { assert } from "../../shared/src/asserts.js";
2
- import { must } from "../../shared/src/must.js";
3
- import { mapAST } from "../../zero-protocol/src/ast.js";
4
- import { hashOfAST } from "../../zero-protocol/src/query-hash.js";
5
- import { buildPipeline } from "../../zql/src/builder/builder.js";
6
- import { computeZqlSpecs } from "../../zero-cache/src/db/lite-tables.js";
7
- import { astToZQL } from "../../ast-to-zql/src/ast-to-zql.js";
8
- import { formatOutput } from "../../ast-to-zql/src/format.js";
9
- import { transformAndHashQuery } from "../../zero-cache/src/auth/read-authorizer.js";
10
- import { hydrate } from "../../zero-cache/src/services/view-syncer/pipeline-driver.js";
11
- //#region ../analyze-query/src/run-ast.ts
12
- async function runAst(lc, clientSchema, ast, isTransformed, options) {
13
- const { clientToServerMapper, permissions, host, db } = options;
14
- const result = {
15
- warnings: [],
16
- syncedRows: void 0,
17
- syncedRowCount: 0,
18
- start: 0,
19
- end: 0,
20
- afterPermissions: void 0,
21
- readRows: void 0,
22
- readRowCountsByQuery: {},
23
- readRowCount: void 0
24
- };
25
- if (!isTransformed) ast = mapAST(ast, must(clientToServerMapper));
26
- if (options.applyPermissions) {
27
- result.warnings.push("Permissions are deprecated and will be removed in an upcoming release. See: https://zero.rocicorp.dev/docs/auth.");
28
- const authData = options.authData ? JSON.parse(options.authData) : {};
29
- if (!options.authData) result.warnings.push("No auth data provided. Permission rules will compare to `NULL` wherever an auth data field is referenced.");
30
- const auth = {
31
- type: "jwt",
32
- raw: "",
33
- decoded: authData
34
- };
35
- ast = transformAndHashQuery(lc, "clientGroupIDForAnalyze", ast, must(permissions, "Permissions are required when applyPermissions is true"), auth, false).transformedAst;
36
- result.afterPermissions = await formatOutput(ast.table + astToZQL(ast));
37
- }
38
- const pipeline = buildPipeline(ast, host, "query-id");
39
- const start = performance.now();
40
- let syncedRowCount = 0;
41
- const rowsByTable = {};
42
- const seenByTable = /* @__PURE__ */ new Set();
43
- const tableSpecs = computeZqlSpecs(lc, db, { includeBackfillingColumns: false });
44
- for (const rowChange of hydrate(pipeline, hashOfAST(ast), clientSchema, tableSpecs)) {
45
- if (rowChange === "yield") continue;
46
- assert(rowChange.type === "add", () => `Expected rowChange type 'add', got '${rowChange.type}'`);
47
- let rows = rowsByTable[rowChange.table];
48
- const s = rowChange.table + "." + JSON.stringify(rowChange.row);
49
- if (seenByTable.has(s)) continue;
50
- syncedRowCount++;
51
- seenByTable.add(s);
52
- if (options.syncedRows) {
53
- if (!rows) {
54
- rows = [];
55
- rowsByTable[rowChange.table] = rows;
56
- }
57
- rows.push(rowChange.row);
58
- }
59
- }
60
- const end = performance.now();
61
- if (options.syncedRows) result.syncedRows = rowsByTable;
62
- result.start = start;
63
- result.end = end;
64
- result.syncedRowCount = syncedRowCount;
65
- result.readRowCountsByQuery = host.debug?.getVendedRowCounts() ?? {};
66
- let readRowCount = 0;
67
- for (const c of Object.values(result.readRowCountsByQuery)) for (const v of Object.values(c)) readRowCount += v;
68
- result.readRowCount = readRowCount;
69
- if (options.vendedRows) result.readRows = host.debug?.getVendedRows();
70
- return result;
71
- }
72
- //#endregion
73
- export { runAst };
74
-
75
- //# sourceMappingURL=run-ast.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-ast.js","names":[],"sources":["../../../../analyze-query/src/run-ast.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {astToZQL} from '../../ast-to-zql/src/ast-to-zql.ts';\nimport {formatOutput} from '../../ast-to-zql/src/format.ts';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {must} from '../../shared/src/must.ts';\nimport type {JWTAuth} from '../../zero-cache/src/auth/auth.ts';\nimport {transformAndHashQuery} from '../../zero-cache/src/auth/read-authorizer.ts';\nimport {computeZqlSpecs} from '../../zero-cache/src/db/lite-tables.ts';\nimport type {LiteAndZqlSpec} from '../../zero-cache/src/db/specs.ts';\nimport {hydrate} from '../../zero-cache/src/services/view-syncer/pipeline-driver.ts';\nimport type {AnalyzeQueryResult} from '../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../zero-protocol/src/ast.ts';\nimport {mapAST} from '../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../zero-protocol/src/data.ts';\nimport {hashOfAST} from '../../zero-protocol/src/query-hash.ts';\nimport type {PermissionsConfig} from '../../zero-schema/src/compiled-permissions.ts';\nimport type {NameMapper} from '../../zero-schema/src/name-mapper.ts';\nimport {\n buildPipeline,\n type BuilderDelegate,\n} from '../../zql/src/builder/builder.ts';\nimport type {Database} from '../../zqlite/src/db.ts';\n\nexport type RunAstOptions = {\n applyPermissions?: boolean | undefined;\n authData?: string | undefined;\n clientToServerMapper?: NameMapper | undefined;\n db: Database;\n host: BuilderDelegate;\n permissions?: PermissionsConfig | undefined;\n syncedRows?: boolean | undefined;\n tableSpecs: Map<string, LiteAndZqlSpec>;\n vendedRows?: boolean | undefined;\n};\n\nexport async function runAst(\n lc: LogContext,\n clientSchema: ClientSchema,\n ast: AST,\n isTransformed: boolean,\n options: RunAstOptions,\n): Promise<AnalyzeQueryResult> {\n const {clientToServerMapper, permissions, host, db} = options;\n const result: AnalyzeQueryResult = {\n warnings: [],\n syncedRows: undefined,\n syncedRowCount: 0,\n start: 0,\n end: 0,\n afterPermissions: undefined,\n readRows: undefined,\n readRowCountsByQuery: {},\n readRowCount: undefined,\n };\n\n if (!isTransformed) {\n // map the AST to server names if not already transformed\n ast = mapAST(ast, must(clientToServerMapper));\n }\n if (options.applyPermissions) {\n result.warnings.push(\n 'Permissions are deprecated and will be removed in an upcoming release. See: https://zero.rocicorp.dev/docs/auth.',\n );\n\n const authData = options.authData ? JSON.parse(options.authData) : {};\n if (!options.authData) {\n result.warnings.push(\n 'No auth data provided. Permission rules will compare to `NULL` wherever an auth data field is referenced.',\n );\n }\n const auth: JWTAuth = {type: 'jwt', raw: '', decoded: authData};\n ast = transformAndHashQuery(\n lc,\n 'clientGroupIDForAnalyze',\n ast,\n must(\n permissions,\n 'Permissions are required when applyPermissions is true',\n ),\n auth,\n false,\n ).transformedAst;\n result.afterPermissions = await formatOutput(ast.table + astToZQL(ast));\n }\n const pipeline = buildPipeline(ast, host, 'query-id');\n\n const start = performance.now();\n\n let syncedRowCount = 0;\n const rowsByTable: Record<string, Row[]> = {};\n const seenByTable: Set<string> = new Set();\n const tableSpecs = computeZqlSpecs(lc, db, {\n includeBackfillingColumns: false,\n });\n for (const rowChange of hydrate(\n pipeline,\n hashOfAST(ast),\n clientSchema,\n tableSpecs,\n )) {\n if (rowChange === 'yield') {\n continue;\n }\n assert(\n rowChange.type === 'add',\n () => `Expected rowChange type 'add', got '${rowChange.type}'`,\n );\n\n let rows: Row[] = rowsByTable[rowChange.table];\n const s = rowChange.table + '.' + JSON.stringify(rowChange.row);\n if (seenByTable.has(s)) {\n continue; // skip duplicates\n }\n syncedRowCount++;\n seenByTable.add(s);\n if (options.syncedRows) {\n if (!rows) {\n rows = [];\n rowsByTable[rowChange.table] = rows;\n }\n rows.push(rowChange.row);\n }\n }\n\n const end = performance.now();\n if (options.syncedRows) {\n result.syncedRows = rowsByTable;\n }\n result.start = start;\n result.end = end;\n\n // Always include the count of synced and vended rows.\n result.syncedRowCount = syncedRowCount;\n result.readRowCountsByQuery = host.debug?.getVendedRowCounts() ?? {};\n let readRowCount = 0;\n for (const c of Object.values(result.readRowCountsByQuery)) {\n for (const v of Object.values(c)) {\n readRowCount += v;\n }\n }\n result.readRowCount = readRowCount;\n\n if (options.vendedRows) {\n result.readRows = host.debug?.getVendedRows();\n }\n return result;\n}\n"],"mappings":";;;;;;;;;;;AAoCA,eAAsB,OACpB,IACA,cACA,KACA,eACA,SAC6B;CAC7B,MAAM,EAAC,sBAAsB,aAAa,MAAM,OAAM;CACtD,MAAM,SAA6B;EACjC,UAAU,EAAE;EACZ,YAAY,KAAA;EACZ,gBAAgB;EAChB,OAAO;EACP,KAAK;EACL,kBAAkB,KAAA;EAClB,UAAU,KAAA;EACV,sBAAsB,EAAE;EACxB,cAAc,KAAA;EACf;AAED,KAAI,CAAC,cAEH,OAAM,OAAO,KAAK,KAAK,qBAAqB,CAAC;AAE/C,KAAI,QAAQ,kBAAkB;AAC5B,SAAO,SAAS,KACd,mHACD;EAED,MAAM,WAAW,QAAQ,WAAW,KAAK,MAAM,QAAQ,SAAS,GAAG,EAAE;AACrE,MAAI,CAAC,QAAQ,SACX,QAAO,SAAS,KACd,4GACD;EAEH,MAAM,OAAgB;GAAC,MAAM;GAAO,KAAK;GAAI,SAAS;GAAS;AAC/D,QAAM,sBACJ,IACA,2BACA,KACA,KACE,aACA,yDACD,EACD,MACA,MACD,CAAC;AACF,SAAO,mBAAmB,MAAM,aAAa,IAAI,QAAQ,SAAS,IAAI,CAAC;;CAEzE,MAAM,WAAW,cAAc,KAAK,MAAM,WAAW;CAErD,MAAM,QAAQ,YAAY,KAAK;CAE/B,IAAI,iBAAiB;CACrB,MAAM,cAAqC,EAAE;CAC7C,MAAM,8BAA2B,IAAI,KAAK;CAC1C,MAAM,aAAa,gBAAgB,IAAI,IAAI,EACzC,2BAA2B,OAC5B,CAAC;AACF,MAAK,MAAM,aAAa,QACtB,UACA,UAAU,IAAI,EACd,cACA,WACD,EAAE;AACD,MAAI,cAAc,QAChB;AAEF,SACE,UAAU,SAAS,aACb,uCAAuC,UAAU,KAAK,GAC7D;EAED,IAAI,OAAc,YAAY,UAAU;EACxC,MAAM,IAAI,UAAU,QAAQ,MAAM,KAAK,UAAU,UAAU,IAAI;AAC/D,MAAI,YAAY,IAAI,EAAE,CACpB;AAEF;AACA,cAAY,IAAI,EAAE;AAClB,MAAI,QAAQ,YAAY;AACtB,OAAI,CAAC,MAAM;AACT,WAAO,EAAE;AACT,gBAAY,UAAU,SAAS;;AAEjC,QAAK,KAAK,UAAU,IAAI;;;CAI5B,MAAM,MAAM,YAAY,KAAK;AAC7B,KAAI,QAAQ,WACV,QAAO,aAAa;AAEtB,QAAO,QAAQ;AACf,QAAO,MAAM;AAGb,QAAO,iBAAiB;AACxB,QAAO,uBAAuB,KAAK,OAAO,oBAAoB,IAAI,EAAE;CACpE,IAAI,eAAe;AACnB,MAAK,MAAM,KAAK,OAAO,OAAO,OAAO,qBAAqB,CACxD,MAAK,MAAM,KAAK,OAAO,OAAO,EAAE,CAC9B,iBAAgB;AAGpB,QAAO,eAAe;AAEtB,KAAI,QAAQ,WACV,QAAO,WAAW,KAAK,OAAO,eAAe;AAE/C,QAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"mutation-recovery.js","names":["#options","#recoveringMutations"],"sources":["../../../../replicache/src/mutation-recovery.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, assertNotUndefined} from '../../shared/src/asserts.ts';\nimport type {Enum} from '../../shared/src/enum.ts';\nimport type {MaybePromise} from '../../shared/src/types.ts';\nimport {throwChunkHasher} from './dag/chunk.ts';\nimport {LazyStore} from './dag/lazy-store.ts';\nimport {StoreImpl} from './dag/store-impl.ts';\nimport type {Store} from './dag/store.ts';\nimport {DEFAULT_HEAD_NAME} from './db/commit.ts';\nimport {\n type ClientStateNotFoundResponse,\n type VersionNotSupportedResponse,\n isClientStateNotFoundResponse,\n isVersionNotSupportedResponse,\n} from './error-responses.ts';\nimport * as FormatVersion from './format-version-enum.ts';\nimport {parseReplicacheFormatVersion as parseFormatVersion} from './format-version.ts';\nimport {assertHash, newRandomHash} from './hash.ts';\nimport type {HTTPRequestInfo} from './http-request-info.ts';\nimport type {CreateStore} from './kv/store.ts';\nimport {\n type ClientGroup,\n type ClientGroupMap,\n getClientGroups,\n disableClientGroup as persistDisableClientGroup,\n setClientGroups,\n} from './persist/client-groups.ts';\nimport type {\n IDBDatabasesStore,\n IndexedDBDatabase,\n} from './persist/idb-databases-store.ts';\nimport type {PullResponseOKV1, PullResponseV1, Puller} from './puller.ts';\nimport type {PushResponse, Pusher} from './pusher.ts';\nimport type {ClientGroupID, ClientID} from './sync/ids.ts';\nimport {beginPullV1} from './sync/pull.ts';\nimport {PUSH_VERSION_DD31, push} from './sync/push.ts';\nimport {withRead, withWrite} from './with-transactions.ts';\n\ntype FormatVersion = Enum<typeof FormatVersion>;\n\nconst MUTATION_RECOVERY_LAZY_STORE_SOURCE_CHUNK_CACHE_SIZE_LIMIT = 10 * 2 ** 20; // 10 MB\n\ninterface ReplicacheDelegate {\n clientID: ClientID;\n closed: boolean;\n idbName: string;\n name: string;\n online: boolean;\n profileID: Promise<string>;\n puller: Puller;\n pusher: Pusher;\n}\n\ninterface MutationRecoveryOptions {\n delegate: ReplicacheDelegate;\n readonly wrapInOnlineCheck: (\n f: () => Promise<boolean>,\n name: string,\n ) => Promise<boolean>;\n readonly wrapInReauthRetries: <R>(\n f: (\n requestID: string,\n requestLc: LogContext,\n ) => Promise<{\n httpRequestInfo: HTTPRequestInfo | undefined;\n result: R;\n }>,\n verb: string,\n lc: LogContext,\n preAuth?: () => MaybePromise<void>,\n postAuth?: () => MaybePromise<void>,\n ) => Promise<{\n result: R;\n authFailure: boolean;\n }>;\n readonly isPushDisabled: () => boolean;\n readonly isPullDisabled: () => boolean;\n readonly lc: LogContext;\n readonly enableMutationRecovery: boolean;\n readonly clientGroupIDPromise: Promise<ClientGroupID | undefined>;\n}\n\nexport class MutationRecovery {\n #recoveringMutations = false;\n readonly #options: MutationRecoveryOptions;\n\n constructor(options: MutationRecoveryOptions) {\n this.#options = options;\n }\n\n async recoverMutations(\n ready: Promise<unknown>,\n perdag: Store,\n idbDatabase: IndexedDBDatabase,\n idbDatabases: IDBDatabasesStore,\n createStore: CreateStore,\n ): Promise<boolean> {\n const {lc, enableMutationRecovery, isPushDisabled, delegate} =\n this.#options;\n\n if (\n !enableMutationRecovery ||\n this.#recoveringMutations ||\n !delegate.online ||\n delegate.closed ||\n isPushDisabled()\n ) {\n return false;\n }\n const stepDescription = 'Recovering mutations.';\n lc.debug?.('Start:', stepDescription);\n try {\n this.#recoveringMutations = true;\n await ready;\n await recoverMutationsFromPerdag(idbDatabase, this.#options, perdag);\n for (const database of Object.values(await idbDatabases.getDatabases())) {\n if (delegate.closed) {\n lc.debug?.('Exiting early due to close:', stepDescription);\n return true;\n }\n if (\n database.replicacheName === delegate.name &&\n database.name !== delegate.idbName\n ) {\n switch (database.replicacheFormatVersion) {\n case FormatVersion.SDD:\n case FormatVersion.DD31:\n case FormatVersion.V6:\n case FormatVersion.V7:\n await recoverMutationsWithNewPerdag(\n database,\n this.#options,\n createStore,\n );\n }\n }\n }\n } catch (e) {\n logMutationRecoveryError(e, lc, stepDescription, delegate);\n } finally {\n lc.debug?.('End:', stepDescription);\n this.#recoveringMutations = false;\n }\n return true;\n }\n}\n\nfunction logMutationRecoveryError(\n e: unknown,\n lc: LogContext,\n stepDescription: string,\n closedDelegate: {closed: boolean},\n) {\n if (closedDelegate.closed) {\n lc.debug?.(\n `Mutation recovery error likely due to close during:\\n${stepDescription}\\nError:\\n`,\n e,\n );\n } else {\n lc.error?.(\n `Mutation recovery error during:\\n${stepDescription}\\nError:\\n`,\n e,\n );\n }\n}\n\nasync function recoverMutationsWithNewPerdag(\n database: IndexedDBDatabase,\n options: MutationRecoveryOptions,\n createStore: CreateStore,\n) {\n const perKvStore = createStore(database.name);\n const perdag = new StoreImpl(perKvStore, newRandomHash, assertHash);\n try {\n await recoverMutationsFromPerdag(database, options, perdag);\n } finally {\n await perdag.close();\n }\n}\n\nfunction recoverMutationsFromPerdag(\n database: IndexedDBDatabase,\n options: MutationRecoveryOptions,\n perdag: Store,\n): Promise<void> {\n assert(\n database.replicacheFormatVersion >= FormatVersion.DD31,\n 'Expected replicacheFormatVersion >= DD31 for mutation recovery',\n );\n return recoverMutationsFromPerdagDD31(database, options, perdag);\n}\n\nasync function recoverMutationsFromPerdagDD31(\n database: IndexedDBDatabase,\n options: MutationRecoveryOptions,\n perdag: Store,\n): Promise<void> {\n const {delegate, lc} = options;\n const stepDescription = `Recovering mutations from db ${database.name}.`;\n lc.debug?.('Start:', stepDescription);\n try {\n const formatVersion = parseFormatVersion(database.replicacheFormatVersion);\n let clientGroups: ClientGroupMap | undefined = await withRead(\n perdag,\n read => getClientGroups(read),\n );\n const clientGroupIDsVisited = new Set<ClientGroupID>();\n while (clientGroups) {\n let newClientGroups: ClientGroupMap | undefined;\n for (const [clientGroupID, clientGroup] of clientGroups) {\n if (delegate.closed) {\n lc.debug?.('Exiting early due to close:', stepDescription);\n return;\n }\n if (!clientGroupIDsVisited.has(clientGroupID)) {\n clientGroupIDsVisited.add(clientGroupID);\n newClientGroups = await recoverMutationsOfClientGroupDD31(\n clientGroup,\n clientGroupID,\n perdag,\n database,\n options,\n formatVersion,\n );\n if (newClientGroups) {\n break;\n }\n }\n }\n clientGroups = newClientGroups;\n }\n } catch (e) {\n logMutationRecoveryError(e, lc, stepDescription, delegate);\n }\n lc.debug?.('End:', stepDescription);\n}\n\nfunction isResponseThatShouldDisableClientGroup(\n response: PushResponse | PullResponseV1 | undefined,\n): response is ClientStateNotFoundResponse | VersionNotSupportedResponse {\n return (\n isClientStateNotFoundResponse(response) ||\n isVersionNotSupportedResponse(response)\n );\n}\n\nasync function disableClientGroup(\n lc: LogContext,\n selfClientGroupID: string,\n clientGroupID: string,\n response: ClientStateNotFoundResponse | VersionNotSupportedResponse,\n perdag: Store,\n) {\n if (isClientStateNotFoundResponse(response)) {\n lc.debug?.(\n `Client group ${selfClientGroupID} cannot recover mutations for client group ${clientGroupID}. The client group is unknown on the server. Marking it as disabled.`,\n );\n } else if (isVersionNotSupportedResponse(response)) {\n lc.debug?.(\n `Client group ${selfClientGroupID} cannot recover mutations for client group ${clientGroupID}. The client group's version is not supported on the server. versionType: ${response.versionType}. Marking it as disabled.`,\n );\n }\n // The client group is not the main client group so we do not need the\n // Replicache instance to update its internal _isClientGroupDisabled\n // property.\n await withWrite(perdag, perdagWrite =>\n persistDisableClientGroup(clientGroupID, perdagWrite),\n );\n}\n\n/**\n * @returns When mutations are recovered the resulting updated client group map.\n * Otherwise undefined, which can be because there were no mutations to\n * recover, or because an error occurred when trying to recover the mutations.\n */\nasync function recoverMutationsOfClientGroupDD31(\n clientGroup: ClientGroup,\n clientGroupID: ClientGroupID,\n perdag: Store,\n database: IndexedDBDatabase,\n options: MutationRecoveryOptions,\n formatVersion: FormatVersion,\n): Promise<ClientGroupMap | undefined> {\n assert(\n database.replicacheFormatVersion >= FormatVersion.DD31,\n 'Expected replicacheFormatVersion >= DD31 for client group mutation recovery',\n );\n\n const {\n delegate,\n lc,\n wrapInOnlineCheck,\n wrapInReauthRetries,\n isPushDisabled,\n isPullDisabled,\n clientGroupIDPromise,\n } = options;\n\n const selfClientGroupID = await clientGroupIDPromise;\n assertNotUndefined(selfClientGroupID);\n if (selfClientGroupID === clientGroupID) {\n return;\n }\n\n let clientID: ClientID | undefined;\n\n // If all local mutations have been applied then exit.\n let allAckd = true;\n for (const [cid, mutationID] of Object.entries(clientGroup.mutationIDs)) {\n // if not present then the server has not acknowledged this client's mutations.\n if (\n !clientGroup.lastServerAckdMutationIDs[cid] ||\n clientGroup.lastServerAckdMutationIDs[cid] < mutationID\n ) {\n clientID = cid;\n allAckd = false;\n break;\n }\n }\n if (allAckd) {\n return;\n }\n\n if (clientGroup.disabled) {\n lc.debug?.(\n `Not recovering mutations for client group ${clientGroupID} because group is disabled.`,\n );\n return;\n }\n\n const stepDescription = `Recovering mutations for client group ${clientGroupID}.`;\n lc.debug?.('Start:', stepDescription);\n const lazyDagForOtherClientGroup = new LazyStore(\n perdag,\n MUTATION_RECOVERY_LAZY_STORE_SOURCE_CHUNK_CACHE_SIZE_LIMIT,\n throwChunkHasher,\n assertHash,\n );\n try {\n await withWrite(lazyDagForOtherClientGroup, write =>\n write.setHead(DEFAULT_HEAD_NAME, clientGroup.headHash),\n );\n\n if (isPushDisabled()) {\n lc.debug?.(\n `Cannot recover mutations for client group ${clientGroupID} because push is disabled.`,\n );\n return;\n }\n\n const {pusher} = delegate;\n\n const pushDescription = 'recoveringMutationsPush';\n const pushSucceeded = await wrapInOnlineCheck(async () => {\n const {result: pusherResult} = await wrapInReauthRetries(\n async (requestID: string, requestLc: LogContext) => {\n assert(clientID, 'Expected clientID to be defined');\n assert(\n lazyDagForOtherClientGroup,\n 'Expected lazyDagForOtherClientGroup to be defined',\n );\n const pusherResult = await push(\n requestID,\n lazyDagForOtherClientGroup,\n requestLc,\n await delegate.profileID,\n clientGroupID,\n // TODO(DD31): clientID is not needed in DD31. It is currently kept for debugging purpose.\n clientID,\n pusher,\n database.schemaVersion,\n PUSH_VERSION_DD31,\n );\n return {\n result: pusherResult,\n httpRequestInfo: pusherResult?.httpRequestInfo,\n };\n },\n pushDescription,\n lc,\n );\n if (!pusherResult) {\n return false;\n }\n const pusherResponse = pusherResult.response;\n if (isResponseThatShouldDisableClientGroup(pusherResponse)) {\n await disableClientGroup(\n lc,\n selfClientGroupID,\n clientGroupID,\n pusherResponse,\n perdag,\n );\n return false;\n }\n return pusherResult.httpRequestInfo.httpStatusCode === 200;\n }, pushDescription);\n if (!pushSucceeded) {\n lc.debug?.(\n `Failed to recover mutations for client ${clientGroupID} due to a push error.`,\n );\n return;\n }\n\n if (isPullDisabled()) {\n lc.debug?.(\n `Cannot confirm mutations were recovered for client ${clientGroupID} ` +\n `because pull is disabled.`,\n );\n return;\n }\n const {puller} = delegate;\n\n const pullDescription = 'recoveringMutationsPull';\n let okPullResponse: PullResponseOKV1 | undefined;\n const pullSucceeded = await wrapInOnlineCheck(async () => {\n const {result: beginPullResponse} = await wrapInReauthRetries(\n async (requestID: string, requestLc: LogContext) => {\n assert(clientID, 'Expected clientID to be defined');\n const beginPullResponse = await beginPullV1(\n await delegate.profileID,\n clientID,\n clientGroupID,\n database.schemaVersion,\n puller,\n requestID,\n lazyDagForOtherClientGroup,\n formatVersion,\n requestLc,\n false,\n );\n return {\n result: beginPullResponse,\n httpRequestInfo: beginPullResponse.httpRequestInfo,\n };\n },\n pullDescription,\n lc,\n );\n const {pullResponse} = beginPullResponse;\n if (isResponseThatShouldDisableClientGroup(pullResponse)) {\n await disableClientGroup(\n lc,\n selfClientGroupID,\n clientGroupID,\n pullResponse,\n perdag,\n );\n return false;\n }\n if (\n !pullResponse ||\n beginPullResponse.httpRequestInfo.httpStatusCode !== 200\n ) {\n return false;\n }\n okPullResponse = pullResponse;\n return true;\n }, pullDescription);\n if (!pullSucceeded) {\n lc.debug?.(\n `Failed to recover mutations for client ${clientGroupID} due to a pull error.`,\n );\n return;\n }\n\n // TODO(arv): Refactor to make pullResponse a const.\n // pullResponse must be non undefined because pullSucceeded is true.\n assert(\n okPullResponse,\n 'Expected okPullResponse to be defined after successful pull',\n );\n lc.debug?.(\n `Client group ${selfClientGroupID} recovered mutations for client group ${clientGroupID}. Details`,\n {\n mutationIDs: clientGroup.mutationIDs,\n lastServerAckdMutationIDs: clientGroup.lastServerAckdMutationIDs,\n lastMutationIDChanges: okPullResponse.lastMutationIDChanges,\n },\n );\n\n return await withWrite(perdag, async dagWrite => {\n const clientGroups = await getClientGroups(dagWrite);\n const clientGroupToUpdate = clientGroups.get(clientGroupID);\n if (!clientGroupToUpdate) {\n return clientGroups;\n }\n\n assert(okPullResponse, 'Expected okPullResponse to be defined');\n const lastServerAckdMutationIDsUpdates: Record<ClientID, number> = {};\n let anyMutationIDsUpdated = false;\n for (const [clientID, lastMutationIDChange] of Object.entries(\n okPullResponse.lastMutationIDChanges,\n )) {\n if (\n (clientGroupToUpdate.lastServerAckdMutationIDs[clientID] ?? 0) <\n lastMutationIDChange\n ) {\n lastServerAckdMutationIDsUpdates[clientID] = lastMutationIDChange;\n anyMutationIDsUpdated = true;\n }\n }\n if (!anyMutationIDsUpdated) {\n return clientGroups;\n }\n\n const newClientGroups = new Map(clientGroups).set(clientGroupID, {\n ...clientGroupToUpdate,\n lastServerAckdMutationIDs: {\n ...clientGroupToUpdate.lastServerAckdMutationIDs,\n ...lastServerAckdMutationIDsUpdates,\n },\n });\n await setClientGroups(newClientGroups, dagWrite);\n return newClientGroups;\n });\n } catch (e) {\n logMutationRecoveryError(e, lc, stepDescription, delegate);\n } finally {\n await lazyDagForOtherClientGroup.close();\n lc.debug?.('End:', stepDescription);\n }\n return;\n}\n"],"mappings":""}