@coffre/db 0.14.5 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/README.md +2 -1
  2. package/dist/change-records-_fKvahvs.js +55 -0
  3. package/dist/connect.d.ts +22 -10
  4. package/dist/connect.js +74 -12
  5. package/dist/database-CVteLhp1.d.ts +410 -0
  6. package/dist/{database-BadNeeN-.js → database-D55ENPX-.js} +46 -25
  7. package/dist/dialect.d.ts +4 -3
  8. package/dist/dialect.js +14 -5
  9. package/dist/grants.d.ts +4 -4
  10. package/dist/grants.js +4 -4
  11. package/dist/hyperdrive.d.ts +48 -23
  12. package/dist/hyperdrive.js +168 -91
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.js +1 -1
  15. package/dist/log-DaD7fyUq.d.ts +722 -0
  16. package/dist/log.d.ts +2 -622
  17. package/dist/log.js +178 -13
  18. package/dist/migrate.d.ts +43 -3
  19. package/dist/migrate.js +149 -29
  20. package/dist/migrations/postgres/0022_log_015.sql +672 -0
  21. package/dist/migrations/postgres/0023_change_path.sql +153 -0
  22. package/dist/migrations/postgres/0024_use_015.sql +556 -0
  23. package/dist/migrations/postgres/0025_app_change.sql +221 -0
  24. package/dist/migrations/postgres/0026_issue_lock.sql +106 -0
  25. package/dist/migrations/postgres/0027_retention.sql +118 -0
  26. package/dist/migrations/postgres/0028_use_stalls.sql +594 -0
  27. package/dist/migrations/postgres/0029_use_objects.sql +887 -0
  28. package/dist/migrations/postgres/0030_unarchive_restores.sql +259 -0
  29. package/dist/migrations/postgres/0031_app_read.sql +65 -0
  30. package/dist/migrations/postgres/0032_secrets_live_index.sql +4 -0
  31. package/dist/migrations/postgres/0033_use_generations.sql +582 -0
  32. package/dist/migrations/postgres/0034_vault_credentials.sql +153 -0
  33. package/dist/migrations/postgres/0035_first_days.sql +3 -0
  34. package/dist/migrations/postgres/0036_vault_issues.sql +91 -0
  35. package/dist/migrations/postgres/0037_vault_bindings.sql +271 -0
  36. package/dist/migrations/postgres/0040_binding_origin.sql +159 -0
  37. package/dist/migrations/postgres/0041_cutover.sql +132 -0
  38. package/dist/migrations/postgres/0042_sign_in_index.sql +7 -0
  39. package/dist/migrations/postgres/0043_issue_revoke_index.sql +4 -0
  40. package/dist/migrations/postgres/0044_use_by_name.sql +705 -0
  41. package/dist/migrations/postgres/0045_decide_first.sql +878 -0
  42. package/dist/migrations/postgres/0046_way_in_uses.sql +1149 -0
  43. package/dist/migrations/postgres/0047_cutover_finish.sql +268 -0
  44. package/dist/migrations/postgres/0048_use_batch.sql +59 -0
  45. package/dist/migrations/postgres/0049_reads.sql +171 -0
  46. package/dist/migrations/postgres/meta/0022_snapshot.json +3831 -0
  47. package/dist/migrations/postgres/meta/0023_snapshot.json +3831 -0
  48. package/dist/migrations/postgres/meta/0024_snapshot.json +3831 -0
  49. package/dist/migrations/postgres/meta/0025_snapshot.json +3831 -0
  50. package/dist/migrations/postgres/meta/0026_snapshot.json +3831 -0
  51. package/dist/migrations/postgres/meta/0027_snapshot.json +3853 -0
  52. package/dist/migrations/postgres/meta/0028_snapshot.json +3853 -0
  53. package/dist/migrations/postgres/meta/0029_snapshot.json +3859 -0
  54. package/dist/migrations/postgres/meta/0030_snapshot.json +3859 -0
  55. package/dist/migrations/postgres/meta/0031_snapshot.json +3859 -0
  56. package/dist/migrations/postgres/meta/0032_snapshot.json +3875 -0
  57. package/dist/migrations/postgres/meta/0033_snapshot.json +3875 -0
  58. package/dist/migrations/postgres/meta/0034_snapshot.json +3875 -0
  59. package/dist/migrations/postgres/meta/0035_snapshot.json +3875 -0
  60. package/dist/migrations/postgres/meta/0036_snapshot.json +3875 -0
  61. package/dist/migrations/postgres/meta/0037_snapshot.json +3875 -0
  62. package/dist/migrations/postgres/meta/0038_snapshot.json +3881 -0
  63. package/dist/migrations/postgres/meta/0039_snapshot.json +3881 -0
  64. package/dist/migrations/postgres/meta/0040_snapshot.json +3931 -0
  65. package/dist/migrations/postgres/meta/0041_snapshot.json +3981 -0
  66. package/dist/migrations/postgres/meta/0042_snapshot.json +3981 -0
  67. package/dist/migrations/postgres/meta/0043_snapshot.json +3981 -0
  68. package/dist/migrations/postgres/meta/0044_snapshot.json +3991 -0
  69. package/dist/migrations/postgres/meta/0045_snapshot.json +3997 -0
  70. package/dist/migrations/postgres/meta/0046_snapshot.json +3997 -0
  71. package/dist/migrations/postgres/meta/0047_snapshot.json +4234 -0
  72. package/dist/migrations/postgres/meta/_journal.json +182 -0
  73. package/dist/migrations/sqlite/0018_log_015.sql +84 -0
  74. package/dist/migrations/sqlite/0019_retention.sql +2 -0
  75. package/dist/migrations/sqlite/0020_ended_references.sql +1 -0
  76. package/dist/migrations/sqlite/0021_secrets_live_index.sql +1 -0
  77. package/dist/migrations/sqlite/0022_binding_origin.sql +1 -0
  78. package/dist/migrations/sqlite/0023_sign_in_index.sql +2 -0
  79. package/dist/migrations/sqlite/0024_issue_revoke_index.sql +2 -0
  80. package/dist/migrations/sqlite/0025_way_in_uses.sql +42 -0
  81. package/dist/migrations/sqlite/0026_cutover_finish.sql +11 -0
  82. package/dist/migrations/sqlite/0027_reads.sql +38 -0
  83. package/dist/migrations/sqlite/meta/0018_snapshot.json +3529 -0
  84. package/dist/migrations/sqlite/meta/0019_snapshot.json +3538 -0
  85. package/dist/migrations/sqlite/meta/0020_snapshot.json +3545 -0
  86. package/dist/migrations/sqlite/meta/0021_snapshot.json +3553 -0
  87. package/dist/migrations/sqlite/meta/0022_snapshot.json +3560 -0
  88. package/dist/migrations/sqlite/meta/0023_snapshot.json +3579 -0
  89. package/dist/migrations/sqlite/meta/0024_snapshot.json +3598 -0
  90. package/dist/migrations/sqlite/meta/0025_snapshot.json +3609 -0
  91. package/dist/migrations/sqlite/meta/0026_snapshot.json +3616 -0
  92. package/dist/migrations/sqlite/meta/0027_snapshot.json +3834 -0
  93. package/dist/migrations/sqlite/meta/_journal.json +70 -0
  94. package/dist/platform-Y3gICK6n.d.ts +58 -0
  95. package/dist/portable.d.ts +2 -2
  96. package/dist/postgres-BI3xTnyw.js +1718 -0
  97. package/dist/postgres-platform-node.d.ts +14 -0
  98. package/dist/postgres-platform-node.js +21 -0
  99. package/dist/postgres-platform-workerd.d.ts +61 -0
  100. package/dist/postgres-platform-workerd.js +163 -0
  101. package/dist/{schema-BfQEBqFv.d.ts → schema-DgoPqqsI.d.ts} +1326 -7
  102. package/dist/schema-sqlite.d.ts +1306 -6
  103. package/dist/schema-sqlite.js +154 -18
  104. package/dist/schema-version.d.ts +1 -1
  105. package/dist/schema-version.js +254 -2
  106. package/dist/schema.d.ts +2 -2
  107. package/dist/schema.js +226 -20
  108. package/package.json +13 -5
  109. package/src/active-subject.ts +9 -0
  110. package/src/change-records.ts +38 -0
  111. package/src/connect.ts +67 -13
  112. package/src/database.ts +67 -51
  113. package/src/dialect.ts +17 -8
  114. package/src/grants.ts +3 -3
  115. package/src/hyperdrive.ts +181 -104
  116. package/src/log.ts +196 -15
  117. package/src/migrate.ts +157 -30
  118. package/src/migrations/postgres/0022_log_015.sql +672 -0
  119. package/src/migrations/postgres/0023_change_path.sql +153 -0
  120. package/src/migrations/postgres/0024_use_015.sql +556 -0
  121. package/src/migrations/postgres/0025_app_change.sql +221 -0
  122. package/src/migrations/postgres/0026_issue_lock.sql +106 -0
  123. package/src/migrations/postgres/0027_retention.sql +118 -0
  124. package/src/migrations/postgres/0028_use_stalls.sql +594 -0
  125. package/src/migrations/postgres/0029_use_objects.sql +887 -0
  126. package/src/migrations/postgres/0030_unarchive_restores.sql +259 -0
  127. package/src/migrations/postgres/0031_app_read.sql +65 -0
  128. package/src/migrations/postgres/0032_secrets_live_index.sql +4 -0
  129. package/src/migrations/postgres/0033_use_generations.sql +582 -0
  130. package/src/migrations/postgres/0034_vault_credentials.sql +153 -0
  131. package/src/migrations/postgres/0035_first_days.sql +3 -0
  132. package/src/migrations/postgres/0036_vault_issues.sql +91 -0
  133. package/src/migrations/postgres/0037_vault_bindings.sql +271 -0
  134. package/src/migrations/postgres/0040_binding_origin.sql +159 -0
  135. package/src/migrations/postgres/0041_cutover.sql +132 -0
  136. package/src/migrations/postgres/0042_sign_in_index.sql +7 -0
  137. package/src/migrations/postgres/0043_issue_revoke_index.sql +4 -0
  138. package/src/migrations/postgres/0044_use_by_name.sql +705 -0
  139. package/src/migrations/postgres/0045_decide_first.sql +878 -0
  140. package/src/migrations/postgres/0046_way_in_uses.sql +1149 -0
  141. package/src/migrations/postgres/0047_cutover_finish.sql +268 -0
  142. package/src/migrations/postgres/0048_use_batch.sql +59 -0
  143. package/src/migrations/postgres/0049_reads.sql +171 -0
  144. package/src/migrations/postgres/meta/0022_snapshot.json +3831 -0
  145. package/src/migrations/postgres/meta/0023_snapshot.json +3831 -0
  146. package/src/migrations/postgres/meta/0024_snapshot.json +3831 -0
  147. package/src/migrations/postgres/meta/0025_snapshot.json +3831 -0
  148. package/src/migrations/postgres/meta/0026_snapshot.json +3831 -0
  149. package/src/migrations/postgres/meta/0027_snapshot.json +3853 -0
  150. package/src/migrations/postgres/meta/0028_snapshot.json +3853 -0
  151. package/src/migrations/postgres/meta/0029_snapshot.json +3859 -0
  152. package/src/migrations/postgres/meta/0030_snapshot.json +3859 -0
  153. package/src/migrations/postgres/meta/0031_snapshot.json +3859 -0
  154. package/src/migrations/postgres/meta/0032_snapshot.json +3875 -0
  155. package/src/migrations/postgres/meta/0033_snapshot.json +3875 -0
  156. package/src/migrations/postgres/meta/0034_snapshot.json +3875 -0
  157. package/src/migrations/postgres/meta/0035_snapshot.json +3875 -0
  158. package/src/migrations/postgres/meta/0036_snapshot.json +3875 -0
  159. package/src/migrations/postgres/meta/0037_snapshot.json +3875 -0
  160. package/src/migrations/postgres/meta/0038_snapshot.json +3881 -0
  161. package/src/migrations/postgres/meta/0039_snapshot.json +3881 -0
  162. package/src/migrations/postgres/meta/0040_snapshot.json +3931 -0
  163. package/src/migrations/postgres/meta/0041_snapshot.json +3981 -0
  164. package/src/migrations/postgres/meta/0042_snapshot.json +3981 -0
  165. package/src/migrations/postgres/meta/0043_snapshot.json +3981 -0
  166. package/src/migrations/postgres/meta/0044_snapshot.json +3991 -0
  167. package/src/migrations/postgres/meta/0045_snapshot.json +3997 -0
  168. package/src/migrations/postgres/meta/0046_snapshot.json +3997 -0
  169. package/src/migrations/postgres/meta/0047_snapshot.json +4234 -0
  170. package/src/migrations/postgres/meta/_journal.json +182 -0
  171. package/src/migrations/sqlite/0018_log_015.sql +84 -0
  172. package/src/migrations/sqlite/0019_retention.sql +2 -0
  173. package/src/migrations/sqlite/0020_ended_references.sql +1 -0
  174. package/src/migrations/sqlite/0021_secrets_live_index.sql +1 -0
  175. package/src/migrations/sqlite/0022_binding_origin.sql +1 -0
  176. package/src/migrations/sqlite/0023_sign_in_index.sql +2 -0
  177. package/src/migrations/sqlite/0024_issue_revoke_index.sql +2 -0
  178. package/src/migrations/sqlite/0025_way_in_uses.sql +42 -0
  179. package/src/migrations/sqlite/0026_cutover_finish.sql +11 -0
  180. package/src/migrations/sqlite/0027_reads.sql +38 -0
  181. package/src/migrations/sqlite/meta/0018_snapshot.json +3529 -0
  182. package/src/migrations/sqlite/meta/0019_snapshot.json +3538 -0
  183. package/src/migrations/sqlite/meta/0020_snapshot.json +3545 -0
  184. package/src/migrations/sqlite/meta/0021_snapshot.json +3553 -0
  185. package/src/migrations/sqlite/meta/0022_snapshot.json +3560 -0
  186. package/src/migrations/sqlite/meta/0023_snapshot.json +3579 -0
  187. package/src/migrations/sqlite/meta/0024_snapshot.json +3598 -0
  188. package/src/migrations/sqlite/meta/0025_snapshot.json +3609 -0
  189. package/src/migrations/sqlite/meta/0026_snapshot.json +3616 -0
  190. package/src/migrations/sqlite/meta/0027_snapshot.json +3834 -0
  191. package/src/migrations/sqlite/meta/_journal.json +70 -0
  192. package/src/postgres-js/README.md +183 -0
  193. package/src/postgres-js/UNLICENSE +24 -0
  194. package/src/postgres-js/bytes.ts +89 -0
  195. package/src/postgres-js/connection.ts +882 -0
  196. package/src/postgres-js/errors.ts +84 -0
  197. package/src/postgres-js/index.ts +516 -0
  198. package/src/postgres-js/platform.node.ts +29 -0
  199. package/src/postgres-js/platform.ts +60 -0
  200. package/src/postgres-js/platform.workerd.ts +225 -0
  201. package/src/postgres-js/query.ts +123 -0
  202. package/src/postgres-js/queue.ts +42 -0
  203. package/src/postgres-js/result.ts +46 -0
  204. package/src/postgres-js/types.ts +52 -0
  205. package/src/postgres.ts +375 -26
  206. package/src/schema-version.ts +2 -2
  207. package/src/schema.sqlite.ts +198 -7
  208. package/src/schema.ts +291 -6
  209. package/src/verify-runtime.ts +18 -29
  210. package/LICENSE +0 -21
  211. package/dist/database-wq1AVRAP.d.ts +0 -73
  212. package/dist/postgres-Bmar8y0q.js +0 -29
  213. package/dist/relations-BfR3JjT1.js +0 -38
  214. package/src/relations.ts +0 -40
