@rocicorp/zero 1.2.0-canary.3 → 1.2.0-canary.4

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 (50) hide show
  1. package/out/shared/src/bigint-json.d.ts.map +1 -1
  2. package/out/shared/src/bigint-json.js.map +1 -1
  3. package/out/shared/src/btree-set.js.map +1 -1
  4. package/out/z2s/src/sql.js.map +1 -1
  5. package/out/zero/package.js +1 -1
  6. package/out/zero/package.js.map +1 -1
  7. package/out/zero-cache/src/auth/load-permissions.d.ts +2 -2
  8. package/out/zero-cache/src/auth/load-permissions.d.ts.map +1 -1
  9. package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
  10. package/out/zero-cache/src/db/run-transaction.d.ts.map +1 -1
  11. package/out/zero-cache/src/db/run-transaction.js +2 -2
  12. package/out/zero-cache/src/db/run-transaction.js.map +1 -1
  13. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
  14. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  15. package/out/zero-cache/src/server/logging.d.ts.map +1 -1
  16. package/out/zero-cache/src/server/logging.js +9 -1
  17. package/out/zero-cache/src/server/logging.js.map +1 -1
  18. package/out/zero-cache/src/services/life-cycle.d.ts +1 -0
  19. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  20. package/out/zero-cache/src/services/life-cycle.js +2 -2
  21. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  22. package/out/zero-cache/src/services/mutagen/pusher.d.ts +2 -2
  23. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  24. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  25. package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts +1 -1
  26. package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts.map +1 -1
  27. package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
  28. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +1 -1
  29. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  30. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  31. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +1 -1
  32. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  33. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  34. package/out/zero-cache/src/services/view-syncer/view-syncer.js +1 -1
  35. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  36. package/out/zero-cache/src/workers/connection.js.map +1 -1
  37. package/out/zero-client/src/client/version.js +1 -1
  38. package/out/zero-protocol/src/application-error.d.ts +1 -1
  39. package/out/zero-protocol/src/application-error.d.ts.map +1 -1
  40. package/out/zero-protocol/src/application-error.js.map +1 -1
  41. package/out/zql/src/ivm/memory-source.d.ts +1 -1
  42. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  43. package/out/zql/src/ivm/memory-source.js +2 -2
  44. package/out/zql/src/ivm/memory-source.js.map +1 -1
  45. package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
  46. package/out/zql/src/planner/planner-debug.js.map +1 -1
  47. package/out/zql/src/query/expression.d.ts +1 -1
  48. package/out/zql/src/query/expression.d.ts.map +1 -1
  49. package/out/zql/src/query/expression.js.map +1 -1
  50. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"bigint-json.d.ts","sourceRoot":"","sources":["../../../../shared/src/bigint-json.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AAWjC,MAAM,MAAM,SAAS,GACjB,IAAI,GACJ,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,SAAS,EAAE,GACpB,UAAU,CAAC;AAEf,MAAM,MAAM,UAAU,GAAG;IAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAA;CAAC,CAAC;AAE1E,eAAO,MAAM,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAY5C,CAAC;AAEH,eAAO,MAAM,gBAAgB,6CAAwC,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,KAAK,CACnB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,GAC3C,SAAS,CAEX;AAOD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,OAAO,EACZ,QAAQ,CAAC,EACL,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GACnB,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAC1C,IAAI,EACR,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,UAGzB;AAED,eAAO,MAAM,UAAU;;;CAGb,CAAC"}