@@ -1,10 +1,11 @@
1
1
  import { n as trackCommits } from "./commits-BuW-NL3n.js";
2
+ import { s as textTypes } from "./postgres-BI3xTnyw.js";
2
3
  import { t as schema_exports } from "./schema.js";
3
4
  import { engineOf } from "./dialect.js";
4
5
  import { AsyncLocalStorage } from "node:async_hooks";
5
- import { Table, createTableRelationsHelpers, extractTablesRelationalConfig, getTableName, is } from "drizzle-orm";
6
- import { NodePgDatabase, NodePgDriver } from "drizzle-orm/node-postgres";
7
- import { PgDialect } from "drizzle-orm/pg-core";
6
+ import { Table, getTableName, is } from "drizzle-orm";
7
+ import { PgDatabase, PgDialect } from "drizzle-orm/pg-core";
8
+ import { PostgresJsSession, PostgresJsTransaction } from "drizzle-orm/postgres-js/session";
8
9
  //#region src/prepared.ts
9
10
  /**
10
11
  * A select built once per process, or once per isolate on Workers, and run
@@ -59,21 +60,29 @@ var QueryOutsideTransaction = class extends Error {
59
60
  this.name = "QueryOutsideTransaction";
60
61
  }
61
62
  };
62
- /** The transaction a flow of work runs inside, with the pool it holds, while it is open. */
63
+ /** The transaction a flow of work runs inside, with the client it holds, while it is open. */
63
64
  const inside = new AsyncLocalStorage();
65
+ /** What Drizzle asks of the client: a statement, or a transaction, which postgres.js runs on a connection it holds. */
66
+ const ASKS = /* @__PURE__ */ new Set([
67
+ "unsafe",
68
+ "begin",
69
+ "reserve"
70
+ ]);
64
71
  /**
65
- * `pool`, refusing a query or a transaction asked from inside a transaction
72
+ * `client`, refusing a query or a transaction asked from inside a transaction
66
73
  * it is already running. Work from any other flow, a concurrent request's,
67
74
  * or what the transaction left running once its work was done, goes on as before.
68
75
  */
69
- function guarded(pool) {
70
- return new Proxy(pool, { get(target, key) {
76
+ function guarded(client) {
77
+ const refuse = (target) => {
78
+ const open = inside.getStore();
79
+ if (open?.open === true && open.client === target) throw new QueryOutsideTransaction();
80
+ };
81
+ return new Proxy(client, { get(target, key) {
71
82
  const value = Reflect.get(target, key, target);
72
- if (typeof value !== "function") return value;
73
- if (key !== "query" && key !== "connect") return value.bind(target);
83
+ if (typeof value !== "function" || !ASKS.has(key)) return value;
74
84
  return (...args) => {
75
- const open = inside.getStore();
76
- if (open?.open === true && open.pool === target) throw new QueryOutsideTransaction();
85
+ refuse(target);
77
86
  return value.apply(target, args);
78
87
  };
79
88
  } });
@@ -82,26 +91,38 @@ function guarded(pool) {
82
91
  function brokenRule(error) {
83
92
  for (let cause = error; cause instanceof Error; cause = cause.cause) if (cause instanceof QueryOutsideTransaction) return cause;
84
93
  }
85
- let relational;
86
- function relationalSchema() {
87
- if (relational === void 0) {
88
- const { tables, tableNamesMap } = extractTablesRelationalConfig(schema_exports, createTableRelationsHelpers);
89
- relational = {
90
- fullSchema: schema_exports,
91
- schema: tables,
92
- tableNamesMap
93
- };
94
+ const relational = {
95
+ fullSchema: schema_exports,
96
+ schema: {},
97
+ tableNamesMap: {}
98
+ };
99
+ /**
100
+ * Drizzle's session for postgres.js, but for a transaction's options, which
101
+ * go in its BEGIN, as node-postgres's session sends them, rather than in a
102
+ * SET TRANSACTION of their own: a round trip less for a snapshot read.
103
+ */
104
+ var Session = class extends PostgresJsSession {
105
+ transaction(work, config) {
106
+ const { dialect, schema: tables, options } = this;
107
+ return this.client.begin(config === void 0 ? "" : transactionOptions(config), (client) => work(new PostgresJsTransaction(dialect, new PostgresJsSession(client, dialect, tables, options), tables)));
94
108
  }
95
- return relational;
109
+ };
110
+ /** What follows BEGIN for `config`, as Drizzle writes it for SET TRANSACTION. */
111
+ function transactionOptions(config) {
112
+ return [
113
+ config.isolationLevel === void 0 ? null : `isolation level ${config.isolationLevel}`,
114
+ config.accessMode ?? null,
115
+ config.deferrable === void 0 ? null : config.deferrable ? "deferrable" : "not deferrable"
116
+ ].filter((option) => option !== null).join(" ");
96
117
  }
97
- function createDatabase(pool) {
118
+ function createDatabase(client) {
119
+ if ("options" in client) textTypes(client);
98
120
  const dialect = new PgDialect();
99
- const config = relationalSchema();
100
- const db = new NodePgDatabase(dialect, new NodePgDriver(guarded(pool), dialect).createSession(config), config);
121
+ const db = new PgDatabase(dialect, new Session(guarded(client), dialect, relational), relational);
101
122
  const run = db.transaction.bind(db);
102
123
  db.transaction = (async (work, config) => {
103
124
  const open = {
104
- pool,
125
+ client,
105
126
  open: true
106
127
  };
107
128
  try {
package/dist/dialect.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as Queryable } from "./database-wq1AVRAP.js";
1
+ import { a as Queryable } from "./database-CVteLhp1.js";
2
2
  import { SQL, SQLWrapper } from "drizzle-orm";
3
3
  import { PgTable } from "drizzle-orm/pg-core";
4
4
  //#region src/dialect.d.ts
@@ -9,7 +9,7 @@ import { PgTable } from "drizzle-orm/pg-core";
9
9
  * Postgres SQLite
10
10
  * isolation READ COMMITTED one writer at a time
11
11
  * lock a row SELECT … FOR UPDATE one writer at a time
12
- * rows changed rowCount rowsAffected
12
+ * rows changed count rowsAffected
13
13
  * duplicate key SQLSTATE 23505 SQLITE_CONSTRAINT_UNIQUE
14
14
  * clock CURRENT_TIMESTAMP strftime(…, 'now')
15
15
  * clock, in ms clock_timestamp() unixepoch('subsec')
@@ -57,7 +57,8 @@ export declare function isUniqueViolation(error: unknown): boolean;
57
57
  /**
58
58
  * Whether a query failed because the database could not be reached or
59
59
  * dropped the connection: an outage, not an answer. Postgres's connection
60
- * exceptions are class 08; pg and Workers' sockets say so in words, and so
60
+ * exceptions are class 08; postgres.js says so in codes of its own, Workers'
61
+ * sockets in words, and so
61
62
  * does Hyperdrive when it has no connection to the database to give: every
62
63
  * one of its pool busy for 15 s ("Timed out while waiting for an open slot
63
64
  * in the pool", FATAL 58000; "Failed to acquire a connection from the
package/dist/dialect.js CHANGED
@@ -27,7 +27,7 @@ function forUpdate(db, query, strength = "update") {
27
27
  * are the query's own, unmapped.
28
28
  */
29
29
  async function rowsOf(db, query) {
30
- if (engineOf(db) === "postgres") return (await db.execute(query)).rows;
30
+ if (engineOf(db) === "postgres") return [...await db.execute(query)];
31
31
  return db.all(query);
32
32
  }
33
33
  /** Insert the rows whose unique keys are free; returns how many that was. */
@@ -58,7 +58,7 @@ function truth(condition) {
58
58
  /** How many rows an insert, update or delete touched. */
59
59
  function changedRows(result) {
60
60
  const header = result;
61
- return header.rowCount ?? header.rowsAffected ?? 0;
61
+ return header.count ?? header.rowsAffected ?? 0;
62
62
  }
63
63
  const DUPLICATE_KEY = /* @__PURE__ */ new Set([
64
64
  "23505",
@@ -74,7 +74,11 @@ function isUniqueViolation(error) {
74
74
  }
75
75
  return false;
76
76
  }
77
- /** The network's codes for a server that is not there, and Postgres's for one that will not take the connection, or has none left (53300). */
77
+ /**
78
+ * The network's codes for a server that is not there, postgres.js's for a
79
+ * connection lost, cut short or never made, and Postgres's for one that will
80
+ * not take the connection, or has none left (53300).
81
+ */
78
82
  const UNREACHABLE = /* @__PURE__ */ new Set([
79
83
  "ECONNREFUSED",
80
84
  "ECONNRESET",
@@ -84,17 +88,22 @@ const UNREACHABLE = /* @__PURE__ */ new Set([
84
88
  "EHOSTUNREACH",
85
89
  "ENETUNREACH",
86
90
  "EPIPE",
91
+ "CONNECTION_CLOSED",
92
+ "CONNECTION_DESTROYED",
93
+ "CONNECTION_ENDED",
94
+ "CONNECT_TIMEOUT",
87
95
  "53300",
88
96
  "57P01",
89
97
  "57P02",
90
98
  "57P03"
91
99
  ]);
92
- /** Hyperdrive's words for having no connection to give, beside pg's and Workers' for one lost. */
100
+ /** Hyperdrive's words for having no connection to give, beside Workers' for one lost. */
93
101
  const UNREACHABLE_WORDS = /connection terminated|network connection lost|connect(ion)? timeout|open slot in the pool|acquire a connection from the pool|server connection attempt failed/i;
94
102
  /**
95
103
  * Whether a query failed because the database could not be reached or
96
104
  * dropped the connection: an outage, not an answer. Postgres's connection
97
- * exceptions are class 08; pg and Workers' sockets say so in words, and so
105
+ * exceptions are class 08; postgres.js says so in codes of its own, Workers'
106
+ * sockets in words, and so
98
107
  * does Hyperdrive when it has no connection to the database to give: every
99
108
  * one of its pool busy for 15 s ("Timed out while waiting for an open slot
100
109
  * in the pool", FATAL 58000; "Failed to acquire a connection from the
package/dist/grants.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { i as Queryable } from "./database-wq1AVRAP.js";
2
- import { Authenticity, Newest } from "./log.js";
1
+ import { a as Queryable } from "./database-CVteLhp1.js";
2
+ import { f as Newest, n as Authenticity } from "./log-DaD7fyUq.js";
3
3
  import { StoredEntry } from "@coffre/core/audit";
4
4
  import { Conversion, ConversionInput, InstanceRole, Scope } from "@coffre/core/access";
5
5
  //#region src/grants.d.ts
@@ -136,8 +136,8 @@ export declare function tamperedMembers(db: Queryable, principal?: string): Prom
136
136
  * taken to.
137
137
  */
138
138
  export declare function reportStands(db: Queryable, principal: string, check: Authenticity): Promise<boolean>;
139
- /** The newest access entry about `principal` that `check` finds the vault's own. */
140
- export declare function newestAccess(db: Queryable, principal: string, check: Authenticity): Promise<Newest>;
139
+ /** The newest access entry about `principal` that `check` finds the vault's own; at or below `through`, if given. */
140
+ export declare function newestAccess(db: Queryable, principal: string, check: Authenticity, through?: bigint): Promise<Newest>;
141
141
  /** Up to `limit` of the vault's allowed access entries about `principal` before `before` (the newest when undefined), newest first. */
142
142
  export declare function accessEntriesAbout(db: Queryable, principal: string, limit: number, before?: bigint): Promise<StoredEntry[]>;
143
143
  //#endregion
package/dist/grants.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { tombstone, truth } from "./dialect.js";
2
- import { a as prepared, i as tablesOf } from "./database-BadNeeN-.js";
2
+ import { a as prepared, i as tablesOf } from "./database-D55ENPX-.js";
3
3
  import { entryColumns, newestAuthentic } from "./log.js";
4
4
  import { and, asc, desc, eq, gt, inArray, isNull, like, lt, or, sql } from "drizzle-orm";
5
5
  import { EVERYWHERE, administers, convertEveryProjectGrants, isInstanceRole, isScope, normalScope, unscoped } from "@coffre/core/access";
@@ -238,9 +238,9 @@ async function reportStands(db, principal, check) {
238
238
  const report = await newestAuthentic((limit, before) => tamperReportsAbout(db, principal, limit, after, before), check);
239
239
  return report === "unreached" || typeof report !== "string";
240
240
  }
241
- /** The newest access entry about `principal` that `check` finds the vault's own. */
242
- function newestAccess(db, principal, check) {
243
- return newestAuthentic((limit, before) => accessEntriesAbout(db, principal, limit, before), check);
241
+ /** The newest access entry about `principal` that `check` finds the vault's own; at or below `through`, if given. */
242
+ function newestAccess(db, principal, check, through) {
243
+ return newestAuthentic((limit, before) => accessEntriesAbout(db, principal, limit, before ?? (through === void 0 ? void 0 : through + 1n)), check);
244
244
  }
245
245
  /** Up to `limit` of the vault's allowed access entries about `principal` before `before` (the newest when undefined), newest first. */
246
246
  async function accessEntriesAbout(db, principal, limit, before) {
@@ -1,5 +1,4 @@
1
- import { n as PoolLike } from "./database-wq1AVRAP.js";
2
- import pg from "pg";
1
+ import { f as PostgresClient, t as Client } from "./database-CVteLhp1.js";
3
2
  //#region src/hyperdrive.d.ts
4
3
  /** Postgres through a Hyperdrive binding: `postgres(env.HYPERDRIVE)`. */
5
4
  export type PostgresDatabase = {
@@ -13,8 +12,8 @@ export declare function postgres(hyperdrive: {
13
12
  readonly connectionString: string;
14
13
  }): PostgresDatabase;
15
14
  /**
16
- * node-postgres for one call on Workers, through Hyperdrive: one client,
17
- * connected on the first query, which every query and transaction of the
15
+ * postgres.js for one call on Workers, through Hyperdrive: one connection,
16
+ * opened by the first query, which every query and transaction of the
18
17
  * call takes its turn on.
19
18
  *
20
19
  * Hyperdrive keeps the pool to the database; a Worker's connections belong
@@ -23,33 +22,59 @@ export declare function postgres(hyperdrive: {
23
22
  * once was now and then cancelled as hung, with nothing left pending, and
24
23
  * every connection costs a round trip before the query can be sent.
25
24
  *
26
- * The turns keep a transaction whole: queries go to the client in the order
27
- * they are asked, a transaction holds it from BEGIN until it is released,
28
- * and a query asked meanwhile waits until then, so nothing runs inside a
29
- * transaction it is not part of. So code inside a transaction must query
30
- * through the transaction: a query on the database there would wait for the
31
- * transaction to end, which waits for it. Neither the vault nor the server
32
- * does.
25
+ * The turns keep a transaction whole: statements go to the connection in
26
+ * the order they are asked, each once the one before it has answered; a
27
+ * transaction holds the connection from BEGIN until it ends, and a query
28
+ * asked meanwhile waits until then, so nothing runs inside a transaction it
29
+ * is not part of. So code inside a transaction must query through the
30
+ * transaction: a query on the database there would wait for the transaction
31
+ * to end, which waits for it. Neither the vault nor the server does.
33
32
  *
34
- * The class name must end in `Pool`: that is how Drizzle knows to check out
35
- * a client for each transaction.
33
+ * With `groupReads`, the plain reads (`select …`, outside a transaction)
34
+ * asked while the pool waits for their turn, or in the same task, take it
35
+ * together, sent under one Sync (`group` in postgres-js/index.ts): on
36
+ * Hyperdrive, which sends a client's Syncs on one at a time, a round trip
37
+ * for them all, where each alone took one. They run as one implicit
38
+ * transaction, so if one fails they all do, with its error; each is a
39
+ * read, so none had anything to keep. Anything else asked meanwhile, a
40
+ * write or a transaction, closes the group, and goes after it: statements
41
+ * still go in the order they are asked.
42
+ *
43
+ * Closed by `end`, once what was asked has answered; asked again after, as
44
+ * a call's background work may, it opens a connection again. Unless `end`
45
+ * was given a time to close by and reached it: then the connection closes
46
+ * at once, failing what is still asked, and nothing opens it again. And
47
+ * `destroy` cuts it the same way, at any time.
36
48
  */
37
- export declare class HyperdrivePool implements Exclude<PoolLike, pg.Pool> {
49
+ export declare class HyperdrivePool implements Client {
38
50
  #private;
39
51
  /**
40
52
  * `closeIdleMs`: for what outlives a call, a Durable Object, which queries
41
- * now and then: the client closes once it has been idle that long, and
42
- * the next query connects again.
53
+ * now and then: the connection closes once it has been idle that long,
54
+ * and the next query connects again. `groupReads`: plain reads asked
55
+ * together go together, under one Sync.
43
56
  */
44
57
  constructor(connectionString: string, options?: {
45
58
  closeIdleMs?: number;
59
+ groupReads?: boolean;
46
60
  });
47
- readonly query: pg.Pool['query'];
48
- /** The client, for a transaction: held from now until `release`. */
49
- connect(): Promise<Pick<pg.PoolClient, 'query'> & {
50
- release: () => void;
51
- }>;
52
- /** Close the client once nothing waits on it: what a Worker hands `waitUntil` when the call is done. */
53
- end(): Promise<void>;
61
+ readonly unsafe: PostgresClient["unsafe"];
62
+ /** A transaction: its turn lasts until it has committed or rolled back. */
63
+ readonly begin: PostgresClient["begin"];
64
+ /**
65
+ * Close the connection once every turn asked is done: what a Worker hands `waitUntil` when the call is done. By
66
+ * `by` (ms since the epoch) at the latest, if given: then at once, what is still asked failing, the statement under
67
+ * way included, and none of it sent again. A use's call past its deadline, whose answer has gone, so lets go of
68
+ * Hyperdrive: what it asked and Hyperdrive had not sent goes with the connection (use.ts, `HELD_PAST_DEADLINE_MS`).
69
+ */
70
+ end(by?: number): Promise<void>;
71
+ /**
72
+ * The connection cut now, what it was asked failing at once, and every
73
+ * turn after refused: for what a host stopped waiting on, a connection
74
+ * gone dead or a connect that never answers (T169), so that whatever
75
+ * still awaits it fails rather than waits for good. Its statement may
76
+ * still run in the database.
77
+ */
78
+ destroy(): void;
54
79
  }
55
80
  //#endregion
@@ -1,17 +1,22 @@
1
- import { t as postgresConnection } from "./postgres-Bmar8y0q.js";
2
- import pg from "pg";
1
+ import { c as plainRead, n as postgresClient, s as textTypes } from "./postgres-BI3xTnyw.js";
3
2
  //#region src/hyperdrive.ts
4
3
  /** Postgres through Hyperdrive, the one database a Worker runs on, the app's and the vault's. */
5
4
  function postgres(hyperdrive) {
6
- if (typeof hyperdrive?.connectionString !== "string") throw new Error("postgres() takes the Hyperdrive binding, e.g. postgres(env.HYPERDRIVE)");
5
+ if (typeof hyperdrive?.connectionString !== "string") throw new Error("postgres() was given no Hyperdrive binding: one the code names (HYPERDRIVE, VAULT_HYPERDRIVE, HOT_HYPERDRIVE) is missing from its wrangler.jsonc, or bound under another name");
7
6
  return {
8
7
  engine: "postgres",
9
8
  hyperdrive
10
9
  };
11
10
  }
11
+ /** What the client refuses to write of a group, before anything of it is sent (`build`, postgres-js/connection.ts). */
12
+ const UNSENT = /* @__PURE__ */ new Set([
13
+ "GROUP_UNTYPED",
14
+ "MAX_PARAMETERS_EXCEEDED",
15
+ "UNDEFINED_VALUE"
16
+ ]);
12
17
  /**
13
- * node-postgres for one call on Workers, through Hyperdrive: one client,
14
- * connected on the first query, which every query and transaction of the
18
+ * postgres.js for one call on Workers, through Hyperdrive: one connection,
19
+ * opened by the first query, which every query and transaction of the
15
20
  * call takes its turn on.
16
21
  *
17
22
  * Hyperdrive keeps the pool to the database; a Worker's connections belong
@@ -20,119 +25,191 @@ function postgres(hyperdrive) {
20
25
  * once was now and then cancelled as hung, with nothing left pending, and
21
26
  * every connection costs a round trip before the query can be sent.
22
27
  *
23
- * The turns keep a transaction whole: queries go to the client in the order
24
- * they are asked, a transaction holds it from BEGIN until it is released,
25
- * and a query asked meanwhile waits until then, so nothing runs inside a
26
- * transaction it is not part of. So code inside a transaction must query
27
- * through the transaction: a query on the database there would wait for the
28
- * transaction to end, which waits for it. Neither the vault nor the server
29
- * does.
28
+ * The turns keep a transaction whole: statements go to the connection in
29
+ * the order they are asked, each once the one before it has answered; a
30
+ * transaction holds the connection from BEGIN until it ends, and a query
31
+ * asked meanwhile waits until then, so nothing runs inside a transaction it
32
+ * is not part of. So code inside a transaction must query through the
33
+ * transaction: a query on the database there would wait for the transaction
34
+ * to end, which waits for it. Neither the vault nor the server does.
30
35
  *
31
- * The class name must end in `Pool`: that is how Drizzle knows to check out
32
- * a client for each transaction.
36
+ * With `groupReads`, the plain reads (`select …`, outside a transaction)
37
+ * asked while the pool waits for their turn, or in the same task, take it
38
+ * together, sent under one Sync (`group` in postgres-js/index.ts): on
39
+ * Hyperdrive, which sends a client's Syncs on one at a time, a round trip
40
+ * for them all, where each alone took one. They run as one implicit
41
+ * transaction, so if one fails they all do, with its error; each is a
42
+ * read, so none had anything to keep. Anything else asked meanwhile, a
43
+ * write or a transaction, closes the group, and goes after it: statements
44
+ * still go in the order they are asked.
45
+ *
46
+ * Closed by `end`, once what was asked has answered; asked again after, as
47
+ * a call's background work may, it opens a connection again. Unless `end`
48
+ * was given a time to close by and reached it: then the connection closes
49
+ * at once, failing what is still asked, and nothing opens it again. And
50
+ * `destroy` cuts it the same way, at any time.
33
51
  */
34
52
  var HyperdrivePool = class {
35
53
  #connectionString;
36
- /** The client, connecting or connected; null before the first query, and once it has failed. */
54
+ /** How long the connection may sit idle before it closes, or undefined: closed by `end` alone. */
55
+ #closeIdleMs;
56
+ /** The client, made by the first statement; null before it, and once `end` closed it. */
37
57
  #client = null;
38
- /** Whether a transaction holds the client. */
39
- #held = false;
40
- /** What waits for its turn, in the order it asked. */
41
- #waiting = [];
42
- /** Queries and transactions asked and not done: waiting for the client, their turn, or an answer. */
58
+ /** The end of the last turn asked: the next one starts once it has. */
59
+ #tail = Promise.resolve();
60
+ /** Turns asked and not done: waiting, or under way. */
43
61
  #busy = 0;
44
- /** What waits for the client to be idle: `end`. */
62
+ /** What waits for every turn to be done: `end`. */
45
63
  #idle = [];
46
- /** How long the client may sit idle before it closes, or null: closed by `end` alone. */
47
- #closeIdleMs;
48
- #idleTimer;
64
+ /** Whether plain reads asked together go together (`groupReads`). */
65
+ #groupReads;
66
+ /** The reads that will take the next group's turn, while it has not started: what a read asked now joins. */
67
+ #gathering = null;
68
+ /** Closed at the time `end` was given, with turns still asked: none opens a connection again. */
69
+ #cut = false;
70
+ /** Set by `destroy`: every turn after it fails. */
71
+ #destroyed = false;
49
72
  /**
50
73
  * `closeIdleMs`: for what outlives a call, a Durable Object, which queries
51
- * now and then: the client closes once it has been idle that long, and
52
- * the next query connects again.
74
+ * now and then: the connection closes once it has been idle that long,
75
+ * and the next query connects again. `groupReads`: plain reads asked
76
+ * together go together, under one Sync.
53
77
  */
54
78
  constructor(connectionString, options = {}) {
55
79
  if (connectionString.trim().length === 0) throw new Error("Hyperdrive returned an empty connection string");
56
80
  this.#connectionString = connectionString;
57
- this.#closeIdleMs = options.closeIdleMs ?? null;
81
+ this.#closeIdleMs = options.closeIdleMs;
82
+ this.#groupReads = options.groupReads === true;
58
83
  }
59
- query = (async (...args) => {
60
- this.#busy += 1;
61
- clearTimeout(this.#idleTimer);
62
- try {
63
- const client = await this.#connected();
64
- return await new Promise((resolve, reject) => {
65
- this.#turn(() => client.query(...args).then(resolve, reject));
66
- });
67
- } finally {
68
- this.#done();
69
- }
84
+ unsafe = ((...args) => {
85
+ let values = false;
86
+ let answer;
87
+ const [text, parameters = [], options] = args;
88
+ /** Its turn, asked once: the first `then`, `catch`, `finally` or `execute` asks it. */
89
+ const asked = () => answer ??= this.#groupReads && options === void 0 && plainRead(text) ? this.#gather({
90
+ text,
91
+ values: parameters,
92
+ arrays: () => values
93
+ }) : this.#turn(() => {
94
+ const query = this.#connected().unsafe(...args);
95
+ return values ? query.values() : query;
96
+ });
97
+ const statement = {
98
+ values: () => {
99
+ values = true;
100
+ return statement;
101
+ },
102
+ execute: () => {
103
+ asked().catch(() => {});
104
+ return statement;
105
+ },
106
+ then: (resolve, reject) => asked().then(resolve, reject),
107
+ catch: (reject) => asked().catch(reject),
108
+ finally: (done) => asked().finally(done),
109
+ [Symbol.toStringTag]: "Statement"
110
+ };
111
+ return statement;
70
112
  });
71
- /** The client, for a transaction: held from now until `release`. */
72
- async connect() {
73
- this.#busy += 1;
74
- clearTimeout(this.#idleTimer);
75
- let client;
76
- try {
77
- client = await this.#connected();
78
- } catch (error) {
79
- this.#done();
80
- throw error;
113
+ /** A transaction: its turn lasts until it has committed or rolled back. */
114
+ begin = ((...args) => this.#turn(() => this.#connected().begin(...args)));
115
+ /**
116
+ * A read, in the group gathering for the next turn, or in a new one: it
117
+ * starts a task later, so that the reads asked with it join, and once
118
+ * the turns before it are done, which those asked while they ran join.
119
+ */
120
+ #gather(read) {
121
+ let members = this.#gathering;
122
+ if (members === null) {
123
+ const gathered = members = [];
124
+ const asked = new Promise((resolve) => setTimeout(resolve, 0));
125
+ this.#turn(async () => {
126
+ await asked;
127
+ if (this.#gathering === gathered) this.#gathering = null;
128
+ try {
129
+ const client = this.#connected();
130
+ const alone = async (member) => {
131
+ const query = client.unsafe(member.text, member.values);
132
+ member.resolve(await (member.arrays() ? query.values() : query));
133
+ };
134
+ if (gathered.length === 1) return await alone(gathered[0]);
135
+ try {
136
+ const answers = await client.group(gathered.map((member) => ({
137
+ query: member.text,
138
+ parameters: member.values,
139
+ arrays: member.arrays()
140
+ })));
141
+ gathered.forEach((member, i) => member.resolve(answers[i]));
142
+ } catch (error) {
143
+ if (!UNSENT.has(error.code)) throw error;
144
+ for (const member of gathered) await alone(member).catch(member.reject);
145
+ }
146
+ } catch (error) {
147
+ for (const member of gathered) member.reject(error);
148
+ }
149
+ });
150
+ this.#gathering = gathered;
81
151
  }
82
- await new Promise((resolve) => this.#turn(() => {
83
- this.#held = true;
84
- resolve();
152
+ return new Promise((resolve, reject) => members.push({
153
+ ...read,
154
+ resolve,
155
+ reject
85
156
  }));
86
- let released = false;
87
- return {
88
- query: client.query.bind(client),
89
- release: () => {
90
- if (released) return;
91
- released = true;
92
- this.#held = false;
93
- this.#next();
94
- this.#done();
95
- }
96
- };
97
157
  }
98
- /** Close the client once nothing waits on it: what a Worker hands `waitUntil` when the call is done. */
99
- async end() {
100
- clearTimeout(this.#idleTimer);
101
- while (this.#busy > 0) await new Promise((resolve) => this.#idle.push(resolve));
158
+ /**
159
+ * Close the connection once every turn asked is done: what a Worker hands `waitUntil` when the call is done. By
160
+ * `by` (ms since the epoch) at the latest, if given: then at once, what is still asked failing, the statement under
161
+ * way included, and none of it sent again. A use's call past its deadline, whose answer has gone, so lets go of
162
+ * Hyperdrive: what it asked and Hyperdrive had not sent goes with the connection (use.ts, `HELD_PAST_DEADLINE_MS`).
163
+ */
164
+ async end(by) {
165
+ await new Promise((resolve) => setTimeout(resolve, 0));
166
+ let timer;
167
+ const reached = by === void 0 ? null : new Promise((resolve) => timer = setTimeout(() => resolve("cut"), Math.max(0, by - Date.now())));
168
+ while (this.#busy > 0 && !this.#cut) {
169
+ const idle = new Promise((resolve) => this.#idle.push(resolve));
170
+ if (await (reached === null ? idle : Promise.race([idle, reached])) === "cut") this.#cut = true;
171
+ }
172
+ clearTimeout(timer);
102
173
  const client = this.#client;
103
174
  this.#client = null;
104
- if (client === null) return;
105
- await client.then((connected) => connected.end()).catch(() => {});
175
+ await client?.end(this.#cut ? { timeout: 0 } : void 0).catch(() => {});
106
176
  }
107
- /** Run `go` now if nothing holds the client or waits before it, otherwise at its turn. */
108
- #turn(go) {
109
- if (!this.#held && this.#waiting.length === 0) go();
110
- else this.#waiting.push(go);
177
+ /**
178
+ * The connection cut now, what it was asked failing at once, and every
179
+ * turn after refused: for what a host stopped waiting on, a connection
180
+ * gone dead or a connect that never answers (T169), so that whatever
181
+ * still awaits it fails rather than waits for good. Its statement may
182
+ * still run in the database.
183
+ */
184
+ destroy() {
185
+ this.#destroyed = true;
186
+ const client = this.#client;
187
+ this.#client = null;
188
+ client?.end({ timeout: 0 }).catch(() => {});
111
189
  }
112
- /** Give the next turns: queries until one is a transaction, which holds the client. */
113
- #next() {
114
- while (!this.#held && this.#waiting.length > 0) this.#waiting.shift()();
190
+ /** `go` once every turn asked before it is done. Anything but a group's closes the group gathering: it goes after. */
191
+ #turn(go) {
192
+ this.#gathering = null;
193
+ this.#busy += 1;
194
+ const answer = this.#tail.then(go);
195
+ this.#tail = answer.then(() => this.#done(), () => this.#done());
196
+ return answer;
115
197
  }
116
- /** One query or transaction done: once none is left, what waits for the client to be idle goes on. */
198
+ /** One turn done: once none is left, what waits for the pool to be idle goes on. */
117
199
  #done() {
118
200
  this.#busy -= 1;
119
- if (this.#busy > 0) return;
120
- for (const resolve of this.#idle.splice(0)) resolve();
121
- if (this.#closeIdleMs !== null && this.#client !== null) this.#idleTimer = setTimeout(() => void this.end(), this.#closeIdleMs);
201
+ if (this.#busy === 0) for (const resolve of this.#idle.splice(0)) resolve();
122
202
  }
123
- /** The call's client, connecting it the first time. One that fails is dropped: the next query connects again. */
203
+ /** The call's client, made the first time. postgres.js opens its connection again when one is lost. */
124
204
  #connected() {
125
- if (this.#client !== null) return this.#client;
126
- const client = new pg.Client(postgresConnection(this.#connectionString));
127
- const connecting = client.connect().then(() => client);
128
- const drop = () => {
129
- if (this.#client === connecting) this.#client = null;
130
- };
131
- client.on("error", drop);
132
- client.on("end", drop);
133
- connecting.catch(drop);
134
- this.#client = connecting;
135
- return connecting;
205
+ if (this.#destroyed) throw new Error("this connection was cut: its call stopped waiting on it");
206
+ if (this.#cut) throw new Error("the call's connection was closed at the time it was given (`end`): nothing more is sent");
207
+ this.#client ??= textTypes(postgresClient(this.#connectionString, {
208
+ max: 1,
209
+ idle_timeout: this.#closeIdleMs === void 0 ? void 0 : this.#closeIdleMs / 1e3,
210
+ max_lifetime: null
211
+ }));
212
+ return this.#client;
136
213
  }
137
214
  };
138
215
  //#endregion