1
+ {"version":3,"file":"bigint-json.d.ts","sourceRoot":"","sources":["../../../../shared/src/bigint-json.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AAYjC,MAAM,MAAM,SAAS,GACjB,IAAI,GACJ,MAAM,GACN,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,SAAS,EAAE,GACpB,UAAU,CAAC;AAEf,MAAM,MAAM,UAAU,GAAG;IAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAA;CAAC,CAAC;AAE1E,eAAO,MAAM,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAY5C,CAAC;AAEH,eAAO,MAAM,gBAAgB,6CAAwC,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,KAAK,CACnB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,KAAK,OAAO,GAC3C,SAAS,CAEX;AAOD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,OAAO,EACZ,QAAQ,CAAC,EACL,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GACnB,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAC1C,IAAI,EACR,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,UAGzB;AAED,eAAO,MAAM,UAAU;;;CAGb,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"bigint-json.js","names":[],"sources":["../../../../shared/src/bigint-json.ts"],"sourcesContent":["/**\n * Background for using `json-custom-numbers`:\n *\n * https://neon.tech/blog/parsing-json-from-postgres-in-js\n */\nimport {\n parse as customParse,\n stringify as customStringify,\n} from 'json-custom-numbers';\nimport * as v from './valita.ts';\n\nfunction numberParser(_: unknown, v: string) {\n const n = +v;\n if (n >= Number.MIN_SAFE_INTEGER && n <= Number.MAX_SAFE_INTEGER) return n;\n if (v.indexOf('.') !== -1 || v.indexOf('e') !== -1 || v.indexOf('E') !== -1)\n return n;\n return BigInt(v);\n}\n\n// Variant of postgres.JSONValue adapted to include bigints\nexport type JSONValue =\n | null\n | string\n | number\n | bigint\n | boolean\n | readonly JSONValue[]\n | JSONObject;\n\nexport type JSONObject = {readonly [prop: string]: JSONValue | undefined};\n\nexport const jsonValueSchema: v.Type<JSONValue> = v.lazy(() => {\n const jsonObjectSchema = v.readonly(v.record(jsonValueSchema));\n\n return v.union(\n v.null(),\n v.string(),\n v.number(),\n v.bigint(),\n v.boolean(),\n v.readonly(v.array(jsonValueSchema)),\n jsonObjectSchema,\n );\n});\n\nexport const jsonObjectSchema = v.readonly(v.record(jsonValueSchema));\n\n/**\n * Parses JSON strings that may contain arbitrarily large integers. Integers\n * larger than {@link Number.MAX_SAFE_INTEGER} are deserialized as a `bigint`.\n */\nexport function parse(\n str: string,\n reviver?: (k: string, v: unknown) => unknown,\n): JSONValue {\n return customParse(str, reviver, numberParser);\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nfunction customSerializer(_: string, v: any, type: string) {\n if (type === 'bigint') return v.toString();\n}\n\n/**\n * Stringifies objects to JSON, supporting objects containing bigint values.\n * Note that the resulting JSON string may not be deserializable by\n * all environments, but it is supported by Postgres. The string should be\n * deserialized with the corresponding {@link parse} method that will represent\n * large numbers as bigints. From there it is up to the application to suitably\n * handle bigints passed to downstream logic.\n */\nexport function stringify(\n obj: unknown,\n replacer?:\n | (string | number)[]\n | ((key: string, value: unknown) => unknown)\n | null,\n indent?: string | number,\n) {\n return customStringify(obj, replacer, indent, customSerializer);\n}\n\nexport const BigIntJSON = {\n parse,\n stringify,\n} as const;\n"],"mappings":";;;;;;;;AAWA,SAAS,aAAa,GAAY,GAAW;CAC3C,MAAM,IAAI,CAAC;AACX,KAAI,KAAK,OAAO,oBAAoB,KAAK,OAAO,iBAAkB,QAAO;AACzE,KAAI,EAAE,QAAQ,IAAI,KAAK,MAAM,EAAE,QAAQ,IAAI,KAAK,MAAM,EAAE,QAAQ,IAAI,KAAK,GACvE,QAAO;AACT,QAAO,OAAO,EAAE;;AAelB,IAAa,kBAAqC,eAAE,WAAW;CAC7D,MAAM,mBAAmB,SAAW,eAAE,OAAO,gBAAgB,CAAC;AAE9D,QAAO,eAAE,MACP,eAAE,MAAM,EACR,eAAE,QAAQ,EACV,eAAE,QAAQ,EACV,eAAE,QAAQ,EACV,eAAE,SAAS,EACX,SAAW,eAAE,MAAM,gBAAgB,CAAC,EACpC,iBACD;EACD;AAEF,IAAa,mBAAmB,SAAW,eAAE,OAAO,gBAAgB,CAAC;;;;;AAMrE,SAAgB,QACd,KACA,SACW;AACX,QAAO,MAAY,KAAK,SAAS,aAAa;;AAIhD,SAAS,iBAAiB,GAAW,GAAQ,MAAc;AACzD,KAAI,SAAS,SAAU,QAAO,EAAE,UAAU;;;;;;;;;;AAW5C,SAAgB,YACd,KACA,UAIA,QACA;AACA,QAAO,UAAgB,KAAK,UAAU,QAAQ,iBAAiB;;AAGjE,IAAa,aAAa;CACxB,OAAA;CACA,WAAA;CACD"}
1
+ {"version":3,"file":"bigint-json.js","names":[],"sources":["../../../../shared/src/bigint-json.ts"],"sourcesContent":["/**\n * Background for using `json-custom-numbers`:\n *\n * https://neon.tech/blog/parsing-json-from-postgres-in-js\n */\nimport {\n parse as customParse,\n stringify as customStringify,\n} from 'json-custom-numbers';\nimport * as v from './valita.ts';\n\nfunction numberParser(_: unknown, v: string) {\n const n = +v;\n if (n >= Number.MIN_SAFE_INTEGER && n <= Number.MAX_SAFE_INTEGER) return n;\n if (v.indexOf('.') !== -1 || v.indexOf('e') !== -1 || v.indexOf('E') !== -1) {\n return n;\n }\n return BigInt(v);\n}\n\n// Variant of postgres.JSONValue adapted to include bigints\nexport type JSONValue =\n | null\n | string\n | number\n | bigint\n | boolean\n | readonly JSONValue[]\n | JSONObject;\n\nexport type JSONObject = {readonly [prop: string]: JSONValue | undefined};\n\nexport const jsonValueSchema: v.Type<JSONValue> = v.lazy(() => {\n const jsonObjectSchema = v.readonly(v.record(jsonValueSchema));\n\n return v.union(\n v.null(),\n v.string(),\n v.number(),\n v.bigint(),\n v.boolean(),\n v.readonly(v.array(jsonValueSchema)),\n jsonObjectSchema,\n );\n});\n\nexport const jsonObjectSchema = v.readonly(v.record(jsonValueSchema));\n\n/**\n * Parses JSON strings that may contain arbitrarily large integers. Integers\n * larger than {@link Number.MAX_SAFE_INTEGER} are deserialized as a `bigint`.\n */\nexport function parse(\n str: string,\n reviver?: (k: string, v: unknown) => unknown,\n): JSONValue {\n return customParse(str, reviver, numberParser);\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nfunction customSerializer(_: string, v: any, type: string) {\n if (type === 'bigint') return v.toString();\n}\n\n/**\n * Stringifies objects to JSON, supporting objects containing bigint values.\n * Note that the resulting JSON string may not be deserializable by\n * all environments, but it is supported by Postgres. The string should be\n * deserialized with the corresponding {@link parse} method that will represent\n * large numbers as bigints. From there it is up to the application to suitably\n * handle bigints passed to downstream logic.\n */\nexport function stringify(\n obj: unknown,\n replacer?:\n | (string | number)[]\n | ((key: string, value: unknown) => unknown)\n | null,\n indent?: string | number,\n) {\n return customStringify(obj, replacer, indent, customSerializer);\n}\n\nexport const BigIntJSON = {\n parse,\n stringify,\n} as const;\n"],"mappings":";;;;;;;;AAWA,SAAS,aAAa,GAAY,GAAW;CAC3C,MAAM,IAAI,CAAC;AACX,KAAI,KAAK,OAAO,oBAAoB,KAAK,OAAO,iBAAkB,QAAO;AACzE,KAAI,EAAE,QAAQ,IAAI,KAAK,MAAM,EAAE,QAAQ,IAAI,KAAK,MAAM,EAAE,QAAQ,IAAI,KAAK,GACvE,QAAO;AAET,QAAO,OAAO,EAAE;;AAelB,IAAa,kBAAqC,eAAE,WAAW;CAC7D,MAAM,mBAAmB,SAAW,eAAE,OAAO,gBAAgB,CAAC;AAE9D,QAAO,eAAE,MACP,eAAE,MAAM,EACR,eAAE,QAAQ,EACV,eAAE,QAAQ,EACV,eAAE,QAAQ,EACV,eAAE,SAAS,EACX,SAAW,eAAE,MAAM,gBAAgB,CAAC,EACpC,iBACD;EACD;AAEF,IAAa,mBAAmB,SAAW,eAAE,OAAO,gBAAgB,CAAC;;;;;AAMrE,SAAgB,QACd,KACA,SACW;AACX,QAAO,MAAY,KAAK,SAAS,aAAa;;AAIhD,SAAS,iBAAiB,GAAW,GAAQ,MAAc;AACzD,KAAI,SAAS,SAAU,QAAO,EAAE,UAAU;;;;;;;;;;AAW5C,SAAgB,YACd,KACA,UAIA,QACA;AACA,QAAO,UAAgB,KAAK,UAAU,QAAQ,iBAAiB;;AAGjE,IAAa,aAAa;CACxB,OAAA;CACA,WAAA;CACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"btree-set.js","names":["#root","#delete","#maxKey"],"sources":["../../../../shared/src/btree-set.ts"],"sourcesContent":["import {assert} from './asserts.ts';\n\nconst MAX_NODE_SIZE = 32;\n\ntype Comparator<K> = (a: K, b: K) => number;\nexport class BTreeSet<K> {\n #root: BNode<K> = emptyLeaf as BNode<K>;\n size: number = 0;\n\n readonly comparator: Comparator<K>;\n\n constructor(comparator: Comparator<K>, entries?: IterableIterator<K>) {\n this.comparator = comparator;\n if (entries) {\n for (const key of entries) {\n this.add(key);\n }\n }\n }\n\n /** Releases the tree so that its size is 0. */\n clear() {\n this.#root = emptyLeaf as BNode<K>;\n this.size = 0;\n }\n\n clone() {\n this.#root.isShared = true;\n const ret = new BTreeSet<K>(this.comparator);\n ret.#root = this.#root;\n ret.size = this.size;\n return ret;\n }\n\n get(key: K): K | undefined {\n return this.#root.get(key, this);\n }\n\n add(key: K): this {\n if (this.#root.isShared) this.#root = this.#root.clone();\n const result = this.#root.set(key, this);\n if (result === null) return this;\n // Root node has split, so create a new root node.\n this.#root = new BNodeInternal<K>([this.#root, result]);\n return this;\n }\n\n /**\n * Returns true if the key exists in the B+ tree, false if not.\n * Use get() for best performance; use has() if you need to\n * distinguish between \"undefined value\" and \"key not present\".\n * @param key Key to detect\n * @description Computational complexity: O(log size)\n */\n has(key: K): boolean {\n return this.#root.has(key, this);\n }\n\n /**\n * Removes a single key-value pair from the B+ tree.\n * @param key Key to find\n * @returns true if a pair was found and removed, false otherwise.\n * @description Computational complexity: O(log size)\n */\n delete(key: K): boolean {\n return this.#delete(key);\n }\n\n #delete(key: K): boolean {\n let root = this.#root;\n if (root.isShared) {\n this.#root = root = root.clone();\n }\n try {\n return root.delete(key, this);\n } finally {\n let isShared;\n while (root.keys.length <= 1 && root.isInternal()) {\n isShared ||= root.isShared;\n this.#root = root =\n root.keys.length === 0 ? emptyLeaf : root.children[0];\n }\n // If any ancestor of the new root was shared, the new root must also be shared\n if (isShared) {\n root.isShared = true;\n }\n }\n }\n\n keys(): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, undefined, true);\n }\n\n values(): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, undefined, true);\n }\n\n valuesFrom(lowestKey?: K, inclusive: boolean = true): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, lowestKey, inclusive);\n }\n\n valuesReversed(): IterableIterator<K> {\n return valuesFromReversed(\n this.#maxKey(),\n this.#root,\n this.comparator,\n undefined,\n true,\n );\n }\n\n valuesFromReversed(\n highestKey?: K,\n inclusive: boolean = true,\n ): IterableIterator<K> {\n return valuesFromReversed(\n this.#maxKey(),\n this.#root,\n this.comparator,\n highestKey,\n inclusive,\n );\n }\n\n /** Gets the highest key in the tree. Complexity: O(1) */\n #maxKey(): K | undefined {\n return this.#root.maxKey();\n }\n\n [Symbol.iterator](): IterableIterator<K> {\n return this.keys();\n }\n}\n\nfunction valuesFrom<K>(\n root: BNode<K>,\n comparator: Comparator<K>,\n lowestKey: K | undefined,\n inclusive: boolean,\n): IterableIterator<K> {\n const info = findPath(lowestKey, root, comparator);\n if (info === undefined) {\n return iterator<K>(() => ({done: true, value: undefined}));\n }\n\n let [nodeQueue, nodeIndex, leaf] = info;\n let i =\n lowestKey === undefined\n ? -1\n : indexOf(lowestKey, leaf.keys, 0, comparator) - 1;\n\n if (\n !inclusive &&\n i < leaf.keys.length &&\n // +1 because we did -1 above.\n comparator(leaf.keys[i + 1], lowestKey!) === 0\n ) {\n i++;\n }\n\n return iterator<K>(() => {\n for (;;) {\n if (++i < leaf.keys.length) {\n return {done: false, value: leaf.keys[i]};\n }\n\n let level = -1;\n for (;;) {\n if (++level >= nodeQueue.length) {\n return {done: true, value: undefined};\n }\n if (++nodeIndex[level] < nodeQueue[level].length) {\n break;\n }\n }\n for (; level > 0; level--) {\n nodeQueue[level - 1] = (\n nodeQueue[level][nodeIndex[level]] as BNodeInternal<K>\n ).children;\n nodeIndex[level - 1] = 0;\n }\n leaf = nodeQueue[0][nodeIndex[0]];\n i = -1;\n }\n });\n}\n\nfunction valuesFromReversed<K>(\n maxKey: K | undefined,\n root: BNode<K>,\n comparator: Comparator<K>,\n highestKey: K | undefined,\n inclusive: boolean,\n): IterableIterator<K> {\n if (highestKey === undefined) {\n highestKey = maxKey;\n if (highestKey === undefined)\n return iterator<K>(() => ({done: true, value: undefined})); // collection is empty\n }\n let [nodeQueue, nodeIndex, leaf] =\n findPath(highestKey, root, comparator) ||\n findPath(maxKey, root, comparator)!;\n assert(\n !nodeQueue[0] || leaf === nodeQueue[0][nodeIndex[0]],\n 'BTreeSet: leaf node mismatch in iteration',\n );\n let i = indexOf(highestKey, leaf.keys, 0, comparator);\n if (\n inclusive &&\n i < leaf.keys.length &&\n comparator(leaf.keys[i], highestKey) <= 0\n ) {\n i++;\n }\n\n return iterator<K>(() => {\n for (;;) {\n if (--i >= 0) {\n return {done: false, value: leaf.keys[i]};\n }\n\n let level;\n // Advance to the next leaf node\n for (level = -1; ; ) {\n if (++level >= nodeQueue.length) {\n return {done: true, value: undefined};\n }\n if (--nodeIndex[level] >= 0) {\n break;\n }\n }\n for (; level > 0; level--) {\n nodeQueue[level - 1] = (\n nodeQueue[level][nodeIndex[level]] as BNodeInternal<K>\n ).children;\n nodeIndex[level - 1] = nodeQueue[level - 1].length - 1;\n }\n leaf = nodeQueue[0][nodeIndex[0]];\n i = leaf.keys.length;\n }\n });\n}\n\nfunction findPath<K>(\n key: K | undefined,\n root: BNode<K>,\n comparator: Comparator<K>,\n): [nodeQueue: BNode<K>[][], nodeIndex: number[], leaf: BNode<K>] | undefined {\n let nextNode = root;\n const nodeQueue: BNode<K>[][] = [];\n const nodeIndex: number[] = [];\n\n if (nextNode.isInternal()) {\n for (let d = 0; nextNode.isInternal(); d++) {\n nodeQueue[d] = nextNode.children;\n nodeIndex[d] =\n key === undefined ? 0 : indexOf(key, nextNode.keys, 0, comparator);\n if (nodeIndex[d] >= nodeQueue[d].length) return; // first key > maxKey()\n nextNode = nodeQueue[d][nodeIndex[d]];\n }\n nodeQueue.reverse();\n nodeIndex.reverse();\n }\n return [nodeQueue, nodeIndex, nextNode];\n}\n\nfunction iterator<T>(next: () => IteratorResult<T>): IterableIterator<T> {\n return {\n next,\n [Symbol.iterator]() {\n return this;\n },\n };\n}\n\n/** Leaf node / base class. **************************************************/\nclass BNode<K> {\n // If this is an internal node, _keys[i] is the highest key in children[i].\n keys: K[];\n // True if this node might be within multiple `BTree`s (or have multiple parents).\n // If so, it must be cloned before being mutated to avoid changing an unrelated tree.\n // This is transitive: if it's true, children are also shared even if `isShared!=true`\n // in those children. (Certain operations will propagate isShared=true to children.)\n isShared: true | undefined;\n\n constructor(keys: K[]) {\n this.keys = keys;\n this.isShared = undefined;\n }\n\n isInternal(): this is BNodeInternal<K> {\n return false;\n }\n\n maxKey() {\n return this.keys[this.keys.length - 1];\n }\n\n minKey(): K | undefined {\n return this.keys[0];\n }\n\n clone(): BNode<K> {\n return new BNode<K>(this.keys.slice(0));\n }\n\n get(key: K, tree: BTreeSet<K>): K | undefined {\n const i = indexOf(key, this.keys, -1, tree.comparator);\n return i < 0 ? undefined : this.keys[i];\n }\n\n has(key: K, tree: BTreeSet<K>): boolean {\n const i = indexOf(key, this.keys, -1, tree.comparator);\n return i >= 0 && i < this.keys.length;\n }\n\n set(key: K, tree: BTreeSet<K>): null | BNode<K> {\n let i = indexOf(key, this.keys, -1, tree.comparator);\n if (i < 0) {\n // key does not exist yet\n i = ~i;\n tree.size++;\n\n if (this.keys.length < MAX_NODE_SIZE) {\n this.keys.splice(i, 0, key);\n return null;\n }\n // This leaf node is full and must split\n const newRightSibling = this.splitOffRightSide();\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n let target: BNode<K> = this;\n if (i > this.keys.length) {\n i -= this.keys.length;\n target = newRightSibling;\n }\n // target.#insertInLeaf(i, key);\n target.keys.splice(i, 0, key);\n\n return newRightSibling;\n }\n\n // usually this is a no-op, but some users may wish to edit the key\n this.keys[i] = key;\n return null;\n }\n\n takeFromRight(rhs: BNode<K>) {\n this.keys.push(rhs.keys.shift()!);\n }\n\n takeFromLeft(lhs: BNode<K>) {\n this.keys.unshift(lhs.keys.pop()!);\n }\n\n splitOffRightSide(): BNode<K> {\n const half = this.keys.length >> 1;\n const keys = this.keys.splice(half);\n return new BNode<K>(keys);\n }\n\n delete(key: K, tree: BTreeSet<K>): boolean {\n const cmp = tree.comparator;\n const iLow = indexOf(key, this.keys, -1, cmp);\n const iHigh = iLow + 1;\n\n if (iLow < 0) {\n return false;\n }\n\n const {keys} = this;\n for (let i = iLow; i < iHigh; i++) {\n const key = keys[i];\n\n if (key !== keys[i] || this.isShared === true) {\n throw new Error('BTree illegally changed or cloned in delete');\n }\n\n this.keys.splice(i, 1);\n tree.size--;\n return true;\n }\n\n return false;\n }\n\n mergeSibling(rhs: BNode<K>, _: number) {\n this.keys.push(...rhs.keys);\n }\n}\n\n/** Internal node (non-leaf node) ********************************************/\nclass BNodeInternal<K> extends BNode<K> {\n // Note: conventionally B+ trees have one fewer key than the number of\n // children, but I find it easier to keep the array lengths equal: each\n // keys[i] caches the value of children[i].maxKey().\n children: BNode<K>[];\n\n /**\n * This does not mark `children` as shared, so it is the responsibility of the caller\n * to ensure children are either marked shared, or aren't included in another tree.\n */\n constructor(children: BNode<K>[], keys?: K[]) {\n if (!keys) {\n keys = [];\n for (let i = 0; i < children.length; i++) {\n keys[i] = children[i].maxKey();\n }\n }\n super(keys);\n this.children = children;\n }\n\n isInternal(): this is BNodeInternal<K> {\n return true;\n }\n\n clone(): BNode<K> {\n const children = this.children.slice(0);\n for (let i = 0; i < children.length; i++) {\n children[i].isShared = true;\n }\n return new BNodeInternal<K>(children, this.keys.slice(0));\n }\n\n minKey() {\n return this.children[0].minKey();\n }\n\n get(key: K, tree: BTreeSet<K>): K | undefined {\n const i = indexOf(key, this.keys, 0, tree.comparator);\n const {children} = this;\n return i < children.length ? children[i].get(key, tree) : undefined;\n }\n\n has(key: K, tree: BTreeSet<K>): boolean {\n const i = indexOf(key, this.keys, 0, tree.comparator);\n const {children} = this;\n return i < children.length ? children[i].has(key, tree) : false;\n }\n\n set(key: K, tree: BTreeSet<K>): null | BNode<K> {\n const c = this.children;\n const cmp = tree.comparator;\n let i = Math.min(indexOf(key, this.keys, 0, cmp), c.length - 1);\n let child = c[i];\n\n if (child.isShared) {\n c[i] = child = child.clone();\n }\n if (child.keys.length >= MAX_NODE_SIZE) {\n // child is full; inserting anything else will cause a split.\n // Shifting an item to the left or right sibling may avoid a split.\n // We can do a shift if the adjacent node is not full and if the\n // current key can still be placed in the same node after the shift.\n let other: BNode<K>;\n if (\n i > 0 &&\n (other = c[i - 1]).keys.length < MAX_NODE_SIZE &&\n cmp(child.keys[0], key) < 0\n ) {\n if (other.isShared) {\n c[i - 1] = other = other.clone();\n }\n other.takeFromRight(child);\n this.keys[i - 1] = other.maxKey();\n } else if (\n (other = c[i + 1]) !== undefined &&\n other.keys.length < MAX_NODE_SIZE &&\n cmp(child.maxKey(), key) < 0\n ) {\n if (other.isShared) c[i + 1] = other = other.clone();\n other.takeFromLeft(child);\n this.keys[i] = c[i].maxKey();\n }\n }\n\n const result = child.set(key, tree);\n this.keys[i] = child.maxKey();\n if (result === null) return null;\n\n // The child has split and `result` is a new right child... does it fit?\n if (this.keys.length < MAX_NODE_SIZE) {\n // yes\n this.insert(i + 1, result);\n return null;\n }\n // no, we must split also\n const newRightSibling = this.splitOffRightSide();\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n let target: BNodeInternal<K> = this;\n if (cmp(result.maxKey(), this.maxKey()) > 0) {\n target = newRightSibling;\n i -= this.keys.length;\n }\n target.insert(i + 1, result);\n return newRightSibling;\n }\n\n /**\n * Inserts `child` at index `i`.\n * This does not mark `child` as shared, so it is the responsibility of the caller\n * to ensure that either child is marked shared, or it is not included in another tree.\n */\n insert(i: number, child: BNode<K>) {\n this.children.splice(i, 0, child);\n this.keys.splice(i, 0, child.maxKey());\n }\n\n /**\n * Split this node.\n * Modifies this to remove the second half of the items, returning a separate node containing them.\n */\n splitOffRightSide() {\n const half = this.children.length >> 1;\n return new BNodeInternal<K>(\n this.children.splice(half),\n this.keys.splice(half),\n );\n }\n\n takeFromRight(rhs: BNode<K>) {\n this.keys.push(rhs.keys.shift()!);\n this.children.push((rhs as BNodeInternal<K>).children.shift()!);\n }\n\n takeFromLeft(lhs: BNode<K>) {\n this.keys.unshift(lhs.keys.pop()!);\n this.children.unshift((lhs as BNodeInternal<K>).children.pop()!);\n }\n\n delete(key: K, tree: BTreeSet<K>): boolean {\n const cmp = tree.comparator;\n const {keys} = this;\n const {children} = this;\n let iLow = indexOf(key, this.keys, 0, cmp);\n let i = iLow;\n const iHigh = Math.min(iLow, keys.length - 1);\n if (i <= iHigh) {\n try {\n if (children[i].isShared) {\n children[i] = children[i].clone();\n }\n const result = children[i].delete(key, tree);\n // Note: if children[i] is empty then keys[i]=undefined.\n // This is an invalid state, but it is fixed below.\n keys[i] = children[i].maxKey();\n return result;\n } finally {\n // Deletions may have occurred, so look for opportunities to merge nodes.\n const half = MAX_NODE_SIZE >> 1;\n if (iLow > 0) iLow--;\n for (i = iHigh; i >= iLow; i--) {\n if (children[i].keys.length <= half) {\n if (children[i].keys.length !== 0) {\n this.tryMerge(i, MAX_NODE_SIZE);\n } else {\n // child is empty! delete it!\n keys.splice(i, 1);\n children.splice(i, 1);\n }\n }\n }\n }\n }\n return false;\n }\n\n /** Merges child i with child i+1 if their combined size is not too large */\n tryMerge(i: number, maxSize: number): boolean {\n const {children} = this;\n if (i >= 0 && i + 1 < children.length) {\n if (children[i].keys.length + children[i + 1].keys.length <= maxSize) {\n if (children[i].isShared)\n // cloned already UNLESS i is outside scan range\n children[i] = children[i].clone();\n children[i].mergeSibling(children[i + 1], maxSize);\n children.splice(i + 1, 1);\n this.keys.splice(i + 1, 1);\n this.keys[i] = children[i].maxKey();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Move children from `rhs` into this.\n * `rhs` must be part of this tree, and be removed from it after this call\n * (otherwise isShared for its children could be incorrect).\n */\n mergeSibling(rhs: BNode<K>, maxNodeSize: number) {\n // assert !this.isShared;\n const oldLength = this.keys.length;\n this.keys.push(...rhs.keys);\n const rhsChildren = (rhs as unknown as BNodeInternal<K>).children;\n this.children.push(...rhsChildren);\n\n if (rhs.isShared && !this.isShared) {\n // All children of a shared node are implicitly shared, and since their new\n // parent is not shared, they must now be explicitly marked as shared.\n for (let i = 0; i < rhsChildren.length; i++) {\n rhsChildren[i].isShared = true;\n }\n }\n\n // If our children are themselves almost empty due to a mass-delete,\n // they may need to be merged too (but only the oldLength-1 and its\n // right sibling should need this).\n this.tryMerge(oldLength - 1, maxNodeSize);\n }\n}\n\n// If key not found, returns i^failXor where i is the insertion index.\n// Callers that don't care whether there was a match will set failXor=0.\nfunction indexOf<K>(\n key: K,\n keys: K[],\n failXor: number,\n comparator: Comparator<K>,\n): number {\n let lo = 0;\n let hi = keys.length;\n let mid = hi >> 1;\n while (lo < hi) {\n const c = comparator(keys[mid], key);\n if (c < 0) {\n lo = mid + 1;\n } else if (c > 0) {\n // key < keys[mid]\n hi = mid;\n } else if (c === 0) {\n return mid;\n } else {\n // c is NaN or otherwise invalid\n if (key === key) {\n // at least the search key is not NaN\n return keys.length;\n }\n throw new Error('NaN was used as a key');\n }\n mid = (lo + hi) >> 1;\n }\n return mid ^ failXor;\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nconst emptyLeaf = new BNode<any>([]);\nemptyLeaf.isShared = true;\n"],"mappings":"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"}
1
+ {"version":3,"file":"btree-set.js","names":["#root","#delete","#maxKey"],"sources":["../../../../shared/src/btree-set.ts"],"sourcesContent":["import {assert} from './asserts.ts';\n\nconst MAX_NODE_SIZE = 32;\n\ntype Comparator<K> = (a: K, b: K) => number;\nexport class BTreeSet<K> {\n #root: BNode<K> = emptyLeaf as BNode<K>;\n size: number = 0;\n\n readonly comparator: Comparator<K>;\n\n constructor(comparator: Comparator<K>, entries?: IterableIterator<K>) {\n this.comparator = comparator;\n if (entries) {\n for (const key of entries) {\n this.add(key);\n }\n }\n }\n\n /** Releases the tree so that its size is 0. */\n clear() {\n this.#root = emptyLeaf as BNode<K>;\n this.size = 0;\n }\n\n clone() {\n this.#root.isShared = true;\n const ret = new BTreeSet<K>(this.comparator);\n ret.#root = this.#root;\n ret.size = this.size;\n return ret;\n }\n\n get(key: K): K | undefined {\n return this.#root.get(key, this);\n }\n\n add(key: K): this {\n if (this.#root.isShared) this.#root = this.#root.clone();\n const result = this.#root.set(key, this);\n if (result === null) return this;\n // Root node has split, so create a new root node.\n this.#root = new BNodeInternal<K>([this.#root, result]);\n return this;\n }\n\n /**\n * Returns true if the key exists in the B+ tree, false if not.\n * Use get() for best performance; use has() if you need to\n * distinguish between \"undefined value\" and \"key not present\".\n * @param key Key to detect\n * @description Computational complexity: O(log size)\n */\n has(key: K): boolean {\n return this.#root.has(key, this);\n }\n\n /**\n * Removes a single key-value pair from the B+ tree.\n * @param key Key to find\n * @returns true if a pair was found and removed, false otherwise.\n * @description Computational complexity: O(log size)\n */\n delete(key: K): boolean {\n return this.#delete(key);\n }\n\n #delete(key: K): boolean {\n let root = this.#root;\n if (root.isShared) {\n this.#root = root = root.clone();\n }\n try {\n return root.delete(key, this);\n } finally {\n let isShared;\n while (root.keys.length <= 1 && root.isInternal()) {\n isShared ||= root.isShared;\n this.#root = root =\n root.keys.length === 0 ? emptyLeaf : root.children[0];\n }\n // If any ancestor of the new root was shared, the new root must also be shared\n if (isShared) {\n root.isShared = true;\n }\n }\n }\n\n keys(): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, undefined, true);\n }\n\n values(): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, undefined, true);\n }\n\n valuesFrom(lowestKey?: K, inclusive: boolean = true): IterableIterator<K> {\n return valuesFrom(this.#root, this.comparator, lowestKey, inclusive);\n }\n\n valuesReversed(): IterableIterator<K> {\n return valuesFromReversed(\n this.#maxKey(),\n this.#root,\n this.comparator,\n undefined,\n true,\n );\n }\n\n valuesFromReversed(\n highestKey?: K,\n inclusive: boolean = true,\n ): IterableIterator<K> {\n return valuesFromReversed(\n this.#maxKey(),\n this.#root,\n this.comparator,\n highestKey,\n inclusive,\n );\n }\n\n /** Gets the highest key in the tree. Complexity: O(1) */\n #maxKey(): K | undefined {\n return this.#root.maxKey();\n }\n\n [Symbol.iterator](): IterableIterator<K> {\n return this.keys();\n }\n}\n\nfunction valuesFrom<K>(\n root: BNode<K>,\n comparator: Comparator<K>,\n lowestKey: K | undefined,\n inclusive: boolean,\n): IterableIterator<K> {\n const info = findPath(lowestKey, root, comparator);\n if (info === undefined) {\n return iterator<K>(() => ({done: true, value: undefined}));\n }\n\n let [nodeQueue, nodeIndex, leaf] = info;\n let i =\n lowestKey === undefined\n ? -1\n : indexOf(lowestKey, leaf.keys, 0, comparator) - 1;\n\n if (\n !inclusive &&\n i < leaf.keys.length &&\n // +1 because we did -1 above.\n comparator(leaf.keys[i + 1], lowestKey!) === 0\n ) {\n i++;\n }\n\n return iterator<K>(() => {\n for (;;) {\n if (++i < leaf.keys.length) {\n return {done: false, value: leaf.keys[i]};\n }\n\n let level = -1;\n for (;;) {\n if (++level >= nodeQueue.length) {\n return {done: true, value: undefined};\n }\n if (++nodeIndex[level] < nodeQueue[level].length) {\n break;\n }\n }\n for (; level > 0; level--) {\n nodeQueue[level - 1] = (\n nodeQueue[level][nodeIndex[level]] as BNodeInternal<K>\n ).children;\n nodeIndex[level - 1] = 0;\n }\n leaf = nodeQueue[0][nodeIndex[0]];\n i = -1;\n }\n });\n}\n\nfunction valuesFromReversed<K>(\n maxKey: K | undefined,\n root: BNode<K>,\n comparator: Comparator<K>,\n highestKey: K | undefined,\n inclusive: boolean,\n): IterableIterator<K> {\n if (highestKey === undefined) {\n highestKey = maxKey;\n if (highestKey === undefined) {\n return iterator<K>(() => ({done: true, value: undefined}));\n } // collection is empty\n }\n let [nodeQueue, nodeIndex, leaf] =\n findPath(highestKey, root, comparator) ||\n findPath(maxKey, root, comparator)!;\n assert(\n !nodeQueue[0] || leaf === nodeQueue[0][nodeIndex[0]],\n 'BTreeSet: leaf node mismatch in iteration',\n );\n let i = indexOf(highestKey, leaf.keys, 0, comparator);\n if (\n inclusive &&\n i < leaf.keys.length &&\n comparator(leaf.keys[i], highestKey) <= 0\n ) {\n i++;\n }\n\n return iterator<K>(() => {\n for (;;) {\n if (--i >= 0) {\n return {done: false, value: leaf.keys[i]};\n }\n\n let level;\n // Advance to the next leaf node\n for (level = -1; ; ) {\n if (++level >= nodeQueue.length) {\n return {done: true, value: undefined};\n }\n if (--nodeIndex[level] >= 0) {\n break;\n }\n }\n for (; level > 0; level--) {\n nodeQueue[level - 1] = (\n nodeQueue[level][nodeIndex[level]] as BNodeInternal<K>\n ).children;\n nodeIndex[level - 1] = nodeQueue[level - 1].length - 1;\n }\n leaf = nodeQueue[0][nodeIndex[0]];\n i = leaf.keys.length;\n }\n });\n}\n\nfunction findPath<K>(\n key: K | undefined,\n root: BNode<K>,\n comparator: Comparator<K>,\n): [nodeQueue: BNode<K>[][], nodeIndex: number[], leaf: BNode<K>] | undefined {\n let nextNode = root;\n const nodeQueue: BNode<K>[][] = [];\n const nodeIndex: number[] = [];\n\n if (nextNode.isInternal()) {\n for (let d = 0; nextNode.isInternal(); d++) {\n nodeQueue[d] = nextNode.children;\n nodeIndex[d] =\n key === undefined ? 0 : indexOf(key, nextNode.keys, 0, comparator);\n if (nodeIndex[d] >= nodeQueue[d].length) return; // first key > maxKey()\n nextNode = nodeQueue[d][nodeIndex[d]];\n }\n nodeQueue.reverse();\n nodeIndex.reverse();\n }\n return [nodeQueue, nodeIndex, nextNode];\n}\n\nfunction iterator<T>(next: () => IteratorResult<T>): IterableIterator<T> {\n return {\n next,\n [Symbol.iterator]() {\n return this;\n },\n };\n}\n\n/** Leaf node / base class. **************************************************/\nclass BNode<K> {\n // If this is an internal node, _keys[i] is the highest key in children[i].\n keys: K[];\n // True if this node might be within multiple `BTree`s (or have multiple parents).\n // If so, it must be cloned before being mutated to avoid changing an unrelated tree.\n // This is transitive: if it's true, children are also shared even if `isShared!=true`\n // in those children. (Certain operations will propagate isShared=true to children.)\n isShared: true | undefined;\n\n constructor(keys: K[]) {\n this.keys = keys;\n this.isShared = undefined;\n }\n\n isInternal(): this is BNodeInternal<K> {\n return false;\n }\n\n maxKey() {\n return this.keys[this.keys.length - 1];\n }\n\n minKey(): K | undefined {\n return this.keys[0];\n }\n\n clone(): BNode<K> {\n return new BNode<K>(this.keys.slice(0));\n }\n\n get(key: K, tree: BTreeSet<K>): K | undefined {\n const i = indexOf(key, this.keys, -1, tree.comparator);\n return i < 0 ? undefined : this.keys[i];\n }\n\n has(key: K, tree: BTreeSet<K>): boolean {\n const i = indexOf(key, this.keys, -1, tree.comparator);\n return i >= 0 && i < this.keys.length;\n }\n\n set(key: K, tree: BTreeSet<K>): null | BNode<K> {\n let i = indexOf(key, this.keys, -1, tree.comparator);\n if (i < 0) {\n // key does not exist yet\n i = ~i;\n tree.size++;\n\n if (this.keys.length < MAX_NODE_SIZE) {\n this.keys.splice(i, 0, key);\n return null;\n }\n // This leaf node is full and must split\n const newRightSibling = this.splitOffRightSide();\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n let target: BNode<K> = this;\n if (i > this.keys.length) {\n i -= this.keys.length;\n target = newRightSibling;\n }\n // target.#insertInLeaf(i, key);\n target.keys.splice(i, 0, key);\n\n return newRightSibling;\n }\n\n // usually this is a no-op, but some users may wish to edit the key\n this.keys[i] = key;\n return null;\n }\n\n takeFromRight(rhs: BNode<K>) {\n this.keys.push(rhs.keys.shift()!);\n }\n\n takeFromLeft(lhs: BNode<K>) {\n this.keys.unshift(lhs.keys.pop()!);\n }\n\n splitOffRightSide(): BNode<K> {\n const half = this.keys.length >> 1;\n const keys = this.keys.splice(half);\n return new BNode<K>(keys);\n }\n\n delete(key: K, tree: BTreeSet<K>): boolean {\n const cmp = tree.comparator;\n const iLow = indexOf(key, this.keys, -1, cmp);\n const iHigh = iLow + 1;\n\n if (iLow < 0) {\n return false;\n }\n\n const {keys} = this;\n for (let i = iLow; i < iHigh; i++) {\n const key = keys[i];\n\n if (key !== keys[i] || this.isShared === true) {\n throw new Error('BTree illegally changed or cloned in delete');\n }\n\n this.keys.splice(i, 1);\n tree.size--;\n return true;\n }\n\n return false;\n }\n\n mergeSibling(rhs: BNode<K>, _: number) {\n this.keys.push(...rhs.keys);\n }\n}\n\n/** Internal node (non-leaf node) ********************************************/\nclass BNodeInternal<K> extends BNode<K> {\n // Note: conventionally B+ trees have one fewer key than the number of\n // children, but I find it easier to keep the array lengths equal: each\n // keys[i] caches the value of children[i].maxKey().\n children: BNode<K>[];\n\n /**\n * This does not mark `children` as shared, so it is the responsibility of the caller\n * to ensure children are either marked shared, or aren't included in another tree.\n */\n constructor(children: BNode<K>[], keys?: K[]) {\n if (!keys) {\n keys = [];\n for (let i = 0; i < children.length; i++) {\n keys[i] = children[i].maxKey();\n }\n }\n super(keys);\n this.children = children;\n }\n\n isInternal(): this is BNodeInternal<K> {\n return true;\n }\n\n clone(): BNode<K> {\n const children = this.children.slice(0);\n for (let i = 0; i < children.length; i++) {\n children[i].isShared = true;\n }\n return new BNodeInternal<K>(children, this.keys.slice(0));\n }\n\n minKey() {\n return this.children[0].minKey();\n }\n\n get(key: K, tree: BTreeSet<K>): K | undefined {\n const i = indexOf(key, this.keys, 0, tree.comparator);\n const {children} = this;\n return i < children.length ? children[i].get(key, tree) : undefined;\n }\n\n has(key: K, tree: BTreeSet<K>): boolean {\n const i = indexOf(key, this.keys, 0, tree.comparator);\n const {children} = this;\n return i < children.length ? children[i].has(key, tree) : false;\n }\n\n set(key: K, tree: BTreeSet<K>): null | BNode<K> {\n const c = this.children;\n const cmp = tree.comparator;\n let i = Math.min(indexOf(key, this.keys, 0, cmp), c.length - 1);\n let child = c[i];\n\n if (child.isShared) {\n c[i] = child = child.clone();\n }\n if (child.keys.length >= MAX_NODE_SIZE) {\n // child is full; inserting anything else will cause a split.\n // Shifting an item to the left or right sibling may avoid a split.\n // We can do a shift if the adjacent node is not full and if the\n // current key can still be placed in the same node after the shift.\n let other: BNode<K>;\n if (\n i > 0 &&\n (other = c[i - 1]).keys.length < MAX_NODE_SIZE &&\n cmp(child.keys[0], key) < 0\n ) {\n if (other.isShared) {\n c[i - 1] = other = other.clone();\n }\n other.takeFromRight(child);\n this.keys[i - 1] = other.maxKey();\n } else if (\n (other = c[i + 1]) !== undefined &&\n other.keys.length < MAX_NODE_SIZE &&\n cmp(child.maxKey(), key) < 0\n ) {\n if (other.isShared) c[i + 1] = other = other.clone();\n other.takeFromLeft(child);\n this.keys[i] = c[i].maxKey();\n }\n }\n\n const result = child.set(key, tree);\n this.keys[i] = child.maxKey();\n if (result === null) return null;\n\n // The child has split and `result` is a new right child... does it fit?\n if (this.keys.length < MAX_NODE_SIZE) {\n // yes\n this.insert(i + 1, result);\n return null;\n }\n // no, we must split also\n const newRightSibling = this.splitOffRightSide();\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n let target: BNodeInternal<K> = this;\n if (cmp(result.maxKey(), this.maxKey()) > 0) {\n target = newRightSibling;\n i -= this.keys.length;\n }\n target.insert(i + 1, result);\n return newRightSibling;\n }\n\n /**\n * Inserts `child` at index `i`.\n * This does not mark `child` as shared, so it is the responsibility of the caller\n * to ensure that either child is marked shared, or it is not included in another tree.\n */\n insert(i: number, child: BNode<K>) {\n this.children.splice(i, 0, child);\n this.keys.splice(i, 0, child.maxKey());\n }\n\n /**\n * Split this node.\n * Modifies this to remove the second half of the items, returning a separate node containing them.\n */\n splitOffRightSide() {\n const half = this.children.length >> 1;\n return new BNodeInternal<K>(\n this.children.splice(half),\n this.keys.splice(half),\n );\n }\n\n takeFromRight(rhs: BNode<K>) {\n this.keys.push(rhs.keys.shift()!);\n this.children.push((rhs as BNodeInternal<K>).children.shift()!);\n }\n\n takeFromLeft(lhs: BNode<K>) {\n this.keys.unshift(lhs.keys.pop()!);\n this.children.unshift((lhs as BNodeInternal<K>).children.pop()!);\n }\n\n delete(key: K, tree: BTreeSet<K>): boolean {\n const cmp = tree.comparator;\n const {keys} = this;\n const {children} = this;\n let iLow = indexOf(key, this.keys, 0, cmp);\n let i = iLow;\n const iHigh = Math.min(iLow, keys.length - 1);\n if (i <= iHigh) {\n try {\n if (children[i].isShared) {\n children[i] = children[i].clone();\n }\n const result = children[i].delete(key, tree);\n // Note: if children[i] is empty then keys[i]=undefined.\n // This is an invalid state, but it is fixed below.\n keys[i] = children[i].maxKey();\n return result;\n } finally {\n // Deletions may have occurred, so look for opportunities to merge nodes.\n const half = MAX_NODE_SIZE >> 1;\n if (iLow > 0) iLow--;\n for (i = iHigh; i >= iLow; i--) {\n if (children[i].keys.length <= half) {\n if (children[i].keys.length !== 0) {\n this.tryMerge(i, MAX_NODE_SIZE);\n } else {\n // child is empty! delete it!\n keys.splice(i, 1);\n children.splice(i, 1);\n }\n }\n }\n }\n }\n return false;\n }\n\n /** Merges child i with child i+1 if their combined size is not too large */\n tryMerge(i: number, maxSize: number): boolean {\n const {children} = this;\n if (i >= 0 && i + 1 < children.length) {\n if (children[i].keys.length + children[i + 1].keys.length <= maxSize) {\n if (\n children[i].isShared\n ) // cloned already UNLESS i is outside scan range\n {\n children[i] = children[i].clone();\n }\n children[i].mergeSibling(children[i + 1], maxSize);\n children.splice(i + 1, 1);\n this.keys.splice(i + 1, 1);\n this.keys[i] = children[i].maxKey();\n return true;\n }\n }\n return false;\n }\n\n /**\n * Move children from `rhs` into this.\n * `rhs` must be part of this tree, and be removed from it after this call\n * (otherwise isShared for its children could be incorrect).\n */\n mergeSibling(rhs: BNode<K>, maxNodeSize: number) {\n // assert !this.isShared;\n const oldLength = this.keys.length;\n this.keys.push(...rhs.keys);\n const rhsChildren = (rhs as unknown as BNodeInternal<K>).children;\n this.children.push(...rhsChildren);\n\n if (rhs.isShared && !this.isShared) {\n // All children of a shared node are implicitly shared, and since their new\n // parent is not shared, they must now be explicitly marked as shared.\n for (let i = 0; i < rhsChildren.length; i++) {\n rhsChildren[i].isShared = true;\n }\n }\n\n // If our children are themselves almost empty due to a mass-delete,\n // they may need to be merged too (but only the oldLength-1 and its\n // right sibling should need this).\n this.tryMerge(oldLength - 1, maxNodeSize);\n }\n}\n\n// If key not found, returns i^failXor where i is the insertion index.\n// Callers that don't care whether there was a match will set failXor=0.\nfunction indexOf<K>(\n key: K,\n keys: K[],\n failXor: number,\n comparator: Comparator<K>,\n): number {\n let lo = 0;\n let hi = keys.length;\n let mid = hi >> 1;\n while (lo < hi) {\n const c = comparator(keys[mid], key);\n if (c < 0) {\n lo = mid + 1;\n } else if (c > 0) {\n // key < keys[mid]\n hi = mid;\n } else if (c === 0) {\n return mid;\n } else {\n // c is NaN or otherwise invalid\n if (key === key) {\n // at least the search key is not NaN\n return keys.length;\n }\n throw new Error('NaN was used as a key');\n }\n mid = (lo + hi) >> 1;\n }\n return mid ^ failXor;\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nconst emptyLeaf = new BNode<any>([]);\nemptyLeaf.isShared = true;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sql.js","names":["#seen","#size"],"sources":["../../../../z2s/src/sql.ts"],"sourcesContent":["import {\n escapePostgresIdentifier,\n escapeSQLiteIdentifier,\n} from '@databases/escape-identifier';\nimport type {FormatConfig, SQLItem, SQLQuery} from '@databases/sql';\nimport baseSql, {SQLItemType} from '@databases/sql';\nimport {assert, unreachable} from '../../shared/src/asserts.ts';\nimport {\n isPgNumberType,\n isPgStringType,\n} from '../../zero-cache/src/types/pg-data-type.ts';\nimport type {LiteralValue} from '../../zero-protocol/src/ast.ts';\nimport type {ServerColumnSchema} from '../../zero-types/src/server-schema.ts';\n\nexport function formatPg(sql: SQLQuery) {\n const format = new ReusingFormat(escapePostgresIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nexport function formatPgInternalConvert(sql: SQLQuery) {\n const format = new SQLConvertFormat(escapePostgresIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nexport function formatSqlite(sql: SQLQuery) {\n const format = new ReusingFormat(escapeSQLiteIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nconst sqlConvert = Symbol('fromJson');\n\nexport type LiteralType = 'boolean' | 'number' | 'string' | 'null';\nexport type PluralLiteralType = Exclude<LiteralType, 'null'>;\n\ntype ColumnSqlConvertArg = {\n [sqlConvert]: 'column';\n type: string;\n value: unknown;\n plural: boolean;\n isEnum: boolean;\n isComparison: boolean;\n};\n\ntype SqlConvertArg =\n | ColumnSqlConvertArg\n | {\n [sqlConvert]: 'literal';\n type: LiteralType;\n value: LiteralValue;\n plural: boolean;\n };\n\nfunction isSqlConvert(value: unknown): value is SqlConvertArg {\n return value !== null && typeof value === 'object' && sqlConvert in value;\n}\n\nexport function sqlConvertSingularLiteralArg(\n value: string | boolean | number | null,\n): SQLQuery {\n const arg: SqlConvertArg = {\n [sqlConvert]: 'literal',\n type: value === null ? 'null' : (typeof value as LiteralType),\n value,\n plural: false,\n };\n return sql.value(arg);\n}\n\nexport function sqlConvertPluralLiteralArg(\n type: PluralLiteralType,\n value: PluralLiteralType[],\n): SQLQuery {\n const arg: SqlConvertArg = {\n [sqlConvert]: 'literal',\n type,\n value,\n plural: true,\n };\n return sql.value(arg);\n}\n\nexport function sqlConvertColumnArg(\n serverColumnSchema: ServerColumnSchema,\n value: unknown,\n plural: boolean,\n isComparison: boolean,\n): SQLQuery {\n return sql.value({\n [sqlConvert]: 'column',\n type: serverColumnSchema.type,\n isEnum: serverColumnSchema.isEnum,\n value,\n plural: plural || serverColumnSchema.isArray,\n isComparison,\n });\n}\n\nclass ReusingFormat implements FormatConfig {\n readonly #seen: Map<unknown, number> = new Map();\n readonly escapeIdentifier: (str: string) => string;\n\n constructor(escapeIdentifier: (str: string) => string) {\n this.escapeIdentifier = escapeIdentifier;\n }\n\n formatValue = (value: unknown) => {\n if (this.#seen.has(value)) {\n return {\n placeholder: `$${this.#seen.get(value)}`,\n value: PREVIOUSLY_SEEN_VALUE,\n };\n }\n this.#seen.set(value, this.#seen.size + 1);\n return {placeholder: `$${this.#seen.size}`, value};\n };\n}\n\nfunction stringify(arg: SqlConvertArg): string | null {\n if (arg.value === null) {\n return null;\n }\n if (arg.plural) {\n return JSON.stringify(arg.value);\n }\n if (arg[sqlConvert] === 'literal' && arg.type === 'string') {\n return arg.value as unknown as string;\n }\n if (\n arg[sqlConvert] === 'column' &&\n (arg.isEnum || isPgStringType(arg.type))\n ) {\n return arg.value as string;\n }\n return JSON.stringify(arg.value);\n}\n\nclass SQLConvertFormat implements FormatConfig {\n readonly #seen: Map<unknown, Map<string, number>> = new Map();\n #size = 0;\n readonly escapeIdentifier: (str: string) => string;\n\n constructor(escapeIdentifier: (str: string) => string) {\n this.escapeIdentifier = escapeIdentifier;\n }\n\n formatValue = (value: unknown) => {\n assert(isSqlConvert(value), 'JsonPackedFormat can only take JsonPackArgs.');\n const byType = this.#seen.get(value.value);\n if (byType?.has(value.type)) {\n return {\n placeholder: createPlaceholder(byType.get(value.type)!, value),\n value: PREVIOUSLY_SEEN_VALUE,\n };\n }\n this.#size++;\n if (byType) {\n byType.set(value.type, this.#size);\n } else {\n this.#seen.set(value.value, new Map([[value.type, this.#size]]));\n }\n return {\n placeholder: createPlaceholder(this.#size, value),\n value: stringify(value),\n };\n };\n}\n\nfunction createPlaceholder(index: number, arg: SqlConvertArg) {\n if (arg.type === 'null') {\n assert(arg.value === null, \"Args of type 'null' must have value null\");\n assert(!arg.plural, \"Args of type 'null' must not be plural\");\n return `$${index}`;\n }\n\n if (arg[sqlConvert] === 'literal') {\n const {value} = arg;\n if (Array.isArray(value)) {\n const elType = pgTypeForLiteralType(arg.type);\n return formatPlural(index, `value::${elType}`);\n }\n return `$${index}::text::${pgTypeForLiteralType(arg.type)}`;\n }\n\n const common = formatCommonToSingularAndPlural(index, arg);\n return arg.plural ? formatPlural(index, common) : common;\n}\n\nfunction formatCommonToSingularAndPlural(\n index: number,\n arg: ColumnSqlConvertArg,\n) {\n // Ok, so what is with all the `::text` casts\n // before the final cast?\n // This is to force the statement to describe its arguments\n // as being text. Without the text cast the args are described as\n // being bool/json/numeric/whatever and the bindings try to coerce\n // the inputs to those types.\n const valuePlaceholder = arg.plural ? 'value' : `$${index}`;\n let atTimeZone = ` AT TIME ZONE 'UTC'`;\n switch (arg.type) {\n case 'timestamptz':\n // @ts-expect-error Fallthrough intended\n case 'timestamp with time zone':\n atTimeZone = '';\n // fallthrough\n\n case 'date':\n case 'timestamp':\n case 'timestamp without time zone':\n return `to_timestamp(${valuePlaceholder}::text::numeric / 1000.0)${atTimeZone}`;\n\n case 'timetz':\n // @ts-expect-error Fallthrough intended\n case 'time with time zone':\n atTimeZone = '';\n // fallthrough\n\n case 'time':\n case 'time without time zone':\n return `(${valuePlaceholder}::text::int * interval'1ms')::time${atTimeZone}`;\n\n // uuid: cast to native uuid type for proper comparison and index usage\n case 'uuid':\n return `${valuePlaceholder}::text::uuid`;\n }\n if (arg.isEnum) {\n return `${valuePlaceholder}::text::\"${arg.type}\"`;\n }\n if (isPgStringType(arg.type)) {\n // For comparison cast to the general `text` type, not the\n // specific column type (i.e. `arg.type`), because we don't want to\n // force the value being compared to the size/max-size of the column\n // type before comparison.\n return arg.isComparison\n ? `${valuePlaceholder}::text`\n : `${valuePlaceholder}::text::${arg.type}`;\n }\n if (isPgNumberType(arg.type)) {\n // For comparison cast to `double precision` which uses IEEE 754 (the same\n // representation as JavaScript numbers which will accurately\n // represent any number value from zql) not the specific column type\n // (i.e. `arg.type`), because we don't want to force the value being\n // compared to the range and precision of the column type before comparison.\n return arg.isComparison\n ? `${valuePlaceholder}::text::double precision`\n : `${valuePlaceholder}::text::${arg.type}`;\n }\n return `${valuePlaceholder}::text::${arg.type}`;\n}\n\nfunction formatPlural(index: number, select: string) {\n return `ARRAY(\n SELECT ${select} FROM jsonb_array_elements_text($${index}::text::jsonb)\n )`;\n}\n\nfunction pgTypeForLiteralType(type: Exclude<LiteralType, 'null'>) {\n switch (type) {\n case 'boolean':\n return 'boolean';\n case 'number':\n // `double precision` uses IEEE 754, the same representation as JavaScript\n // numbers, and so this will accurately represent any number value\n // from zql\n return 'double precision';\n case 'string':\n return 'text';\n default:\n unreachable(type);\n }\n}\n\nexport const sql = baseSql.default;\n\nconst PREVIOUSLY_SEEN_VALUE = Symbol('PREVIOUSLY_SEEN_VALUE');\n\nfunction formatFn(\n items: readonly SQLItem[],\n {escapeIdentifier, formatValue}: FormatConfig,\n): {\n text: string;\n values: unknown[];\n} {\n // Create an empty query object.\n let text = '';\n const values = [];\n\n const localIdentifiers = new Map<unknown, string>();\n\n for (const item of items) {\n switch (item.type) {\n // If this is just raw text, we add it directly to the query text.\n case SQLItemType.RAW: {\n text += item.text;\n break;\n }\n\n // If we got a value SQL item, add a placeholder and add the value to our\n // placeholder values array.\n case SQLItemType.VALUE: {\n const {placeholder, value} = formatValue(item.value, values.length);\n text += placeholder;\n if (value !== PREVIOUSLY_SEEN_VALUE) {\n values.push(value);\n }\n\n break;\n }\n\n // If we got an identifier type, escape the strings and get a local\n // identifier for non-string identifiers.\n case SQLItemType.IDENTIFIER: {\n // This is a specific addition for Zero as Zero\n // does not support dots in identifiers.\n // If a dot is found, we assume it is a namespace\n // and split the identifier into its parts.\n const names =\n item.names.length === 1 &&\n typeof item.names[0] === 'string' &&\n item.names[0].includes('.')\n ? item.names[0].split('.')\n : item.names;\n\n text += names\n .map((name): string => {\n if (typeof name === 'string') return escapeIdentifier(name);\n\n if (!localIdentifiers.has(name))\n localIdentifiers.set(name, `__local_${localIdentifiers.size}__`);\n\n return escapeIdentifier(localIdentifiers.get(name)!);\n })\n .join('.');\n break;\n }\n }\n }\n\n if (text.trim()) {\n const lines = text.split('\\n');\n const min = Math.min(\n ...lines.filter(l => l.trim() !== '').map(l => /^\\s*/.exec(l)![0].length),\n );\n if (min) {\n text = lines.map(line => line.substr(min)).join('\\n');\n }\n }\n return {\n text: text.trim(),\n values,\n };\n}\n"],"mappings":";;;;;AAcA,SAAgB,SAAS,KAAe;CACtC,MAAM,SAAS,IAAI,cAAc,yBAAyB;AAC1D,QAAO,IAAI,QAAQ,UAA8B,SAAS,OAAO,OAAO,CAAC;;AAG3E,SAAgB,wBAAwB,KAAe;CACrD,MAAM,SAAS,IAAI,iBAAiB,yBAAyB;AAC7D,QAAO,IAAI,QAAQ,UAA8B,SAAS,OAAO,OAAO,CAAC;;AAQ3E,IAAM,aAAa,OAAO,WAAW;AAuBrC,SAAS,aAAa,OAAwC;AAC5D,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,cAAc;;AAGtE,SAAgB,6BACd,OACU;CACV,MAAM,MAAqB;GACxB,aAAa;EACd,MAAM,UAAU,OAAO,SAAU,OAAO;EACxC;EACA,QAAQ;EACT;AACD,QAAO,IAAI,MAAM,IAAI;;AAGvB,SAAgB,2BACd,MACA,OACU;CACV,MAAM,MAAqB;GACxB,aAAa;EACd;EACA;EACA,QAAQ;EACT;AACD,QAAO,IAAI,MAAM,IAAI;;AAGvB,SAAgB,oBACd,oBACA,OACA,QACA,cACU;AACV,QAAO,IAAI,MAAM;GACd,aAAa;EACd,MAAM,mBAAmB;EACzB,QAAQ,mBAAmB;EAC3B;EACA,QAAQ,UAAU,mBAAmB;EACrC;EACD,CAAC;;AAGJ,IAAM,gBAAN,MAA4C;CAC1C,wBAAuC,IAAI,KAAK;CAChD;CAEA,YAAY,kBAA2C;AACrD,OAAK,mBAAmB;;CAG1B,eAAe,UAAmB;AAChC,MAAI,MAAA,KAAW,IAAI,MAAM,CACvB,QAAO;GACL,aAAa,IAAI,MAAA,KAAW,IAAI,MAAM;GACtC,OAAO;GACR;AAEH,QAAA,KAAW,IAAI,OAAO,MAAA,KAAW,OAAO,EAAE;AAC1C,SAAO;GAAC,aAAa,IAAI,MAAA,KAAW;GAAQ;GAAM;;;AAItD,SAAS,UAAU,KAAmC;AACpD,KAAI,IAAI,UAAU,KAChB,QAAO;AAET,KAAI,IAAI,OACN,QAAO,KAAK,UAAU,IAAI,MAAM;AAElC,KAAI,IAAI,gBAAgB,aAAa,IAAI,SAAS,SAChD,QAAO,IAAI;AAEb,KACE,IAAI,gBAAgB,aACnB,IAAI,UAAU,eAAe,IAAI,KAAK,EAEvC,QAAO,IAAI;AAEb,QAAO,KAAK,UAAU,IAAI,MAAM;;AAGlC,IAAM,mBAAN,MAA+C;CAC7C,wBAAoD,IAAI,KAAK;CAC7D,QAAQ;CACR;CAEA,YAAY,kBAA2C;AACrD,OAAK,mBAAmB;;CAG1B,eAAe,UAAmB;AAChC,SAAO,aAAa,MAAM,EAAE,+CAA+C;EAC3E,MAAM,SAAS,MAAA,KAAW,IAAI,MAAM,MAAM;AAC1C,MAAI,QAAQ,IAAI,MAAM,KAAK,CACzB,QAAO;GACL,aAAa,kBAAkB,OAAO,IAAI,MAAM,KAAK,EAAG,MAAM;GAC9D,OAAO;GACR;AAEH,QAAA;AACA,MAAI,OACF,QAAO,IAAI,MAAM,MAAM,MAAA,KAAW;MAElC,OAAA,KAAW,IAAI,MAAM,OAAO,IAAI,IAAI,CAAC,CAAC,MAAM,MAAM,MAAA,KAAW,CAAC,CAAC,CAAC;AAElE,SAAO;GACL,aAAa,kBAAkB,MAAA,MAAY,MAAM;GACjD,OAAO,UAAU,MAAM;GACxB;;;AAIL,SAAS,kBAAkB,OAAe,KAAoB;AAC5D,KAAI,IAAI,SAAS,QAAQ;AACvB,SAAO,IAAI,UAAU,MAAM,2CAA2C;AACtE,SAAO,CAAC,IAAI,QAAQ,yCAAyC;AAC7D,SAAO,IAAI;;AAGb,KAAI,IAAI,gBAAgB,WAAW;EACjC,MAAM,EAAC,UAAS;AAChB,MAAI,MAAM,QAAQ,MAAM,CAEtB,QAAO,aAAa,OAAO,UADZ,qBAAqB,IAAI,KAAK,GACC;AAEhD,SAAO,IAAI,MAAM,UAAU,qBAAqB,IAAI,KAAK;;CAG3D,MAAM,SAAS,gCAAgC,OAAO,IAAI;AAC1D,QAAO,IAAI,SAAS,aAAa,OAAO,OAAO,GAAG;;AAGpD,SAAS,gCACP,OACA,KACA;CAOA,MAAM,mBAAmB,IAAI,SAAS,UAAU,IAAI;CACpD,IAAI,aAAa;AACjB,SAAQ,IAAI,MAAZ;EACE,KAAK;EAEL,KAAK,2BACH,cAAa;EAGf,KAAK;EACL,KAAK;EACL,KAAK,8BACH,QAAO,gBAAgB,iBAAiB,2BAA2B;EAErE,KAAK;EAEL,KAAK,sBACH,cAAa;EAGf,KAAK;EACL,KAAK,yBACH,QAAO,IAAI,iBAAiB,oCAAoC;EAGlE,KAAK,OACH,QAAO,GAAG,iBAAiB;;AAE/B,KAAI,IAAI,OACN,QAAO,GAAG,iBAAiB,WAAW,IAAI,KAAK;AAEjD,KAAI,eAAe,IAAI,KAAK,CAK1B,QAAO,IAAI,eACP,GAAG,iBAAiB,UACpB,GAAG,iBAAiB,UAAU,IAAI;AAExC,KAAI,eAAe,IAAI,KAAK,CAM1B,QAAO,IAAI,eACP,GAAG,iBAAiB,4BACpB,GAAG,iBAAiB,UAAU,IAAI;AAExC,QAAO,GAAG,iBAAiB,UAAU,IAAI;;AAG3C,SAAS,aAAa,OAAe,QAAgB;AACnD,QAAO;mBACU,OAAO,mCAAmC,MAAM;;;AAInE,SAAS,qBAAqB,MAAoC;AAChE,SAAQ,MAAR;EACE,KAAK,UACH,QAAO;EACT,KAAK,SAIH,QAAO;EACT,KAAK,SACH,QAAO;EACT,QACE,aAAY,KAAK;;;AAIvB,IAAa,MAAM,QAAQ;AAE3B,IAAM,wBAAwB,OAAO,wBAAwB;AAE7D,SAAS,SACP,OACA,EAAC,kBAAkB,eAInB;CAEA,IAAI,OAAO;CACX,MAAM,SAAS,EAAE;CAEjB,MAAM,mCAAmB,IAAI,KAAsB;AAEnD,MAAK,MAAM,QAAQ,MACjB,SAAQ,KAAK,MAAb;EAEE,KAAK,YAAY;AACf,WAAQ,KAAK;AACb;EAKF,KAAK,YAAY,OAAO;GACtB,MAAM,EAAC,aAAa,UAAS,YAAY,KAAK,OAAO,OAAO,OAAO;AACnE,WAAQ;AACR,OAAI,UAAU,sBACZ,QAAO,KAAK,MAAM;AAGpB;;EAKF,KAAK,YAAY,YAAY;GAK3B,MAAM,QACJ,KAAK,MAAM,WAAW,KACtB,OAAO,KAAK,MAAM,OAAO,YACzB,KAAK,MAAM,GAAG,SAAS,IAAI,GACvB,KAAK,MAAM,GAAG,MAAM,IAAI,GACxB,KAAK;AAEX,WAAQ,MACL,KAAK,SAAiB;AACrB,QAAI,OAAO,SAAS,SAAU,QAAO,iBAAiB,KAAK;AAE3D,QAAI,CAAC,iBAAiB,IAAI,KAAK,CAC7B,kBAAiB,IAAI,MAAM,WAAW,iBAAiB,KAAK,IAAI;AAElE,WAAO,iBAAiB,iBAAiB,IAAI,KAAK,CAAE;KACpD,CACD,KAAK,IAAI;AACZ;;;AAKN,KAAI,KAAK,MAAM,EAAE;EACf,MAAM,QAAQ,KAAK,MAAM,KAAK;EAC9B,MAAM,MAAM,KAAK,IACf,GAAG,MAAM,QAAO,MAAK,EAAE,MAAM,KAAK,GAAG,CAAC,KAAI,MAAK,OAAO,KAAK,EAAE,CAAE,GAAG,OAAO,CAC1E;AACD,MAAI,IACF,QAAO,MAAM,KAAI,SAAQ,KAAK,OAAO,IAAI,CAAC,CAAC,KAAK,KAAK;;AAGzD,QAAO;EACL,MAAM,KAAK,MAAM;EACjB;EACD"}
1
+ {"version":3,"file":"sql.js","names":["#seen","#size"],"sources":["../../../../z2s/src/sql.ts"],"sourcesContent":["import {\n escapePostgresIdentifier,\n escapeSQLiteIdentifier,\n} from '@databases/escape-identifier';\nimport type {FormatConfig, SQLItem, SQLQuery} from '@databases/sql';\nimport baseSql, {SQLItemType} from '@databases/sql';\nimport {assert, unreachable} from '../../shared/src/asserts.ts';\nimport {\n isPgNumberType,\n isPgStringType,\n} from '../../zero-cache/src/types/pg-data-type.ts';\nimport type {LiteralValue} from '../../zero-protocol/src/ast.ts';\nimport type {ServerColumnSchema} from '../../zero-types/src/server-schema.ts';\n\nexport function formatPg(sql: SQLQuery) {\n const format = new ReusingFormat(escapePostgresIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nexport function formatPgInternalConvert(sql: SQLQuery) {\n const format = new SQLConvertFormat(escapePostgresIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nexport function formatSqlite(sql: SQLQuery) {\n const format = new ReusingFormat(escapeSQLiteIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nconst sqlConvert = Symbol('fromJson');\n\nexport type LiteralType = 'boolean' | 'number' | 'string' | 'null';\nexport type PluralLiteralType = Exclude<LiteralType, 'null'>;\n\ntype ColumnSqlConvertArg = {\n [sqlConvert]: 'column';\n type: string;\n value: unknown;\n plural: boolean;\n isEnum: boolean;\n isComparison: boolean;\n};\n\ntype SqlConvertArg =\n | ColumnSqlConvertArg\n | {\n [sqlConvert]: 'literal';\n type: LiteralType;\n value: LiteralValue;\n plural: boolean;\n };\n\nfunction isSqlConvert(value: unknown): value is SqlConvertArg {\n return value !== null && typeof value === 'object' && sqlConvert in value;\n}\n\nexport function sqlConvertSingularLiteralArg(\n value: string | boolean | number | null,\n): SQLQuery {\n const arg: SqlConvertArg = {\n [sqlConvert]: 'literal',\n type: value === null ? 'null' : (typeof value as LiteralType),\n value,\n plural: false,\n };\n return sql.value(arg);\n}\n\nexport function sqlConvertPluralLiteralArg(\n type: PluralLiteralType,\n value: PluralLiteralType[],\n): SQLQuery {\n const arg: SqlConvertArg = {\n [sqlConvert]: 'literal',\n type,\n value,\n plural: true,\n };\n return sql.value(arg);\n}\n\nexport function sqlConvertColumnArg(\n serverColumnSchema: ServerColumnSchema,\n value: unknown,\n plural: boolean,\n isComparison: boolean,\n): SQLQuery {\n return sql.value({\n [sqlConvert]: 'column',\n type: serverColumnSchema.type,\n isEnum: serverColumnSchema.isEnum,\n value,\n plural: plural || serverColumnSchema.isArray,\n isComparison,\n });\n}\n\nclass ReusingFormat implements FormatConfig {\n readonly #seen: Map<unknown, number> = new Map();\n readonly escapeIdentifier: (str: string) => string;\n\n constructor(escapeIdentifier: (str: string) => string) {\n this.escapeIdentifier = escapeIdentifier;\n }\n\n formatValue = (value: unknown) => {\n if (this.#seen.has(value)) {\n return {\n placeholder: `$${this.#seen.get(value)}`,\n value: PREVIOUSLY_SEEN_VALUE,\n };\n }\n this.#seen.set(value, this.#seen.size + 1);\n return {placeholder: `$${this.#seen.size}`, value};\n };\n}\n\nfunction stringify(arg: SqlConvertArg): string | null {\n if (arg.value === null) {\n return null;\n }\n if (arg.plural) {\n return JSON.stringify(arg.value);\n }\n if (arg[sqlConvert] === 'literal' && arg.type === 'string') {\n return arg.value as unknown as string;\n }\n if (\n arg[sqlConvert] === 'column' &&\n (arg.isEnum || isPgStringType(arg.type))\n ) {\n return arg.value as string;\n }\n return JSON.stringify(arg.value);\n}\n\nclass SQLConvertFormat implements FormatConfig {\n readonly #seen: Map<unknown, Map<string, number>> = new Map();\n #size = 0;\n readonly escapeIdentifier: (str: string) => string;\n\n constructor(escapeIdentifier: (str: string) => string) {\n this.escapeIdentifier = escapeIdentifier;\n }\n\n formatValue = (value: unknown) => {\n assert(isSqlConvert(value), 'JsonPackedFormat can only take JsonPackArgs.');\n const byType = this.#seen.get(value.value);\n if (byType?.has(value.type)) {\n return {\n placeholder: createPlaceholder(byType.get(value.type)!, value),\n value: PREVIOUSLY_SEEN_VALUE,\n };\n }\n this.#size++;\n if (byType) {\n byType.set(value.type, this.#size);\n } else {\n this.#seen.set(value.value, new Map([[value.type, this.#size]]));\n }\n return {\n placeholder: createPlaceholder(this.#size, value),\n value: stringify(value),\n };\n };\n}\n\nfunction createPlaceholder(index: number, arg: SqlConvertArg) {\n if (arg.type === 'null') {\n assert(arg.value === null, \"Args of type 'null' must have value null\");\n assert(!arg.plural, \"Args of type 'null' must not be plural\");\n return `$${index}`;\n }\n\n if (arg[sqlConvert] === 'literal') {\n const {value} = arg;\n if (Array.isArray(value)) {\n const elType = pgTypeForLiteralType(arg.type);\n return formatPlural(index, `value::${elType}`);\n }\n return `$${index}::text::${pgTypeForLiteralType(arg.type)}`;\n }\n\n const common = formatCommonToSingularAndPlural(index, arg);\n return arg.plural ? formatPlural(index, common) : common;\n}\n\nfunction formatCommonToSingularAndPlural(\n index: number,\n arg: ColumnSqlConvertArg,\n) {\n // Ok, so what is with all the `::text` casts\n // before the final cast?\n // This is to force the statement to describe its arguments\n // as being text. Without the text cast the args are described as\n // being bool/json/numeric/whatever and the bindings try to coerce\n // the inputs to those types.\n const valuePlaceholder = arg.plural ? 'value' : `$${index}`;\n let atTimeZone = ` AT TIME ZONE 'UTC'`;\n switch (arg.type) {\n case 'timestamptz':\n // @ts-expect-error Fallthrough intended\n case 'timestamp with time zone':\n atTimeZone = '';\n // fallthrough\n\n case 'date':\n case 'timestamp':\n case 'timestamp without time zone':\n return `to_timestamp(${valuePlaceholder}::text::numeric / 1000.0)${atTimeZone}`;\n\n case 'timetz':\n // @ts-expect-error Fallthrough intended\n case 'time with time zone':\n atTimeZone = '';\n // fallthrough\n\n case 'time':\n case 'time without time zone':\n return `(${valuePlaceholder}::text::int * interval'1ms')::time${atTimeZone}`;\n\n // uuid: cast to native uuid type for proper comparison and index usage\n case 'uuid':\n return `${valuePlaceholder}::text::uuid`;\n }\n if (arg.isEnum) {\n return `${valuePlaceholder}::text::\"${arg.type}\"`;\n }\n if (isPgStringType(arg.type)) {\n // For comparison cast to the general `text` type, not the\n // specific column type (i.e. `arg.type`), because we don't want to\n // force the value being compared to the size/max-size of the column\n // type before comparison.\n return arg.isComparison\n ? `${valuePlaceholder}::text`\n : `${valuePlaceholder}::text::${arg.type}`;\n }\n if (isPgNumberType(arg.type)) {\n // For comparison cast to `double precision` which uses IEEE 754 (the same\n // representation as JavaScript numbers which will accurately\n // represent any number value from zql) not the specific column type\n // (i.e. `arg.type`), because we don't want to force the value being\n // compared to the range and precision of the column type before comparison.\n return arg.isComparison\n ? `${valuePlaceholder}::text::double precision`\n : `${valuePlaceholder}::text::${arg.type}`;\n }\n return `${valuePlaceholder}::text::${arg.type}`;\n}\n\nfunction formatPlural(index: number, select: string) {\n return `ARRAY(\n SELECT ${select} FROM jsonb_array_elements_text($${index}::text::jsonb)\n )`;\n}\n\nfunction pgTypeForLiteralType(type: Exclude<LiteralType, 'null'>) {\n switch (type) {\n case 'boolean':\n return 'boolean';\n case 'number':\n // `double precision` uses IEEE 754, the same representation as JavaScript\n // numbers, and so this will accurately represent any number value\n // from zql\n return 'double precision';\n case 'string':\n return 'text';\n default:\n unreachable(type);\n }\n}\n\nexport const sql = baseSql.default;\n\nconst PREVIOUSLY_SEEN_VALUE = Symbol('PREVIOUSLY_SEEN_VALUE');\n\nfunction formatFn(\n items: readonly SQLItem[],\n {escapeIdentifier, formatValue}: FormatConfig,\n): {\n text: string;\n values: unknown[];\n} {\n // Create an empty query object.\n let text = '';\n const values = [];\n\n const localIdentifiers = new Map<unknown, string>();\n\n for (const item of items) {\n switch (item.type) {\n // If this is just raw text, we add it directly to the query text.\n case SQLItemType.RAW: {\n text += item.text;\n break;\n }\n\n // If we got a value SQL item, add a placeholder and add the value to our\n // placeholder values array.\n case SQLItemType.VALUE: {\n const {placeholder, value} = formatValue(item.value, values.length);\n text += placeholder;\n if (value !== PREVIOUSLY_SEEN_VALUE) {\n values.push(value);\n }\n\n break;\n }\n\n // If we got an identifier type, escape the strings and get a local\n // identifier for non-string identifiers.\n case SQLItemType.IDENTIFIER: {\n // This is a specific addition for Zero as Zero\n // does not support dots in identifiers.\n // If a dot is found, we assume it is a namespace\n // and split the identifier into its parts.\n const names =\n item.names.length === 1 &&\n typeof item.names[0] === 'string' &&\n item.names[0].includes('.')\n ? item.names[0].split('.')\n : item.names;\n\n text += names\n .map((name): string => {\n if (typeof name === 'string') return escapeIdentifier(name);\n\n if (!localIdentifiers.has(name)) {\n localIdentifiers.set(name, `__local_${localIdentifiers.size}__`);\n }\n\n return escapeIdentifier(localIdentifiers.get(name)!);\n })\n .join('.');\n break;\n }\n }\n }\n\n if (text.trim()) {\n const lines = text.split('\\n');\n const min = Math.min(\n ...lines.filter(l => l.trim() !== '').map(l => /^\\s*/.exec(l)![0].length),\n );\n if (min) {\n text = lines.map(line => line.substr(min)).join('\\n');\n }\n }\n return {\n text: text.trim(),\n values,\n };\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  var package_default = {
2
2
  name: "@rocicorp/zero",
3
- version: "1.2.0-canary.3",
3
+ version: "1.2.0-canary.4",
4
4
  description: "Zero is a web framework for serverless web development.",
5
5
  author: "Rocicorp, Inc.",
6
6
  repository: {
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.2.0-canary.3\",\n \"description\": \"Zero is a web framework for serverless web development.\",\n \"author\": \"Rocicorp, Inc.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/rocicorp/mono.git\",\n \"directory\": \"packages/zero\"\n },\n \"license\": \"Apache-2.0\",\n \"homepage\": \"https://zero.rocicorp.dev\",\n \"bugs\": {\n \"url\": \"https://bugs.rocicorp.dev\"\n },\n \"scripts\": {\n \"build\": \"node --experimental-strip-types --no-warnings tool/build.ts\",\n \"build:watch\": \"node --experimental-strip-types --no-warnings tool/build.ts --watch\",\n \"check-types\": \"tsc -p tsconfig.client.json && tsc -p tsconfig.server.json\",\n \"check-types:client:watch\": \"tsc -p tsconfig.client.json --watch\",\n \"check-types:server:watch\": \"tsc -p tsconfig.server.json --watch\",\n \"format\": \"prettier --write .\",\n \"check-format\": \"prettier --check .\",\n \"lint\": \"oxlint --type-aware src/\",\n \"docs\": \"node --experimental-strip-types --no-warnings tool/generate-docs.ts\",\n \"docs:server\": \"node --watch --experimental-strip-types --no-warnings tool/generate-docs.ts --server\"\n },\n \"dependencies\": {\n \"@badrap/valita\": \"0.3.11\",\n \"@databases/escape-identifier\": \"^1.0.3\",\n \"@databases/sql\": \"^3.3.0\",\n \"@dotenvx/dotenvx\": \"^1.39.0\",\n \"@drdgvhbh/postgres-error-codes\": \"^0.0.6\",\n \"@fastify/cors\": \"^10.0.0\",\n \"@fastify/websocket\": \"^11.0.0\",\n \"@google-cloud/precise-date\": \"^4.0.0\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/api-logs\": \"^0.203.0\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.62.0\",\n \"@opentelemetry/exporter-metrics-otlp-http\": \"^0.203.0\",\n \"@opentelemetry/resources\": \"^2.0.1\",\n \"@opentelemetry/sdk-metrics\": \"^2.0.1\",\n \"@opentelemetry/sdk-node\": \"^0.203.0\",\n \"@opentelemetry/sdk-trace-node\": \"^2.0.1\",\n \"@postgresql-typed/oids\": \"^0.2.0\",\n \"@rocicorp/lock\": \"^1.0.4\",\n \"@rocicorp/logger\": \"^5.4.0\",\n \"@rocicorp/resolver\": \"^1.0.2\",\n \"@rocicorp/zero-sqlite3\": \"^1.0.15\",\n \"@standard-schema/spec\": \"^1.0.0\",\n \"@types/basic-auth\": \"^1.1.8\",\n \"@types/ws\": \"^8.5.12\",\n \"basic-auth\": \"^2.0.1\",\n \"chalk\": \"^5.3.0\",\n \"chalk-template\": \"^1.1.0\",\n \"chokidar\": \"^4.0.1\",\n \"cloudevents\": \"^10.0.0\",\n \"command-line-args\": \"^6.0.1\",\n \"command-line-usage\": \"^7.0.3\",\n \"compare-utf8\": \"^0.1.1\",\n \"defu\": \"^6.1.4\",\n \"eventemitter3\": \"^5.0.1\",\n \"fastify\": \"^5.0.0\",\n \"is-in-subnet\": \"^4.0.1\",\n \"jose\": \"^5.9.3\",\n \"js-xxhash\": \"^4.0.0\",\n \"json-custom-numbers\": \"^3.1.1\",\n \"kasi\": \"^1.1.0\",\n \"nanoid\": \"^5.1.2\",\n \"parse-prometheus-text-format\": \"^1.1.1\",\n \"pg-format\": \"npm:pg-format-fix@^1.0.5\",\n \"postgres\": \"3.4.7\",\n \"prettier\": \"^3.8.1\",\n \"semver\": \"^7.5.4\",\n \"tsx\": \"^4.21.0\",\n \"url-pattern\": \"^1.0.3\",\n \"urlpattern-polyfill\": \"^10.1.0\",\n \"ws\": \"^8.18.1\"\n },\n \"devDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"@vitest/runner\": \"4.1.2\",\n \"analyze-query\": \"0.0.0\",\n \"ast-to-zql\": \"0.0.0\",\n \"expo-sqlite\": \">=15\",\n \"replicache\": \"15.2.1\",\n \"shared\": \"0.0.0\",\n \"syncpack\": \"^14.2.1\",\n \"typedoc\": \"^0.28.17\",\n \"typedoc-plugin-markdown\": \"^4.10.0\",\n \"typescript\": \"~5.9.3\",\n \"vite\": \"8.0.3\",\n \"vitest\": \"4.1.2\",\n \"zero-cache\": \"0.0.0\",\n \"zero-client\": \"0.0.0\",\n \"zero-pg\": \"0.0.0\",\n \"zero-protocol\": \"0.0.0\",\n \"zero-react\": \"0.0.0\",\n \"zero-server\": \"0.0.0\",\n \"zero-solid\": \"0.0.0\",\n \"zqlite\": \"0.0.0\"\n },\n \"peerDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"expo-sqlite\": \">=15\"\n },\n \"peerDependenciesMeta\": {\n \"expo-sqlite\": {\n \"optional\": true\n },\n \"@op-engineering/op-sqlite\": {\n \"optional\": true\n }\n },\n \"type\": \"module\",\n \"main\": \"out/zero/src/zero.js\",\n \"module\": \"out/zero/src/zero.js\",\n \"types\": \"out/zero/src/zero.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./out/zero/src/zero.d.ts\",\n \"default\": \"./out/zero/src/zero.js\"\n },\n \"./bindings\": {\n \"types\": \"./out/zero/src/bindings.d.ts\",\n \"default\": \"./out/zero/src/bindings.js\"\n },\n \"./change-protocol/v0\": {\n \"types\": \"./out/zero/src/change-protocol/v0.d.ts\",\n \"default\": \"./out/zero/src/change-protocol/v0.js\"\n },\n \"./expo-sqlite\": {\n \"types\": \"./out/zero/src/expo-sqlite.d.ts\",\n \"default\": \"./out/zero/src/expo-sqlite.js\"\n },\n \"./op-sqlite\": {\n \"types\": \"./out/zero/src/op-sqlite.d.ts\",\n \"default\": \"./out/zero/src/op-sqlite.js\"\n },\n \"./pg\": {\n \"types\": \"./out/zero/src/pg.d.ts\",\n \"default\": \"./out/zero/src/pg.js\"\n },\n \"./react\": {\n \"types\": \"./out/zero/src/react.d.ts\",\n \"default\": \"./out/zero/src/react.js\"\n },\n \"./react-native\": {\n \"types\": \"./out/zero/src/react-native.d.ts\",\n \"default\": \"./out/zero/src/react-native.js\"\n },\n \"./server\": {\n \"types\": \"./out/zero/src/server.d.ts\",\n \"default\": \"./out/zero/src/server.js\"\n },\n \"./server/adapters/drizzle\": {\n \"types\": \"./out/zero/src/adapters/drizzle.d.ts\",\n \"default\": \"./out/zero/src/adapters/drizzle.js\"\n },\n \"./server/adapters/prisma\": {\n \"types\": \"./out/zero/src/adapters/prisma.d.ts\",\n \"default\": \"./out/zero/src/adapters/prisma.js\"\n },\n \"./server/adapters/pg\": {\n \"types\": \"./out/zero/src/adapters/pg.d.ts\",\n \"default\": \"./out/zero/src/adapters/pg.js\"\n },\n \"./server/adapters/postgresjs\": {\n \"types\": \"./out/zero/src/adapters/postgresjs.d.ts\",\n \"default\": \"./out/zero/src/adapters/postgresjs.js\"\n },\n \"./solid\": {\n \"types\": \"./out/zero/src/solid.d.ts\",\n \"default\": \"./out/zero/src/solid.js\"\n },\n \"./sqlite\": {\n \"types\": \"./out/zero/src/sqlite.d.ts\",\n \"default\": \"./out/zero/src/sqlite.js\"\n },\n \"./zqlite\": {\n \"types\": \"./out/zero/src/zqlite.d.ts\",\n \"default\": \"./out/zero/src/zqlite.js\"\n }\n },\n \"bin\": {\n \"zero-build-schema\": \"./out/zero/src/build-schema.js\",\n \"zero-cache\": \"./out/zero/src/cli.js\",\n \"zero-cache-dev\": \"./out/zero/src/zero-cache-dev.js\",\n \"zero-deploy-permissions\": \"./out/zero/src/deploy-permissions.js\",\n \"zero-out\": \"./out/zero/src/zero-out.js\",\n \"ast-to-zql\": \"./out/zero/src/ast-to-zql.js\",\n \"analyze-query\": \"./out/zero/src/analyze-query.js\",\n \"transform-query\": \"./out/zero/src/transform-query.js\"\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"files\": [\n \"out\",\n \"!*.tsbuildinfo\"\n ]\n}"],"mappings":""}
1
+ {"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.2.0-canary.4\",\n \"description\": \"Zero is a web framework for serverless web development.\",\n \"author\": \"Rocicorp, Inc.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/rocicorp/mono.git\",\n \"directory\": \"packages/zero\"\n },\n \"license\": \"Apache-2.0\",\n \"homepage\": \"https://zero.rocicorp.dev\",\n \"bugs\": {\n \"url\": \"https://bugs.rocicorp.dev\"\n },\n \"scripts\": {\n \"build\": \"node --experimental-strip-types --no-warnings tool/build.ts\",\n \"build:watch\": \"node --experimental-strip-types --no-warnings tool/build.ts --watch\",\n \"check-types\": \"tsc -p tsconfig.client.json && tsc -p tsconfig.server.json\",\n \"check-types:client:watch\": \"tsc -p tsconfig.client.json --watch\",\n \"check-types:server:watch\": \"tsc -p tsconfig.server.json --watch\",\n \"format\": \"prettier --write .\",\n \"check-format\": \"prettier --check .\",\n \"lint\": \"oxlint --type-aware src/\",\n \"docs\": \"node --experimental-strip-types --no-warnings tool/generate-docs.ts\",\n \"docs:server\": \"node --watch --experimental-strip-types --no-warnings tool/generate-docs.ts --server\"\n },\n \"dependencies\": {\n \"@badrap/valita\": \"0.3.11\",\n \"@databases/escape-identifier\": \"^1.0.3\",\n \"@databases/sql\": \"^3.3.0\",\n \"@dotenvx/dotenvx\": \"^1.39.0\",\n \"@drdgvhbh/postgres-error-codes\": \"^0.0.6\",\n \"@fastify/cors\": \"^10.0.0\",\n \"@fastify/websocket\": \"^11.0.0\",\n \"@google-cloud/precise-date\": \"^4.0.0\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/api-logs\": \"^0.203.0\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.62.0\",\n \"@opentelemetry/exporter-metrics-otlp-http\": \"^0.203.0\",\n \"@opentelemetry/resources\": \"^2.0.1\",\n \"@opentelemetry/sdk-metrics\": \"^2.0.1\",\n \"@opentelemetry/sdk-node\": \"^0.203.0\",\n \"@opentelemetry/sdk-trace-node\": \"^2.0.1\",\n \"@postgresql-typed/oids\": \"^0.2.0\",\n \"@rocicorp/lock\": \"^1.0.4\",\n \"@rocicorp/logger\": \"^5.4.0\",\n \"@rocicorp/resolver\": \"^1.0.2\",\n \"@rocicorp/zero-sqlite3\": \"^1.0.15\",\n \"@standard-schema/spec\": \"^1.0.0\",\n \"@types/basic-auth\": \"^1.1.8\",\n \"@types/ws\": \"^8.5.12\",\n \"basic-auth\": \"^2.0.1\",\n \"chalk\": \"^5.3.0\",\n \"chalk-template\": \"^1.1.0\",\n \"chokidar\": \"^4.0.1\",\n \"cloudevents\": \"^10.0.0\",\n \"command-line-args\": \"^6.0.1\",\n \"command-line-usage\": \"^7.0.3\",\n \"compare-utf8\": \"^0.1.1\",\n \"defu\": \"^6.1.4\",\n \"eventemitter3\": \"^5.0.1\",\n \"fastify\": \"^5.0.0\",\n \"is-in-subnet\": \"^4.0.1\",\n \"jose\": \"^5.9.3\",\n \"js-xxhash\": \"^4.0.0\",\n \"json-custom-numbers\": \"^3.1.1\",\n \"kasi\": \"^1.1.0\",\n \"nanoid\": \"^5.1.2\",\n \"parse-prometheus-text-format\": \"^1.1.1\",\n \"pg-format\": \"npm:pg-format-fix@^1.0.5\",\n \"postgres\": \"3.4.7\",\n \"prettier\": \"^3.8.1\",\n \"semver\": \"^7.5.4\",\n \"tsx\": \"^4.21.0\",\n \"url-pattern\": \"^1.0.3\",\n \"urlpattern-polyfill\": \"^10.1.0\",\n \"ws\": \"^8.18.1\"\n },\n \"devDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"@vitest/runner\": \"4.1.2\",\n \"analyze-query\": \"0.0.0\",\n \"ast-to-zql\": \"0.0.0\",\n \"expo-sqlite\": \">=15\",\n \"replicache\": \"15.2.1\",\n \"shared\": \"0.0.0\",\n \"syncpack\": \"^14.2.1\",\n \"typedoc\": \"^0.28.17\",\n \"typedoc-plugin-markdown\": \"^4.10.0\",\n \"typescript\": \"~5.9.3\",\n \"vite\": \"8.0.3\",\n \"vitest\": \"4.1.2\",\n \"zero-cache\": \"0.0.0\",\n \"zero-client\": \"0.0.0\",\n \"zero-pg\": \"0.0.0\",\n \"zero-protocol\": \"0.0.0\",\n \"zero-react\": \"0.0.0\",\n \"zero-server\": \"0.0.0\",\n \"zero-solid\": \"0.0.0\",\n \"zqlite\": \"0.0.0\"\n },\n \"peerDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"expo-sqlite\": \">=15\"\n },\n \"peerDependenciesMeta\": {\n \"expo-sqlite\": {\n \"optional\": true\n },\n \"@op-engineering/op-sqlite\": {\n \"optional\": true\n }\n },\n \"type\": \"module\",\n \"main\": \"out/zero/src/zero.js\",\n \"module\": \"out/zero/src/zero.js\",\n \"types\": \"out/zero/src/zero.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./out/zero/src/zero.d.ts\",\n \"default\": \"./out/zero/src/zero.js\"\n },\n \"./bindings\": {\n \"types\": \"./out/zero/src/bindings.d.ts\",\n \"default\": \"./out/zero/src/bindings.js\"\n },\n \"./change-protocol/v0\": {\n \"types\": \"./out/zero/src/change-protocol/v0.d.ts\",\n \"default\": \"./out/zero/src/change-protocol/v0.js\"\n },\n \"./expo-sqlite\": {\n \"types\": \"./out/zero/src/expo-sqlite.d.ts\",\n \"default\": \"./out/zero/src/expo-sqlite.js\"\n },\n \"./op-sqlite\": {\n \"types\": \"./out/zero/src/op-sqlite.d.ts\",\n \"default\": \"./out/zero/src/op-sqlite.js\"\n },\n \"./pg\": {\n \"types\": \"./out/zero/src/pg.d.ts\",\n \"default\": \"./out/zero/src/pg.js\"\n },\n \"./react\": {\n \"types\": \"./out/zero/src/react.d.ts\",\n \"default\": \"./out/zero/src/react.js\"\n },\n \"./react-native\": {\n \"types\": \"./out/zero/src/react-native.d.ts\",\n \"default\": \"./out/zero/src/react-native.js\"\n },\n \"./server\": {\n \"types\": \"./out/zero/src/server.d.ts\",\n \"default\": \"./out/zero/src/server.js\"\n },\n \"./server/adapters/drizzle\": {\n \"types\": \"./out/zero/src/adapters/drizzle.d.ts\",\n \"default\": \"./out/zero/src/adapters/drizzle.js\"\n },\n \"./server/adapters/prisma\": {\n \"types\": \"./out/zero/src/adapters/prisma.d.ts\",\n \"default\": \"./out/zero/src/adapters/prisma.js\"\n },\n \"./server/adapters/pg\": {\n \"types\": \"./out/zero/src/adapters/pg.d.ts\",\n \"default\": \"./out/zero/src/adapters/pg.js\"\n },\n \"./server/adapters/postgresjs\": {\n \"types\": \"./out/zero/src/adapters/postgresjs.d.ts\",\n \"default\": \"./out/zero/src/adapters/postgresjs.js\"\n },\n \"./solid\": {\n \"types\": \"./out/zero/src/solid.d.ts\",\n \"default\": \"./out/zero/src/solid.js\"\n },\n \"./sqlite\": {\n \"types\": \"./out/zero/src/sqlite.d.ts\",\n \"default\": \"./out/zero/src/sqlite.js\"\n },\n \"./zqlite\": {\n \"types\": \"./out/zero/src/zqlite.d.ts\",\n \"default\": \"./out/zero/src/zqlite.js\"\n }\n },\n \"bin\": {\n \"zero-build-schema\": \"./out/zero/src/build-schema.js\",\n \"zero-cache\": \"./out/zero/src/cli.js\",\n \"zero-cache-dev\": \"./out/zero/src/zero-cache-dev.js\",\n \"zero-deploy-permissions\": \"./out/zero/src/deploy-permissions.js\",\n \"zero-out\": \"./out/zero/src/zero-out.js\",\n \"ast-to-zql\": \"./out/zero/src/ast-to-zql.js\",\n \"analyze-query\": \"./out/zero/src/analyze-query.js\",\n \"transform-query\": \"./out/zero/src/transform-query.js\"\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"files\": [\n \"out\",\n \"!*.tsbuildinfo\"\n ]\n}"],"mappings":""}
@@ -8,8 +8,8 @@ export type LoadedPermissions = {
8
8
  permissions: PermissionsConfig | null;
9
9
  hash: string | null;
10
10
  };
11
- export declare function loadPermissions(lc: LogContext, replica: StatementRunner, appID: string, config?: ZeroConfig | undefined): LoadedPermissions;
12
- export declare function reloadPermissionsIfChanged(lc: LogContext, replica: StatementRunner, appID: string, current: LoadedPermissions | null, config?: ZeroConfig | undefined): {
11
+ export declare function loadPermissions(lc: LogContext, replica: StatementRunner, appID: string, config?: ZeroConfig): LoadedPermissions;
12
+ export declare function reloadPermissionsIfChanged(lc: LogContext, replica: StatementRunner, appID: string, current: LoadedPermissions | null, config?: ZeroConfig): {
13
13
  permissions: LoadedPermissions;
14
14
  changed: boolean;
15
15
  };
@@ -1 +1 @@
1
- {"version":3,"file":"load-permissions.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/auth/load-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,kDAAkD,CAAC;AAE1D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAC9D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AACxD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAEzD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAGzD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,eAAe,CAC7B,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,GAC9B,iBAAiB,CAqCnB;AAED,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,GAAG,IAAI,EACjC,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,GAC9B;IAAC,WAAW,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAWpD;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,GAAG,MAAM,CAiBnE"}
1
+ {"version":3,"file":"load-permissions.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/auth/load-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,kDAAkD,CAAC;AAE1D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAC9D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AACxD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAEzD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAGzD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,eAAe,CAC7B,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,UAAU,GAClB,iBAAiB,CAqCnB;AAED,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,GAAG,IAAI,EACjC,MAAM,CAAC,EAAE,UAAU,GAClB;IAAC,WAAW,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAWpD;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,GAAG,MAAM,CAiBnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"load-permissions.js","names":[],"sources":["../../../../../zero-cache/src/auth/load-permissions.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport * as v from '../../../shared/src/valita.ts';\nimport {\n permissionsConfigSchema,\n type PermissionsConfig,\n} from '../../../zero-schema/src/compiled-permissions.ts';\nimport type {TableSchema} from '../../../zero-schema/src/table-schema.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport type {Database} from '../../../zqlite/src/db.ts';\nimport type {ZeroConfig} from '../config/zero-config.ts';\nimport {computeZqlSpecs} from '../db/lite-tables.ts';\nimport type {StatementRunner} from '../db/statements.ts';\nimport {elide} from '../types/strings.ts';\n\nexport type LoadedPermissions = {\n permissions: PermissionsConfig | null;\n hash: string | null;\n};\n\nexport function loadPermissions(\n lc: LogContext,\n replica: StatementRunner,\n appID: string,\n config?: ZeroConfig | undefined,\n): LoadedPermissions {\n const {permissions, hash} = replica.get(\n `SELECT permissions, hash FROM \"${appID}.permissions\"`,\n );\n if (permissions === null) {\n const hasCustomEndpoints =\n config !== undefined &&\n (config.push?.url !== undefined || config.mutate?.url !== undefined) &&\n (config.query?.url !== undefined || config.getQueries?.url !== undefined);\n\n if (!hasCustomEndpoints) {\n const appIDFlag = appID === 'zero' ? '' : ` --app-id=${appID}`;\n lc.warn?.(\n `\\n\\n\\n` +\n `No upstream permissions deployed.\\n` +\n `Run 'npx zero-deploy-permissions${appIDFlag}' to enforce permissions.` +\n `\\n\\n\\n`,\n );\n }\n return {permissions, hash: null};\n }\n let obj;\n let parsed;\n try {\n obj = JSON.parse(permissions);\n parsed = v.parse(obj, permissionsConfigSchema);\n } catch (e) {\n // TODO: Plumb the --server-version and include in error message.\n throw new Error(\n `Could not parse upstream permissions: ` +\n `'${elide(String(permissions), 100)}'.\\n` +\n `This may happen if Permissions with a new internal format are ` +\n `deployed before the supporting server has been fully rolled out.`,\n {cause: e},\n );\n }\n return {permissions: parsed, hash};\n}\n\nexport function reloadPermissionsIfChanged(\n lc: LogContext,\n replica: StatementRunner,\n appID: string,\n current: LoadedPermissions | null,\n config?: ZeroConfig | undefined,\n): {permissions: LoadedPermissions; changed: boolean} {\n if (current === null) {\n return {\n permissions: loadPermissions(lc, replica, appID, config),\n changed: true,\n };\n }\n const {hash} = replica.get(`SELECT hash FROM \"${appID}.permissions\"`);\n return hash === current.hash\n ? {permissions: current, changed: false}\n : {permissions: loadPermissions(lc, replica, appID, config), changed: true};\n}\n\nexport function getSchema(lc: LogContext, replica: Database): Schema {\n const specs = computeZqlSpecs(lc, replica, {\n includeBackfillingColumns: false,\n });\n const tables = Object.fromEntries(\n [...specs.values()].map(table => {\n const {\n tableSpec: {name, primaryKey},\n zqlSpec: columns,\n } = table;\n return [name, {name, columns, primaryKey} satisfies TableSchema];\n }),\n );\n return {\n tables,\n relationships: {}, // relationships are already denormalized in ASTs\n };\n}\n"],"mappings":";;;;;AAmBA,SAAgB,gBACd,IACA,SACA,OACA,QACmB;CACnB,MAAM,EAAC,aAAa,SAAQ,QAAQ,IAClC,kCAAkC,MAAM,eACzC;AACD,KAAI,gBAAgB,MAAM;AAMxB,MAAI,EAJF,WAAW,KAAA,MACV,OAAO,MAAM,QAAQ,KAAA,KAAa,OAAO,QAAQ,QAAQ,KAAA,OACzD,OAAO,OAAO,QAAQ,KAAA,KAAa,OAAO,YAAY,QAAQ,KAAA,KAExC;GACvB,MAAM,YAAY,UAAU,SAAS,KAAK,aAAa;AACvD,MAAG,OACD;;;;kCAEqC,UAAU,iCAEhD;;AAEH,SAAO;GAAC;GAAa,MAAM;GAAK;;CAElC,IAAI;CACJ,IAAI;AACJ,KAAI;AACF,QAAM,KAAK,MAAM,YAAY;AAC7B,WAAS,MAAQ,KAAK,wBAAwB;UACvC,GAAG;AAEV,QAAM,IAAI,MACR,0CACM,MAAM,OAAO,YAAY,EAAE,IAAI,CAAC,qIAGtC,EAAC,OAAO,GAAE,CACX;;AAEH,QAAO;EAAC,aAAa;EAAQ;EAAK;;AAGpC,SAAgB,2BACd,IACA,SACA,OACA,SACA,QACoD;AACpD,KAAI,YAAY,KACd,QAAO;EACL,aAAa,gBAAgB,IAAI,SAAS,OAAO,OAAO;EACxD,SAAS;EACV;CAEH,MAAM,EAAC,SAAQ,QAAQ,IAAI,qBAAqB,MAAM,eAAe;AACrE,QAAO,SAAS,QAAQ,OACpB;EAAC,aAAa;EAAS,SAAS;EAAM,GACtC;EAAC,aAAa,gBAAgB,IAAI,SAAS,OAAO,OAAO;EAAE,SAAS;EAAK;;AAG/E,SAAgB,UAAU,IAAgB,SAA2B;CACnE,MAAM,QAAQ,gBAAgB,IAAI,SAAS,EACzC,2BAA2B,OAC5B,CAAC;AAUF,QAAO;EACL,QAVa,OAAO,YACpB,CAAC,GAAG,MAAM,QAAQ,CAAC,CAAC,KAAI,UAAS;GAC/B,MAAM,EACJ,WAAW,EAAC,MAAM,cAClB,SAAS,YACP;AACJ,UAAO,CAAC,MAAM;IAAC;IAAM;IAAS;IAAW,CAAuB;IAChE,CACH;EAGC,eAAe,EAAE;EAClB"}
1
+ {"version":3,"file":"load-permissions.js","names":[],"sources":["../../../../../zero-cache/src/auth/load-permissions.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport * as v from '../../../shared/src/valita.ts';\nimport {\n permissionsConfigSchema,\n type PermissionsConfig,\n} from '../../../zero-schema/src/compiled-permissions.ts';\nimport type {TableSchema} from '../../../zero-schema/src/table-schema.ts';\nimport type {Schema} from '../../../zero-types/src/schema.ts';\nimport type {Database} from '../../../zqlite/src/db.ts';\nimport type {ZeroConfig} from '../config/zero-config.ts';\nimport {computeZqlSpecs} from '../db/lite-tables.ts';\nimport type {StatementRunner} from '../db/statements.ts';\nimport {elide} from '../types/strings.ts';\n\nexport type LoadedPermissions = {\n permissions: PermissionsConfig | null;\n hash: string | null;\n};\n\nexport function loadPermissions(\n lc: LogContext,\n replica: StatementRunner,\n appID: string,\n config?: ZeroConfig,\n): LoadedPermissions {\n const {permissions, hash} = replica.get(\n `SELECT permissions, hash FROM \"${appID}.permissions\"`,\n );\n if (permissions === null) {\n const hasCustomEndpoints =\n config !== undefined &&\n (config.push?.url !== undefined || config.mutate?.url !== undefined) &&\n (config.query?.url !== undefined || config.getQueries?.url !== undefined);\n\n if (!hasCustomEndpoints) {\n const appIDFlag = appID === 'zero' ? '' : ` --app-id=${appID}`;\n lc.warn?.(\n `\\n\\n\\n` +\n `No upstream permissions deployed.\\n` +\n `Run 'npx zero-deploy-permissions${appIDFlag}' to enforce permissions.` +\n `\\n\\n\\n`,\n );\n }\n return {permissions, hash: null};\n }\n let obj;\n let parsed;\n try {\n obj = JSON.parse(permissions);\n parsed = v.parse(obj, permissionsConfigSchema);\n } catch (e) {\n // TODO: Plumb the --server-version and include in error message.\n throw new Error(\n `Could not parse upstream permissions: ` +\n `'${elide(String(permissions), 100)}'.\\n` +\n `This may happen if Permissions with a new internal format are ` +\n `deployed before the supporting server has been fully rolled out.`,\n {cause: e},\n );\n }\n return {permissions: parsed, hash};\n}\n\nexport function reloadPermissionsIfChanged(\n lc: LogContext,\n replica: StatementRunner,\n appID: string,\n current: LoadedPermissions | null,\n config?: ZeroConfig,\n): {permissions: LoadedPermissions; changed: boolean} {\n if (current === null) {\n return {\n permissions: loadPermissions(lc, replica, appID, config),\n changed: true,\n };\n }\n const {hash} = replica.get(`SELECT hash FROM \"${appID}.permissions\"`);\n return hash === current.hash\n ? {permissions: current, changed: false}\n : {permissions: loadPermissions(lc, replica, appID, config), changed: true};\n}\n\nexport function getSchema(lc: LogContext, replica: Database): Schema {\n const specs = computeZqlSpecs(lc, replica, {\n includeBackfillingColumns: false,\n });\n const tables = Object.fromEntries(\n [...specs.values()].map(table => {\n const {\n tableSpec: {name, primaryKey},\n zqlSpec: columns,\n } = table;\n return [name, {name, columns, primaryKey} satisfies TableSchema];\n }),\n );\n return {\n tables,\n relationships: {}, // relationships are already denormalized in ASTs\n };\n}\n"],"mappings":";;;;;AAmBA,SAAgB,gBACd,IACA,SACA,OACA,QACmB;CACnB,MAAM,EAAC,aAAa,SAAQ,QAAQ,IAClC,kCAAkC,MAAM,eACzC;AACD,KAAI,gBAAgB,MAAM;AAMxB,MAAI,EAJF,WAAW,KAAA,MACV,OAAO,MAAM,QAAQ,KAAA,KAAa,OAAO,QAAQ,QAAQ,KAAA,OACzD,OAAO,OAAO,QAAQ,KAAA,KAAa,OAAO,YAAY,QAAQ,KAAA,KAExC;GACvB,MAAM,YAAY,UAAU,SAAS,KAAK,aAAa;AACvD,MAAG,OACD;;;;kCAEqC,UAAU,iCAEhD;;AAEH,SAAO;GAAC;GAAa,MAAM;GAAK;;CAElC,IAAI;CACJ,IAAI;AACJ,KAAI;AACF,QAAM,KAAK,MAAM,YAAY;AAC7B,WAAS,MAAQ,KAAK,wBAAwB;UACvC,GAAG;AAEV,QAAM,IAAI,MACR,0CACM,MAAM,OAAO,YAAY,EAAE,IAAI,CAAC,qIAGtC,EAAC,OAAO,GAAE,CACX;;AAEH,QAAO;EAAC,aAAa;EAAQ;EAAK;;AAGpC,SAAgB,2BACd,IACA,SACA,OACA,SACA,QACoD;AACpD,KAAI,YAAY,KACd,QAAO;EACL,aAAa,gBAAgB,IAAI,SAAS,OAAO,OAAO;EACxD,SAAS;EACV;CAEH,MAAM,EAAC,SAAQ,QAAQ,IAAI,qBAAqB,MAAM,eAAe;AACrE,QAAO,SAAS,QAAQ,OACpB;EAAC,aAAa;EAAS,SAAS;EAAM,GACtC;EAAC,aAAa,gBAAgB,IAAI,SAAS,OAAO,OAAO;EAAE,SAAS;EAAK;;AAG/E,SAAgB,UAAU,IAAgB,SAA2B;CACnE,MAAM,QAAQ,gBAAgB,IAAI,SAAS,EACzC,2BAA2B,OAC5B,CAAC;AAUF,QAAO;EACL,QAVa,OAAO,YACpB,CAAC,GAAG,MAAM,QAAQ,CAAC,CAAC,KAAI,UAAS;GAC/B,MAAM,EACJ,WAAW,EAAC,MAAM,cAClB,SAAS,YACP;AACJ,UAAO,CAAC,MAAM;IAAC;IAAM;IAAS;IAAW,CAAuB;IAChE,CACH;EAGC,eAAe,EAAE;EAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-transaction.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/run-transaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAC,KAAK,UAAU,EAAE,KAAK,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AACzE,OAAO,KAAK,KAAK,IAAI,MAAM,gBAAgB,CAAC;AAG5C,KAAK,IAAI,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;AAU9B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,CAAC,EAAE,IAAI,CAAC;CACb,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,CAAC,EACrB,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,CAAC,EAAE,EAAE,mBAAmB,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC/C,IAAI,GAAE,kBAAuB,gGA+B9B"}
1
+ {"version":3,"file":"run-transaction.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/run-transaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAC,KAAK,UAAU,EAAE,KAAK,mBAAmB,EAAC,MAAM,gBAAgB,CAAC;AACzE,OAAO,KAAK,KAAK,IAAI,MAAM,gBAAgB,CAAC;AAG5C,KAAK,IAAI,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;AAU9B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,CAAC,EAAE,IAAI,CAAC;CACb,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,KAAK,CAAC,CAAC,EACrB,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,CAAC,EAAE,EAAE,mBAAmB,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC/C,IAAI,GAAE,kBAAuB,gGAgC9B"}
@@ -12,8 +12,8 @@ var IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS = parseInt(process.env.ZERO_IDLE_IN_T
12
12
  function runTx(db, fn, opts = {}) {
13
13
  const { mode = READ_COMMITTED } = opts;
14
14
  return db.begin(mode, (sql) => {
15
- sql`SET LOCAL statement_timeout = 0;`.execute();
16
- sql.unsafe(`SET LOCAL idle_in_transaction_session_timeout = ${IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS}`).execute();
15
+ sql`SET LOCAL statement_timeout = 0;`.execute().catch(() => {});
16
+ sql.unsafe(`SET LOCAL idle_in_transaction_session_timeout = ${IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS}`).execute().catch(() => {});
17
17
  return fn(sql);
18
18
  });
19
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"run-transaction.js","names":[],"sources":["../../../../../zero-cache/src/db/run-transaction.ts"],"sourcesContent":["import type {Enum} from '../../../shared/src/enum.ts';\nimport {type PostgresDB, type PostgresTransaction} from '../types/pg.ts';\nimport type * as Mode from './mode-enum.ts';\nimport {READ_COMMITTED} from './mode-enum.ts';\n\ntype Mode = Enum<typeof Mode>;\n\n// The default timeout is settable by ZERO_IDLE_IN_TRANSACTION_SESSION_TIMEOUT\n// as an emergency measure and is explicitly not made available as a server\n// option. This value is function of how the zero-cache uses transactions, and\n// should never need to be \"tuned\" or adjusted for different environments.\nconst IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS = parseInt(\n process.env.ZERO_IDLE_IN_TRANSACTION_SESSION_TIMEOUT ?? '60000',\n);\n\nexport type TransactionOptions = {\n mode?: Mode;\n};\n\n/**\n * Runs a zero-cache transaction on the given postgres DB. For consistency\n * across various postgres providers, certain transaction-level parameters\n * are set to override any defaults set by the provider, including:\n * * `statement_timeout` (disabled)\n * * `idle_in_transaction_session_timeout` (1min)\n */\nexport function runTx<T>(\n db: PostgresDB,\n fn: (tx: PostgresTransaction) => T | Promise<T>,\n opts: TransactionOptions = {},\n) {\n const {\n // Explicitly default to the Postgres default to override any custom\n // `default_transaction_isolation`.\n mode = READ_COMMITTED,\n } = opts;\n return db.begin(mode, sql => {\n // Disable any statement_timeout for the current transaction. By default,\n // Postgres does not impose a statement timeout, but some users and\n // providers set one at the database level (even though it is explicitly\n // discouraged by the Postgres documentation).\n //\n // Zero logic in particular often does not fit into the category of general\n // application logic; for potentially long-running operations like\n // migrations and background cleanup, the statement timeout should be\n // disabled to prevent these operations from timing out.\n void sql`SET LOCAL statement_timeout = 0;`.execute();\n\n // Set an idle_in_transaction_session_timeout to limit the blast radius of\n // orphaned transactions. The zero-cache does not keep transactions open\n // and idle (though this may change if support for streaming of in-progress\n // transactions is added to our logical replication layer).\n void sql\n .unsafe(\n /*sql*/ `SET LOCAL idle_in_transaction_session_timeout = ${IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS}`,\n )\n .execute();\n\n return fn(sql);\n });\n}\n"],"mappings":";;;AAWA,IAAM,yCAAyC,SAC7C,QAAQ,IAAI,4CAA4C,QACzD;;;;;;;;AAaD,SAAgB,MACd,IACA,IACA,OAA2B,EAAE,EAC7B;CACA,MAAM,EAGJ,OAAO,mBACL;AACJ,QAAO,GAAG,MAAM,OAAM,QAAO;AAUtB,KAAG,mCAAmC,SAAS;AAM/C,MACF,OACS,mDAAmD,yCAC5D,CACA,SAAS;AAEZ,SAAO,GAAG,IAAI;GACd"}
1
+ {"version":3,"file":"run-transaction.js","names":[],"sources":["../../../../../zero-cache/src/db/run-transaction.ts"],"sourcesContent":["import type {Enum} from '../../../shared/src/enum.ts';\nimport {type PostgresDB, type PostgresTransaction} from '../types/pg.ts';\nimport type * as Mode from './mode-enum.ts';\nimport {READ_COMMITTED} from './mode-enum.ts';\n\ntype Mode = Enum<typeof Mode>;\n\n// The default timeout is settable by ZERO_IDLE_IN_TRANSACTION_SESSION_TIMEOUT\n// as an emergency measure and is explicitly not made available as a server\n// option. This value is function of how the zero-cache uses transactions, and\n// should never need to be \"tuned\" or adjusted for different environments.\nconst IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS = parseInt(\n process.env.ZERO_IDLE_IN_TRANSACTION_SESSION_TIMEOUT ?? '60000',\n);\n\nexport type TransactionOptions = {\n mode?: Mode;\n};\n\n/**\n * Runs a zero-cache transaction on the given postgres DB. For consistency\n * across various postgres providers, certain transaction-level parameters\n * are set to override any defaults set by the provider, including:\n * * `statement_timeout` (disabled)\n * * `idle_in_transaction_session_timeout` (1min)\n */\nexport function runTx<T>(\n db: PostgresDB,\n fn: (tx: PostgresTransaction) => T | Promise<T>,\n opts: TransactionOptions = {},\n) {\n const {\n // Explicitly default to the Postgres default to override any custom\n // `default_transaction_isolation`.\n mode = READ_COMMITTED,\n } = opts;\n return db.begin(mode, sql => {\n // Disable any statement_timeout for the current transaction. By default,\n // Postgres does not impose a statement timeout, but some users and\n // providers set one at the database level (even though it is explicitly\n // discouraged by the Postgres documentation).\n //\n // Zero logic in particular often does not fit into the category of general\n // application logic; for potentially long-running operations like\n // migrations and background cleanup, the statement timeout should be\n // disabled to prevent these operations from timing out.\n void sql`SET LOCAL statement_timeout = 0;`.execute().catch(() => {});\n\n // Set an idle_in_transaction_session_timeout to limit the blast radius of\n // orphaned transactions. The zero-cache does not keep transactions open\n // and idle (though this may change if support for streaming of in-progress\n // transactions is added to our logical replication layer).\n void sql\n .unsafe(\n /*sql*/ `SET LOCAL idle_in_transaction_session_timeout = ${IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS}`,\n )\n .execute()\n .catch(() => {});\n\n return fn(sql);\n });\n}\n"],"mappings":";;;AAWA,IAAM,yCAAyC,SAC7C,QAAQ,IAAI,4CAA4C,QACzD;;;;;;;;AAaD,SAAgB,MACd,IACA,IACA,OAA2B,EAAE,EAC7B;CACA,MAAM,EAGJ,OAAO,mBACL;AACJ,QAAO,GAAG,MAAM,OAAM,QAAO;AAUtB,KAAG,mCAAmC,SAAS,CAAC,YAAY,GAAG;AAM/D,MACF,OACS,mDAAmD,yCAC5D,CACA,SAAS,CACT,YAAY,GAAG;AAElB,SAAO,GAAG,IAAI;GACd"}
@@ -1 +1 @@
1
- {"version":3,"file":"anonymous-otel-start.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/anonymous-otel-start.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAOjD,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,0BAA0B,CAAC;AAGlC,MAAM,MAAM,WAAW,GAAG;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAoeF,eAAO,MAAM,uBAAuB,GAAI,KAAK,UAAU,EAAE,SAAS,UAAU,SAC/C,CAAC;AAC9B,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,GAAG,QAAQ,EAAE,cAAS,SAC1B,CAAC;AACxC,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,GAAG,QAAQ,EAAE,cAAS,SAC1B,CAAC;AACrC,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,SACX,CAAC;AACpC,eAAO,MAAM,uBAAuB,YACC,CAAC;AACtC,eAAO,MAAM,yBAAyB,YACC,CAAC;AACxC,eAAO,MAAM,2BAA2B,GAAI,QAAQ,MAAM,MAAM,SACjB,CAAC;AAChD,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,WAAW,SACtB,CAAC;AACzC,eAAO,MAAM,0BAA0B,YAA6B,CAAC"}
1
+ {"version":3,"file":"anonymous-otel-start.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/anonymous-otel-start.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAOjD,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,0BAA0B,CAAC;AAGlC,MAAM,MAAM,WAAW,GAAG;IACxB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAweF,eAAO,MAAM,uBAAuB,GAAI,KAAK,UAAU,EAAE,SAAS,UAAU,SAC/C,CAAC;AAC9B,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,GAAG,QAAQ,EAAE,cAAS,SAC1B,CAAC;AACxC,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,GAAG,QAAQ,EAAE,cAAS,SAC1B,CAAC;AACrC,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,SACX,CAAC;AACpC,eAAO,MAAM,uBAAuB,YACC,CAAC;AACtC,eAAO,MAAM,yBAAyB,YACC,CAAC;AACxC,eAAO,MAAM,2BAA2B,GAAI,QAAQ,MAAM,MAAM,SACjB,CAAC;AAChD,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,WAAW,SACtB,CAAC;AACzC,eAAO,MAAM,0BAA0B,YAA6B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"anonymous-otel-start.js","names":["#instance","#processId","#lc","#starting","#config","#viewSyncerCount","#cachedAttributes","#run","#stopped","#getAttributes","#meterProvider","#meter","#setupMetrics","#activeUsersGetter","#totalCrudMutations","#totalCustomMutations","#totalCrudQueries","#totalCustomQueries","#totalRowsSynced","#totalConnectionsSuccess","#totalConnectionsAttempted","#activeClientGroupsGetter","#getPlatform","#getGitProjectId","#getOrSetFsID","#findUp","#isInContainer"],"sources":["../../../../../zero-cache/src/server/anonymous-otel-start.ts"],"sourcesContent":["import type {ObservableResult} from '@opentelemetry/api';\nimport {type Meter} from '@opentelemetry/api';\nimport {OTLPMetricExporter} from '@opentelemetry/exporter-metrics-otlp-http';\nimport {resourceFromAttributes} from '@opentelemetry/resources';\nimport {\n MeterProvider,\n PeriodicExportingMetricReader,\n} from '@opentelemetry/sdk-metrics';\nimport type {LogContext} from '@rocicorp/logger';\nimport {execSync} from 'child_process';\nimport {randomUUID} from 'crypto';\nimport {existsSync, mkdirSync, readFileSync, writeFileSync} from 'fs';\nimport {homedir, platform} from 'os';\nimport {dirname, join} from 'path';\nimport {h64} from '../../../shared/src/hash.js';\nimport {\n getServerVersion,\n getZeroConfig,\n type ZeroConfig,\n} from '../config/zero-config.js';\nimport {setupOtelDiagnosticLogger} from './otel-diag-logger.ts';\n\nexport type ActiveUsers = {\n active_users_last_day: number;\n users_1da: number;\n users_7da: number;\n users_30da: number;\n users_1da_legacy: number;\n users_7da_legacy: number;\n users_30da_legacy: number;\n};\n\nclass AnonymousTelemetryManager {\n static #instance: AnonymousTelemetryManager;\n #starting = false;\n #stopped = false;\n #meter!: Meter;\n #meterProvider!: MeterProvider;\n #totalCrudMutations = 0;\n #totalCustomMutations = 0;\n #totalCrudQueries = 0;\n #totalCustomQueries = 0;\n #totalRowsSynced = 0;\n #totalConnectionsSuccess = 0;\n #totalConnectionsAttempted = 0;\n #activeClientGroupsGetter: (() => number) | undefined;\n #activeUsersGetter: (() => ActiveUsers) | undefined;\n #lc: LogContext | undefined;\n #config: ZeroConfig | undefined;\n #processId: string;\n #cachedAttributes: Record<string, string> | undefined;\n #viewSyncerCount = 1;\n\n private constructor() {\n this.#processId = randomUUID();\n }\n\n static getInstance(): AnonymousTelemetryManager {\n if (!AnonymousTelemetryManager.#instance) {\n AnonymousTelemetryManager.#instance = new AnonymousTelemetryManager();\n }\n return AnonymousTelemetryManager.#instance;\n }\n\n start(lc?: LogContext, config?: ZeroConfig) {\n this.#lc = lc;\n\n // Set up OpenTelemetry diagnostic logger if not already configured\n setupOtelDiagnosticLogger(lc);\n\n if (!config) {\n try {\n config = getZeroConfig();\n } catch (e) {\n this.#lc?.info?.('telemetry: disabled - unable to parse config', e);\n return;\n }\n }\n\n if (process.env.DO_NOT_TRACK) {\n this.#lc?.info?.(\n 'telemetry: disabled - DO_NOT_TRACK environment variable is set',\n );\n return;\n }\n\n if (!config.enableTelemetry) {\n this.#lc?.info?.('telemetry: disabled - enableTelemetry is false');\n return;\n }\n\n if (this.#starting) {\n return;\n }\n\n this.#starting = true;\n this.#config = config;\n this.#viewSyncerCount = config.numSyncWorkers ?? 1;\n this.#cachedAttributes = undefined;\n\n this.#lc?.info?.(`telemetry: starting in 1 minute`);\n\n // Delay telemetry startup by 1 minute to avoid potential boot loop issues\n setTimeout(() => this.#run(), 60000);\n }\n\n #run() {\n if (this.#stopped) {\n return;\n }\n\n const resource = resourceFromAttributes(this.#getAttributes());\n\n // Add a random jitter to the export interval to avoid all view-syncers exporting at the same time\n const exportIntervalMillis =\n 60000 * this.#viewSyncerCount + Math.floor(Math.random() * 10000);\n const readers = [\n new PeriodicExportingMetricReader({\n exportIntervalMillis,\n exporter: new OTLPMetricExporter({\n url: 'https://metrics.rocicorp.dev',\n timeoutMillis: 30000,\n }),\n }),\n ];\n\n // Uncomment this to debug metrics exports.\n\n // readers.push(\n // new PeriodicExportingMetricReader({\n // exportIntervalMillis,\n // exporter: new ConsoleMetricExporter(),\n // }),\n // );\n\n this.#meterProvider = new MeterProvider({resource, readers});\n this.#meter = this.#meterProvider.getMeter('zero-anonymous-telemetry');\n\n this.#setupMetrics();\n this.#lc?.info?.(\n `telemetry: started (exports every ${exportIntervalMillis / 1000} seconds for ${this.#viewSyncerCount} view-syncers)`,\n );\n }\n\n #setupMetrics() {\n // Observable gauges\n const uptimeGauge = this.#meter.createObservableGauge('zero.uptime', {\n description: 'System uptime in seconds',\n unit: 'seconds',\n });\n\n // Observable counters\n const uptimeCounter = this.#meter.createObservableCounter(\n 'zero.uptime_counter',\n {\n description: 'System uptime in seconds',\n unit: 'seconds',\n },\n );\n const crudMutationsCounter = this.#meter.createObservableCounter(\n 'zero.crud_mutations_processed',\n {\n description: 'Total number of CRUD mutations processed',\n },\n );\n const customMutationsCounter = this.#meter.createObservableCounter(\n 'zero.custom_mutations_processed',\n {\n description: 'Total number of custom mutations processed',\n },\n );\n const totalMutationsCounter = this.#meter.createObservableCounter(\n 'zero.mutations_processed',\n {\n description: 'Total number of mutations processed',\n },\n );\n const crudQueriesCounter = this.#meter.createObservableCounter(\n 'zero.crud_queries_processed',\n {\n description: 'Total number of CRUD queries processed',\n },\n );\n const customQueriesCounter = this.#meter.createObservableCounter(\n 'zero.custom_queries_processed',\n {\n description: 'Total number of custom queries processed',\n },\n );\n const totalQueriesCounter = this.#meter.createObservableCounter(\n 'zero.queries_processed',\n {\n description: 'Total number of queries processed',\n },\n );\n const rowsSyncedCounter = this.#meter.createObservableCounter(\n 'zero.rows_synced',\n {\n description: 'Total number of rows synced',\n },\n );\n\n // Observable counters for connections\n const connectionsSuccessCounter = this.#meter.createObservableCounter(\n 'zero.connections_success',\n {\n description: 'Total number of successful connections',\n },\n );\n\n const connectionsAttemptedCounter = this.#meter.createObservableCounter(\n 'zero.connections_attempted',\n {\n description: 'Total number of attempted connections',\n },\n );\n\n const activeClientGroupsGauge = this.#meter.createObservableGauge(\n 'zero.gauge_active_client_groups',\n {\n description: 'Number of currently active client groups',\n },\n );\n\n const attrs = this.#getAttributes();\n const active =\n (metric: keyof ActiveUsers) => (result: ObservableResult) => {\n const actives = this.#activeUsersGetter?.();\n if (actives) {\n const value = actives[metric];\n result.observe(value, attrs);\n }\n };\n this.#meter\n .createObservableGauge('zero.active_users_last_day', {\n description: 'Count of CVR instances active in the last 24h',\n })\n .addCallback(active('active_users_last_day'));\n this.#meter\n .createObservableGauge('zero.users_1da', {\n description: 'Count of 1-day active profiles',\n })\n .addCallback(active('users_1da'));\n this.#meter\n .createObservableGauge('zero.users_7da', {\n description: 'Count of 7-day active profiles',\n })\n .addCallback(active('users_7da'));\n this.#meter\n .createObservableGauge('zero.users_30da', {\n description: 'Count of 30-day active profiles',\n })\n .addCallback(active('users_30da'));\n this.#meter\n .createObservableGauge('zero.users_1da_legacy', {\n description: 'Count of 1-day active profiles with CVR fallback',\n })\n .addCallback(active('users_1da_legacy'));\n this.#meter\n .createObservableGauge('zero.users_7da_legacy', {\n description: 'Count of 7-day active profiles with CVR fallback',\n })\n .addCallback(active('users_7da_legacy'));\n this.#meter\n .createObservableGauge('zero.users_30da_legacy', {\n description: 'Count of 30-day active profiles with CVR fallback',\n })\n .addCallback(active('users_30da_legacy'));\n\n // Callbacks\n uptimeGauge.addCallback((result: ObservableResult) => {\n const uptimeSeconds = Math.floor(process.uptime());\n result.observe(uptimeSeconds, attrs);\n });\n uptimeCounter.addCallback((result: ObservableResult) => {\n const uptimeSeconds = Math.floor(process.uptime());\n result.observe(uptimeSeconds, attrs);\n });\n crudMutationsCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalCrudMutations, attrs);\n });\n customMutationsCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalCustomMutations, attrs);\n });\n totalMutationsCounter.addCallback((result: ObservableResult) => {\n const totalMutations =\n this.#totalCrudMutations + this.#totalCustomMutations;\n result.observe(totalMutations, attrs);\n });\n crudQueriesCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalCrudQueries, attrs);\n });\n customQueriesCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalCustomQueries, attrs);\n });\n totalQueriesCounter.addCallback((result: ObservableResult) => {\n const totalQueries = this.#totalCrudQueries + this.#totalCustomQueries;\n result.observe(totalQueries, attrs);\n });\n rowsSyncedCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalRowsSynced, attrs);\n });\n connectionsSuccessCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalConnectionsSuccess, attrs);\n });\n connectionsAttemptedCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalConnectionsAttempted, attrs);\n });\n activeClientGroupsGauge.addCallback((result: ObservableResult) => {\n const activeClientGroups = this.#activeClientGroupsGetter?.() ?? 0;\n result.observe(activeClientGroups, attrs);\n });\n }\n\n recordMutation(type: 'crud' | 'custom', count = 1) {\n if (type === 'crud') {\n this.#totalCrudMutations += count;\n } else {\n this.#totalCustomMutations += count;\n }\n }\n\n recordQuery(type: 'crud' | 'custom', count = 1) {\n if (type === 'crud') {\n this.#totalCrudQueries += count;\n } else {\n this.#totalCustomQueries += count;\n }\n }\n\n recordRowsSynced(count: number) {\n this.#totalRowsSynced += count;\n }\n\n recordConnectionSuccess() {\n this.#totalConnectionsSuccess++;\n }\n\n recordConnectionAttempted() {\n this.#totalConnectionsAttempted++;\n }\n\n setActiveClientGroupsGetter(getter: () => number) {\n this.#activeClientGroupsGetter = getter;\n }\n\n setActiveUsersGetter(getter: () => ActiveUsers) {\n this.#activeUsersGetter = getter;\n }\n\n shutdown() {\n this.#stopped = true;\n if (this.#meterProvider) {\n this.#lc?.info?.('telemetry: shutting down');\n void this.#meterProvider.shutdown();\n }\n }\n\n #getAttributes() {\n if (!this.#cachedAttributes) {\n this.#cachedAttributes = {\n 'zero.app.id': h64(this.#config?.upstream.db || 'unknown').toString(),\n 'zero.machine.os': platform(),\n 'zero.telemetry.type': 'anonymous',\n 'zero.infra.platform': this.#getPlatform(),\n 'zero.version': getServerVersion(this.#config),\n 'zero.task.id': this.#config?.taskID || 'unknown',\n 'zero.project.id': this.#getGitProjectId(),\n 'zero.process.id': this.#processId,\n 'zero.fs.id': this.#getOrSetFsID(),\n };\n this.#lc?.debug?.(\n `telemetry: cached attributes=${JSON.stringify(this.#cachedAttributes)}`,\n );\n }\n return this.#cachedAttributes;\n }\n\n #getPlatform(): string {\n if (process.env.ZERO_ON_CLOUD_ZERO) return 'cloudzero';\n if (process.env.FLY_APP_NAME || process.env.FLY_REGION) return 'fly.io';\n if (\n process.env.ECS_CONTAINER_METADATA_URI_V4 ||\n process.env.ECS_CONTAINER_METADATA_URI ||\n process.env.AWS_EXECUTION_ENV\n )\n return 'aws';\n if (process.env.RAILWAY_ENV || process.env.RAILWAY_STATIC_URL)\n return 'railway';\n if (process.env.RENDER || process.env.RENDER_SERVICE_ID) return 'render';\n if (\n process.env.GCP_PROJECT ||\n process.env.GCLOUD_PROJECT ||\n process.env.GOOGLE_CLOUD_PROJECT\n )\n return 'gcp';\n if (process.env.COOLIFY_URL || process.env.COOLIFY_CONTAINER_NAME)\n return 'coolify';\n if (process.env.CONTAINER_APP_REVISION) return 'azure';\n if (process.env.FLIGHTCONTROL || process.env.FC_URL) return 'flightcontrol';\n return 'unknown';\n }\n\n #findUp(startDir: string, target: string): string | null {\n let dir = startDir;\n while (dir !== dirname(dir)) {\n if (existsSync(join(dir, target))) return dir;\n dir = dirname(dir);\n }\n return null;\n }\n\n #getGitProjectId(): string {\n try {\n const cwd = process.cwd();\n const gitRoot = this.#findUp(cwd, '.git');\n if (!gitRoot) {\n return 'unknown';\n }\n\n const rootCommitHash = execSync('git rev-list --max-parents=0 HEAD -1', {\n cwd: gitRoot,\n encoding: 'utf8',\n timeout: 1000,\n stdio: ['ignore', 'pipe', 'ignore'], // Suppress stderr\n }).trim();\n\n return rootCommitHash.length === 40 ? rootCommitHash : 'unknown';\n } catch (error) {\n this.#lc?.debug?.('telemetry: unable to get Git root commit:', error);\n return 'unknown';\n }\n }\n\n #getOrSetFsID(): string {\n try {\n if (this.#isInContainer()) {\n return 'container';\n }\n const fsidPath = join(homedir(), '.rocicorp', 'fsid');\n const fsidDir = dirname(fsidPath);\n\n mkdirSync(fsidDir, {recursive: true});\n\n // Always try atomic file creation first - this eliminates any race conditions\n const newId = randomUUID();\n try {\n writeFileSync(fsidPath, newId, {encoding: 'utf8', flag: 'wx'});\n return newId;\n } catch (writeError) {\n if ((writeError as NodeJS.ErrnoException).code === 'EEXIST') {\n const existingId = readFileSync(fsidPath, 'utf8').trim();\n return existingId;\n }\n throw writeError;\n }\n } catch (error) {\n this.#lc?.debug?.(\n 'telemetry: unable to get or set filesystem ID:',\n error,\n );\n return 'unknown';\n }\n }\n\n #isInContainer(): boolean {\n try {\n if (process.env.ZERO_IN_CONTAINER) {\n return true;\n }\n\n if (existsSync('/.dockerenv')) {\n return true;\n }\n\n if (existsSync('/usr/local/bin/docker-entrypoint.sh')) {\n return true;\n }\n\n if (process.env.KUBERNETES_SERVICE_HOST) {\n return true;\n }\n\n if (\n process.env.DOCKER_CONTAINER_ID ||\n process.env.HOSTNAME?.match(/^[a-f0-9]{12}$/)\n ) {\n return true;\n }\n\n if (existsSync('/proc/1/cgroup')) {\n const cgroup = readFileSync('/proc/1/cgroup', 'utf8');\n if (\n cgroup.includes('docker') ||\n cgroup.includes('kubepods') ||\n cgroup.includes('containerd')\n ) {\n return true;\n }\n }\n\n return false;\n } catch (error) {\n this.#lc?.debug?.(\n 'telemetry: unable to detect container environment:',\n error,\n );\n return false;\n }\n }\n}\n\nconst manager = () => AnonymousTelemetryManager.getInstance();\n\nexport const startAnonymousTelemetry = (lc?: LogContext, config?: ZeroConfig) =>\n manager().start(lc, config);\nexport const recordMutation = (type: 'crud' | 'custom', count = 1) =>\n manager().recordMutation(type, count);\nexport const recordQuery = (type: 'crud' | 'custom', count = 1) =>\n manager().recordQuery(type, count);\nexport const recordRowsSynced = (count: number) =>\n manager().recordRowsSynced(count);\nexport const recordConnectionSuccess = () =>\n manager().recordConnectionSuccess();\nexport const recordConnectionAttempted = () =>\n manager().recordConnectionAttempted();\nexport const setActiveClientGroupsGetter = (getter: () => number) =>\n manager().setActiveClientGroupsGetter(getter);\nexport const setActiveUsersGetter = (getter: () => ActiveUsers) =>\n manager().setActiveUsersGetter(getter);\nexport const shutdownAnonymousTelemetry = () => manager().shutdown();\n"],"mappings":"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"}
1
+ {"version":3,"file":"anonymous-otel-start.js","names":["#instance","#processId","#lc","#starting","#config","#viewSyncerCount","#cachedAttributes","#run","#stopped","#getAttributes","#meterProvider","#meter","#setupMetrics","#activeUsersGetter","#totalCrudMutations","#totalCustomMutations","#totalCrudQueries","#totalCustomQueries","#totalRowsSynced","#totalConnectionsSuccess","#totalConnectionsAttempted","#activeClientGroupsGetter","#getPlatform","#getGitProjectId","#getOrSetFsID","#findUp","#isInContainer"],"sources":["../../../../../zero-cache/src/server/anonymous-otel-start.ts"],"sourcesContent":["import type {ObservableResult} from '@opentelemetry/api';\nimport {type Meter} from '@opentelemetry/api';\nimport {OTLPMetricExporter} from '@opentelemetry/exporter-metrics-otlp-http';\nimport {resourceFromAttributes} from '@opentelemetry/resources';\nimport {\n MeterProvider,\n PeriodicExportingMetricReader,\n} from '@opentelemetry/sdk-metrics';\nimport type {LogContext} from '@rocicorp/logger';\nimport {execSync} from 'child_process';\nimport {randomUUID} from 'crypto';\nimport {existsSync, mkdirSync, readFileSync, writeFileSync} from 'fs';\nimport {homedir, platform} from 'os';\nimport {dirname, join} from 'path';\nimport {h64} from '../../../shared/src/hash.js';\nimport {\n getServerVersion,\n getZeroConfig,\n type ZeroConfig,\n} from '../config/zero-config.js';\nimport {setupOtelDiagnosticLogger} from './otel-diag-logger.ts';\n\nexport type ActiveUsers = {\n active_users_last_day: number;\n users_1da: number;\n users_7da: number;\n users_30da: number;\n users_1da_legacy: number;\n users_7da_legacy: number;\n users_30da_legacy: number;\n};\n\nclass AnonymousTelemetryManager {\n static #instance: AnonymousTelemetryManager;\n #starting = false;\n #stopped = false;\n #meter!: Meter;\n #meterProvider!: MeterProvider;\n #totalCrudMutations = 0;\n #totalCustomMutations = 0;\n #totalCrudQueries = 0;\n #totalCustomQueries = 0;\n #totalRowsSynced = 0;\n #totalConnectionsSuccess = 0;\n #totalConnectionsAttempted = 0;\n #activeClientGroupsGetter: (() => number) | undefined;\n #activeUsersGetter: (() => ActiveUsers) | undefined;\n #lc: LogContext | undefined;\n #config: ZeroConfig | undefined;\n #processId: string;\n #cachedAttributes: Record<string, string> | undefined;\n #viewSyncerCount = 1;\n\n private constructor() {\n this.#processId = randomUUID();\n }\n\n static getInstance(): AnonymousTelemetryManager {\n if (!AnonymousTelemetryManager.#instance) {\n AnonymousTelemetryManager.#instance = new AnonymousTelemetryManager();\n }\n return AnonymousTelemetryManager.#instance;\n }\n\n start(lc?: LogContext, config?: ZeroConfig) {\n this.#lc = lc;\n\n // Set up OpenTelemetry diagnostic logger if not already configured\n setupOtelDiagnosticLogger(lc);\n\n if (!config) {\n try {\n config = getZeroConfig();\n } catch (e) {\n this.#lc?.info?.('telemetry: disabled - unable to parse config', e);\n return;\n }\n }\n\n if (process.env.DO_NOT_TRACK) {\n this.#lc?.info?.(\n 'telemetry: disabled - DO_NOT_TRACK environment variable is set',\n );\n return;\n }\n\n if (!config.enableTelemetry) {\n this.#lc?.info?.('telemetry: disabled - enableTelemetry is false');\n return;\n }\n\n if (this.#starting) {\n return;\n }\n\n this.#starting = true;\n this.#config = config;\n this.#viewSyncerCount = config.numSyncWorkers ?? 1;\n this.#cachedAttributes = undefined;\n\n this.#lc?.info?.(`telemetry: starting in 1 minute`);\n\n // Delay telemetry startup by 1 minute to avoid potential boot loop issues\n setTimeout(() => this.#run(), 60000);\n }\n\n #run() {\n if (this.#stopped) {\n return;\n }\n\n const resource = resourceFromAttributes(this.#getAttributes());\n\n // Add a random jitter to the export interval to avoid all view-syncers exporting at the same time\n const exportIntervalMillis =\n 60000 * this.#viewSyncerCount + Math.floor(Math.random() * 10000);\n const readers = [\n new PeriodicExportingMetricReader({\n exportIntervalMillis,\n exporter: new OTLPMetricExporter({\n url: 'https://metrics.rocicorp.dev',\n timeoutMillis: 30000,\n }),\n }),\n ];\n\n // Uncomment this to debug metrics exports.\n\n // readers.push(\n // new PeriodicExportingMetricReader({\n // exportIntervalMillis,\n // exporter: new ConsoleMetricExporter(),\n // }),\n // );\n\n this.#meterProvider = new MeterProvider({resource, readers});\n this.#meter = this.#meterProvider.getMeter('zero-anonymous-telemetry');\n\n this.#setupMetrics();\n this.#lc?.info?.(\n `telemetry: started (exports every ${exportIntervalMillis / 1000} seconds for ${this.#viewSyncerCount} view-syncers)`,\n );\n }\n\n #setupMetrics() {\n // Observable gauges\n const uptimeGauge = this.#meter.createObservableGauge('zero.uptime', {\n description: 'System uptime in seconds',\n unit: 'seconds',\n });\n\n // Observable counters\n const uptimeCounter = this.#meter.createObservableCounter(\n 'zero.uptime_counter',\n {\n description: 'System uptime in seconds',\n unit: 'seconds',\n },\n );\n const crudMutationsCounter = this.#meter.createObservableCounter(\n 'zero.crud_mutations_processed',\n {\n description: 'Total number of CRUD mutations processed',\n },\n );\n const customMutationsCounter = this.#meter.createObservableCounter(\n 'zero.custom_mutations_processed',\n {\n description: 'Total number of custom mutations processed',\n },\n );\n const totalMutationsCounter = this.#meter.createObservableCounter(\n 'zero.mutations_processed',\n {\n description: 'Total number of mutations processed',\n },\n );\n const crudQueriesCounter = this.#meter.createObservableCounter(\n 'zero.crud_queries_processed',\n {\n description: 'Total number of CRUD queries processed',\n },\n );\n const customQueriesCounter = this.#meter.createObservableCounter(\n 'zero.custom_queries_processed',\n {\n description: 'Total number of custom queries processed',\n },\n );\n const totalQueriesCounter = this.#meter.createObservableCounter(\n 'zero.queries_processed',\n {\n description: 'Total number of queries processed',\n },\n );\n const rowsSyncedCounter = this.#meter.createObservableCounter(\n 'zero.rows_synced',\n {\n description: 'Total number of rows synced',\n },\n );\n\n // Observable counters for connections\n const connectionsSuccessCounter = this.#meter.createObservableCounter(\n 'zero.connections_success',\n {\n description: 'Total number of successful connections',\n },\n );\n\n const connectionsAttemptedCounter = this.#meter.createObservableCounter(\n 'zero.connections_attempted',\n {\n description: 'Total number of attempted connections',\n },\n );\n\n const activeClientGroupsGauge = this.#meter.createObservableGauge(\n 'zero.gauge_active_client_groups',\n {\n description: 'Number of currently active client groups',\n },\n );\n\n const attrs = this.#getAttributes();\n const active =\n (metric: keyof ActiveUsers) => (result: ObservableResult) => {\n const actives = this.#activeUsersGetter?.();\n if (actives) {\n const value = actives[metric];\n result.observe(value, attrs);\n }\n };\n this.#meter\n .createObservableGauge('zero.active_users_last_day', {\n description: 'Count of CVR instances active in the last 24h',\n })\n .addCallback(active('active_users_last_day'));\n this.#meter\n .createObservableGauge('zero.users_1da', {\n description: 'Count of 1-day active profiles',\n })\n .addCallback(active('users_1da'));\n this.#meter\n .createObservableGauge('zero.users_7da', {\n description: 'Count of 7-day active profiles',\n })\n .addCallback(active('users_7da'));\n this.#meter\n .createObservableGauge('zero.users_30da', {\n description: 'Count of 30-day active profiles',\n })\n .addCallback(active('users_30da'));\n this.#meter\n .createObservableGauge('zero.users_1da_legacy', {\n description: 'Count of 1-day active profiles with CVR fallback',\n })\n .addCallback(active('users_1da_legacy'));\n this.#meter\n .createObservableGauge('zero.users_7da_legacy', {\n description: 'Count of 7-day active profiles with CVR fallback',\n })\n .addCallback(active('users_7da_legacy'));\n this.#meter\n .createObservableGauge('zero.users_30da_legacy', {\n description: 'Count of 30-day active profiles with CVR fallback',\n })\n .addCallback(active('users_30da_legacy'));\n\n // Callbacks\n uptimeGauge.addCallback((result: ObservableResult) => {\n const uptimeSeconds = Math.floor(process.uptime());\n result.observe(uptimeSeconds, attrs);\n });\n uptimeCounter.addCallback((result: ObservableResult) => {\n const uptimeSeconds = Math.floor(process.uptime());\n result.observe(uptimeSeconds, attrs);\n });\n crudMutationsCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalCrudMutations, attrs);\n });\n customMutationsCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalCustomMutations, attrs);\n });\n totalMutationsCounter.addCallback((result: ObservableResult) => {\n const totalMutations =\n this.#totalCrudMutations + this.#totalCustomMutations;\n result.observe(totalMutations, attrs);\n });\n crudQueriesCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalCrudQueries, attrs);\n });\n customQueriesCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalCustomQueries, attrs);\n });\n totalQueriesCounter.addCallback((result: ObservableResult) => {\n const totalQueries = this.#totalCrudQueries + this.#totalCustomQueries;\n result.observe(totalQueries, attrs);\n });\n rowsSyncedCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalRowsSynced, attrs);\n });\n connectionsSuccessCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalConnectionsSuccess, attrs);\n });\n connectionsAttemptedCounter.addCallback((result: ObservableResult) => {\n result.observe(this.#totalConnectionsAttempted, attrs);\n });\n activeClientGroupsGauge.addCallback((result: ObservableResult) => {\n const activeClientGroups = this.#activeClientGroupsGetter?.() ?? 0;\n result.observe(activeClientGroups, attrs);\n });\n }\n\n recordMutation(type: 'crud' | 'custom', count = 1) {\n if (type === 'crud') {\n this.#totalCrudMutations += count;\n } else {\n this.#totalCustomMutations += count;\n }\n }\n\n recordQuery(type: 'crud' | 'custom', count = 1) {\n if (type === 'crud') {\n this.#totalCrudQueries += count;\n } else {\n this.#totalCustomQueries += count;\n }\n }\n\n recordRowsSynced(count: number) {\n this.#totalRowsSynced += count;\n }\n\n recordConnectionSuccess() {\n this.#totalConnectionsSuccess++;\n }\n\n recordConnectionAttempted() {\n this.#totalConnectionsAttempted++;\n }\n\n setActiveClientGroupsGetter(getter: () => number) {\n this.#activeClientGroupsGetter = getter;\n }\n\n setActiveUsersGetter(getter: () => ActiveUsers) {\n this.#activeUsersGetter = getter;\n }\n\n shutdown() {\n this.#stopped = true;\n if (this.#meterProvider) {\n this.#lc?.info?.('telemetry: shutting down');\n void this.#meterProvider.shutdown();\n }\n }\n\n #getAttributes() {\n if (!this.#cachedAttributes) {\n this.#cachedAttributes = {\n 'zero.app.id': h64(this.#config?.upstream.db || 'unknown').toString(),\n 'zero.machine.os': platform(),\n 'zero.telemetry.type': 'anonymous',\n 'zero.infra.platform': this.#getPlatform(),\n 'zero.version': getServerVersion(this.#config),\n 'zero.task.id': this.#config?.taskID || 'unknown',\n 'zero.project.id': this.#getGitProjectId(),\n 'zero.process.id': this.#processId,\n 'zero.fs.id': this.#getOrSetFsID(),\n };\n this.#lc?.debug?.(\n `telemetry: cached attributes=${JSON.stringify(this.#cachedAttributes)}`,\n );\n }\n return this.#cachedAttributes;\n }\n\n #getPlatform(): string {\n if (process.env.ZERO_ON_CLOUD_ZERO) return 'cloudzero';\n if (process.env.FLY_APP_NAME || process.env.FLY_REGION) return 'fly.io';\n if (\n process.env.ECS_CONTAINER_METADATA_URI_V4 ||\n process.env.ECS_CONTAINER_METADATA_URI ||\n process.env.AWS_EXECUTION_ENV\n ) {\n return 'aws';\n }\n if (process.env.RAILWAY_ENV || process.env.RAILWAY_STATIC_URL) {\n return 'railway';\n }\n if (process.env.RENDER || process.env.RENDER_SERVICE_ID) return 'render';\n if (\n process.env.GCP_PROJECT ||\n process.env.GCLOUD_PROJECT ||\n process.env.GOOGLE_CLOUD_PROJECT\n ) {\n return 'gcp';\n }\n if (process.env.COOLIFY_URL || process.env.COOLIFY_CONTAINER_NAME) {\n return 'coolify';\n }\n if (process.env.CONTAINER_APP_REVISION) return 'azure';\n if (process.env.FLIGHTCONTROL || process.env.FC_URL) return 'flightcontrol';\n return 'unknown';\n }\n\n #findUp(startDir: string, target: string): string | null {\n let dir = startDir;\n while (dir !== dirname(dir)) {\n if (existsSync(join(dir, target))) return dir;\n dir = dirname(dir);\n }\n return null;\n }\n\n #getGitProjectId(): string {\n try {\n const cwd = process.cwd();\n const gitRoot = this.#findUp(cwd, '.git');\n if (!gitRoot) {\n return 'unknown';\n }\n\n const rootCommitHash = execSync('git rev-list --max-parents=0 HEAD -1', {\n cwd: gitRoot,\n encoding: 'utf8',\n timeout: 1000,\n stdio: ['ignore', 'pipe', 'ignore'], // Suppress stderr\n }).trim();\n\n return rootCommitHash.length === 40 ? rootCommitHash : 'unknown';\n } catch (error) {\n this.#lc?.debug?.('telemetry: unable to get Git root commit:', error);\n return 'unknown';\n }\n }\n\n #getOrSetFsID(): string {\n try {\n if (this.#isInContainer()) {\n return 'container';\n }\n const fsidPath = join(homedir(), '.rocicorp', 'fsid');\n const fsidDir = dirname(fsidPath);\n\n mkdirSync(fsidDir, {recursive: true});\n\n // Always try atomic file creation first - this eliminates any race conditions\n const newId = randomUUID();\n try {\n writeFileSync(fsidPath, newId, {encoding: 'utf8', flag: 'wx'});\n return newId;\n } catch (writeError) {\n if ((writeError as NodeJS.ErrnoException).code === 'EEXIST') {\n const existingId = readFileSync(fsidPath, 'utf8').trim();\n return existingId;\n }\n throw writeError;\n }\n } catch (error) {\n this.#lc?.debug?.(\n 'telemetry: unable to get or set filesystem ID:',\n error,\n );\n return 'unknown';\n }\n }\n\n #isInContainer(): boolean {\n try {\n if (process.env.ZERO_IN_CONTAINER) {\n return true;\n }\n\n if (existsSync('/.dockerenv')) {\n return true;\n }\n\n if (existsSync('/usr/local/bin/docker-entrypoint.sh')) {\n return true;\n }\n\n if (process.env.KUBERNETES_SERVICE_HOST) {\n return true;\n }\n\n if (\n process.env.DOCKER_CONTAINER_ID ||\n process.env.HOSTNAME?.match(/^[a-f0-9]{12}$/)\n ) {\n return true;\n }\n\n if (existsSync('/proc/1/cgroup')) {\n const cgroup = readFileSync('/proc/1/cgroup', 'utf8');\n if (\n cgroup.includes('docker') ||\n cgroup.includes('kubepods') ||\n cgroup.includes('containerd')\n ) {\n return true;\n }\n }\n\n return false;\n } catch (error) {\n this.#lc?.debug?.(\n 'telemetry: unable to detect container environment:',\n error,\n );\n return false;\n }\n }\n}\n\nconst manager = () => AnonymousTelemetryManager.getInstance();\n\nexport const startAnonymousTelemetry = (lc?: LogContext, config?: ZeroConfig) =>\n manager().start(lc, config);\nexport const recordMutation = (type: 'crud' | 'custom', count = 1) =>\n manager().recordMutation(type, count);\nexport const recordQuery = (type: 'crud' | 'custom', count = 1) =>\n manager().recordQuery(type, count);\nexport const recordRowsSynced = (count: number) =>\n manager().recordRowsSynced(count);\nexport const recordConnectionSuccess = () =>\n manager().recordConnectionSuccess();\nexport const recordConnectionAttempted = () =>\n manager().recordConnectionAttempted();\nexport const setActiveClientGroupsGetter = (getter: () => number) =>\n manager().setActiveClientGroupsGetter(getter);\nexport const setActiveUsersGetter = (getter: () => ActiveUsers) =>\n manager().setActiveUsersGetter(getter);\nexport const shutdownAnonymousTelemetry = () => manager().shutdown();\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/logging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,gCAAgC,CAAC;AAGxC,wBAAgB,gBAAgB,CAC9B,EAAC,GAAG,EAAC,EAAE;IAAC,GAAG,EAAE,SAAS,CAAA;CAAC,EACvB,OAAO,EAAE;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,EACzB,WAAW,UAAO,GACjB,UAAU,CAMZ"}
1
+ {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/logging.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,gCAAgC,CAAC;AAIxC,wBAAgB,gBAAgB,CAC9B,EAAC,GAAG,EAAC,EAAE;IAAC,GAAG,EAAE,SAAS,CAAA;CAAC,EACvB,OAAO,EAAE;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,EACzB,WAAW,UAAO,GACjB,UAAU,CASZ"}
@@ -1,10 +1,18 @@
1
+ import "../services/life-cycle.js";
1
2
  import { otelLogsEnabled } from "../../../otel/src/enabled.js";
2
3
  import { createLogContext as createLogContext$1, getLogSink } from "../../../shared/src/logging.js";
3
4
  import { OtelLogSink } from "./otel-log-sink.js";
4
5
  import "@rocicorp/logger";
5
6
  //#region ../zero-cache/src/server/logging.ts
6
7
  function createLogContext({ log }, context, includeOtel = true) {
7
- return createLogContext$1({ log }, context, createLogSink(log, includeOtel));
8
+ const logSink = createLogSink(log, includeOtel);
9
+ const lc = createLogContext$1({ log }, context, logSink);
10
+ process.on("uncaughtException", async (err, origin) => {
11
+ lc.error?.(origin, err);
12
+ await logSink.flush?.();
13
+ process.exit(13);
14
+ });
15
+ return lc;
8
16
  }
9
17
  function createLogSink(config, includeOtel) {
10
18
  const sink = getLogSink(config);
@@ -1 +1 @@
1
- {"version":3,"file":"logging.js","names":["#sinks"],"sources":["../../../../../zero-cache/src/server/logging.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {type Context, type LogLevel, type LogSink} from '@rocicorp/logger';\nimport {otelLogsEnabled} from '../../../otel/src/enabled.ts';\nimport {\n createLogContext as createLogContextShared,\n getLogSink,\n type LogConfig,\n} from '../../../shared/src/logging.ts';\nimport {OtelLogSink} from './otel-log-sink.ts';\n\nexport function createLogContext(\n {log}: {log: LogConfig},\n context: {worker: string},\n includeOtel = true,\n): LogContext {\n return createLogContextShared(\n {log},\n context,\n createLogSink(log, includeOtel),\n );\n}\n\nfunction createLogSink(config: LogConfig, includeOtel: boolean): LogSink {\n const sink = getLogSink(config);\n if (includeOtel && otelLogsEnabled()) {\n const otelSink = new OtelLogSink();\n return new CompositeLogSink([otelSink, sink]);\n }\n return sink;\n}\n\nclass CompositeLogSink implements LogSink {\n readonly #sinks: LogSink[];\n\n constructor(sinks: LogSink[]) {\n this.#sinks = sinks;\n }\n\n log(level: LogLevel, context: Context | undefined, ...args: unknown[]): void {\n for (const sink of this.#sinks) {\n sink.log(level, context, ...args);\n }\n }\n}\n"],"mappings":";;;;;AAUA,SAAgB,iBACd,EAAC,OACD,SACA,cAAc,MACF;AACZ,QAAO,mBACL,EAAC,KAAI,EACL,SACA,cAAc,KAAK,YAAY,CAChC;;AAGH,SAAS,cAAc,QAAmB,aAA+B;CACvE,MAAM,OAAO,WAAW,OAAO;AAC/B,KAAI,eAAe,iBAAiB,CAElC,QAAO,IAAI,iBAAiB,CADX,IAAI,aAAa,EACK,KAAK,CAAC;AAE/C,QAAO;;AAGT,IAAM,mBAAN,MAA0C;CACxC;CAEA,YAAY,OAAkB;AAC5B,QAAA,QAAc;;CAGhB,IAAI,OAAiB,SAA8B,GAAG,MAAuB;AAC3E,OAAK,MAAM,QAAQ,MAAA,MACjB,MAAK,IAAI,OAAO,SAAS,GAAG,KAAK"}
1
+ {"version":3,"file":"logging.js","names":["#sinks"],"sources":["../../../../../zero-cache/src/server/logging.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {type Context, type LogLevel, type LogSink} from '@rocicorp/logger';\nimport {otelLogsEnabled} from '../../../otel/src/enabled.ts';\nimport {\n createLogContext as createLogContextShared,\n getLogSink,\n type LogConfig,\n} from '../../../shared/src/logging.ts';\nimport {UNHANDLED_EXCEPTION_ERROR_CODE} from '../services/life-cycle.ts';\nimport {OtelLogSink} from './otel-log-sink.ts';\n\nexport function createLogContext(\n {log}: {log: LogConfig},\n context: {worker: string},\n includeOtel = true,\n): LogContext {\n const logSink = createLogSink(log, includeOtel);\n const lc = createLogContextShared({log}, context, logSink);\n process.on('uncaughtException', async (err, origin) => {\n lc.error?.(origin, err);\n await logSink.flush?.();\n process.exit(UNHANDLED_EXCEPTION_ERROR_CODE);\n });\n return lc;\n}\n\nfunction createLogSink(config: LogConfig, includeOtel: boolean): LogSink {\n const sink = getLogSink(config);\n if (includeOtel && otelLogsEnabled()) {\n const otelSink = new OtelLogSink();\n return new CompositeLogSink([otelSink, sink]);\n }\n return sink;\n}\n\nclass CompositeLogSink implements LogSink {\n readonly #sinks: LogSink[];\n\n constructor(sinks: LogSink[]) {\n this.#sinks = sinks;\n }\n\n log(level: LogLevel, context: Context | undefined, ...args: unknown[]): void {\n for (const sink of this.#sinks) {\n sink.log(level, context, ...args);\n }\n }\n}\n"],"mappings":";;;;;;AAWA,SAAgB,iBACd,EAAC,OACD,SACA,cAAc,MACF;CACZ,MAAM,UAAU,cAAc,KAAK,YAAY;CAC/C,MAAM,KAAK,mBAAuB,EAAC,KAAI,EAAE,SAAS,QAAQ;AAC1D,SAAQ,GAAG,qBAAqB,OAAO,KAAK,WAAW;AACrD,KAAG,QAAQ,QAAQ,IAAI;AACvB,QAAM,QAAQ,SAAS;AACvB,UAAQ,KAAA,GAAoC;GAC5C;AACF,QAAO;;AAGT,SAAS,cAAc,QAAmB,aAA+B;CACvE,MAAM,OAAO,WAAW,OAAO;AAC/B,KAAI,eAAe,iBAAiB,CAElC,QAAO,IAAI,iBAAiB,CADX,IAAI,aAAa,EACK,KAAK,CAAC;AAE/C,QAAO;;AAGT,IAAM,mBAAN,MAA0C;CACxC;CAEA,YAAY,OAAkB;AAC5B,QAAA,QAAc;;CAGhB,IAAI,OAAiB,SAA8B,GAAG,MAAuB;AAC3E,OAAK,MAAM,QAAQ,MAAA,MACjB,MAAK,IAAI,OAAO,SAAS,GAAG,KAAK"}
@@ -18,6 +18,7 @@ import type { SingletonService } from './service.ts';
18
18
  export type WorkerType = 'user-facing' | 'supporting';
19
19
  export declare const GRACEFUL_SHUTDOWN: readonly ["SIGTERM", "SIGINT"];
20
20
  export declare const FORCEFUL_SHUTDOWN: readonly ["SIGQUIT"];
21
+ export declare const UNHANDLED_EXCEPTION_ERROR_CODE = 13;
21
22
  /**
22
23
  * Handles readiness, termination signals, and coordination of graceful
23
24
  * shutdown.
@@ -1 +1 @@
1
- {"version":3,"file":"life-cycle.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/services/life-cycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,WAAW,CAAC;AAEnD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAC;AACzC,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,YAAY,CAAC;AAEtD,eAAO,MAAM,iBAAiB,gCAAiC,CAAC;AAChE,eAAO,MAAM,iBAAiB,sBAAuB,CAAC;AAEtD;;;GAGG;AACH,qBAAa,cAAc;;gBAWb,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY;IAiC9C,IAAI;IAoBJ,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM;IA2B9D,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAiBjE,YAAY,IAAI,MAAM,EAAE;IAIlB,eAAe;IAIrB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM;CAqE3C;AAED;;;;;;GAMG;AAEH,wBAAsB,cAAc,CAClC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,YAAY,EACpB,GAAG,QAAQ,EAAE,gBAAgB,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,iBAWvD;AAID;;;;;;;;;;GAUG;AACH,qBAAa,gBAAgB;;gBAQf,EAAE,EAAE,UAAU,EAAE,YAAY,SAA2B;IAKnE,WAAW,CAAC,UAAU,EAAE,mBAAmB;IAsD3C,IAAI;CAML"}
1
+ {"version":3,"file":"life-cycle.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/services/life-cycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,WAAW,CAAC;AAEnD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAC;AACzC,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,MAAM,EACZ,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,YAAY,CAAC;AAEtD,eAAO,MAAM,iBAAiB,gCAAiC,CAAC;AAChE,eAAO,MAAM,iBAAiB,sBAAuB,CAAC;AAKtD,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD;;;GAGG;AACH,qBAAa,cAAc;;gBAWb,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY;IAiC9C,IAAI;IAoBJ,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM;IA2B9D,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAiBjE,YAAY,IAAI,MAAM,EAAE;IAIlB,eAAe;IAIrB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM;CAwE3C;AAED;;;;;;GAMG;AAEH,wBAAsB,cAAc,CAClC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,YAAY,EACpB,GAAG,QAAQ,EAAE,gBAAgB,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,iBAWvD;AAID;;;;;;;;;;GAUG;AACH,qBAAa,gBAAgB;;gBAQf,EAAE,EAAE,UAAU,EAAE,YAAY,SAA2B;IAKnE,WAAW,CAAC,UAAU,EAAE,mBAAmB;IAsD3C,IAAI;CAML"}