@crvouga/mockingbird-service-postgres 3.6.0 → 3.7.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.
package/dist/wire/cli.js CHANGED
@@ -744,9 +744,6 @@ function ownedTransport(policy) {
744
744
 
745
745
  // ../../adapters/node/dist/cli.js
746
746
  import { readFile as readFile5 } from "node:fs/promises";
747
- import { createRequire as createRequire3 } from "node:module";
748
- import { resolve as resolve3 } from "node:path";
749
- import { pathToFileURL } from "node:url";
750
747
  import { parseArgs } from "node:util";
751
748
 
752
749
  // ../../adapters/node/dist/fleet.js
@@ -760,6 +757,31 @@ import { createHash as createHash3, randomBytes, randomUUID as randomUUID3 } fro
760
757
 
761
758
  // ../../adapters/node/dist/fleet-archive.js
762
759
  import { createHash } from "node:crypto";
760
+ function validateCompatibilityTags(tags) {
761
+ if (!tags || typeof tags !== "object" || Array.isArray(tags))
762
+ throw new Error("invalid archive compatibility tags");
763
+ const entries = Object.entries(tags);
764
+ if (entries.length > 32 || entries.some(([key, value]) => !/^[A-Za-z0-9_.-]{1,64}$/.test(key) || typeof value !== "string" || value.length < 1 || value.length > 256 || [...value].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)))
765
+ throw new Error("invalid archive compatibility tags");
766
+ }
767
+ function assertCompatibilityTags(tags, policy) {
768
+ if (tags !== void 0)
769
+ validateCompatibilityTags(tags);
770
+ if (!policy)
771
+ return;
772
+ validateCompatibilityTags(policy.tags);
773
+ if (policy.missing !== void 0 && !["allow", "reject"].includes(policy.missing))
774
+ throw new Error("invalid missing compatibility policy");
775
+ if (tags === void 0 && policy.missing === "allow")
776
+ return;
777
+ if (canonical(tags) !== canonical(policy.tags))
778
+ throw new Error("application archive compatibility mismatch");
779
+ }
780
+ function assertArchiveCompatibility(input, policy) {
781
+ const archive = validateArchive(input);
782
+ assertCompatibilityTags(archive.compatibility, policy);
783
+ return archive;
784
+ }
763
785
  var canonical = (value) => {
764
786
  if (Array.isArray(value))
765
787
  return `[${value.map(canonical).join(",")}]`;
@@ -779,6 +801,8 @@ function validateArchive(value) {
779
801
  const { sha256: sha2563, ...content } = doc;
780
802
  if (doc.format !== "mockingbird.fleet/v1" || typeof doc.sourceId !== "string" || typeof doc.createdAt !== "string" || !doc.namespaces || typeof doc.namespaces !== "object" || Array.isArray(doc.namespaces) || sha2563 !== digest(content))
781
803
  throw new Error("unsupported or corrupt fleet archive");
804
+ if (doc.compatibility !== void 0)
805
+ validateCompatibilityTags(doc.compatibility);
782
806
  for (const [namespace, entry] of Object.entries(doc.namespaces)) {
783
807
  if (!/^[A-Za-z0-9_.-]{1,64}$/.test(namespace) || !entry || !Number.isFinite(entry.clock?.now) || typeof entry.clock?.frozen !== "boolean" || !entry.services || !Object.keys(entry.services).length)
784
808
  throw new Error("invalid archive namespace");
@@ -794,6 +818,7 @@ function inspectArchive(input) {
794
818
  format: archive.format,
795
819
  createdAt: archive.createdAt,
796
820
  sha256: archive.sha256,
821
+ ...archive.compatibility ? { compatibility: archive.compatibility } : {},
797
822
  namespaces: Object.fromEntries(Object.entries(archive.namespaces).map(([name2, ns]) => [
798
823
  name2,
799
824
  {
@@ -1436,11 +1461,28 @@ var ingressSupport = {
1436
1461
  streaming: true,
1437
1462
  signing: "vendor request signing is not used; webhook signatures remain payload based"
1438
1463
  },
1464
+ cognito: {
1465
+ publicOrigin: true,
1466
+ pathPrefix: true,
1467
+ namespaces: "path-or-header",
1468
+ streaming: true,
1469
+ signing: "JWT issuer and JWKS use the configured public namespace; SigV4 verification is not modelled"
1470
+ },
1471
+ medplum: {
1472
+ publicOrigin: true,
1473
+ pathPrefix: true,
1474
+ namespaces: "path-or-header",
1475
+ streaming: true,
1476
+ signing: "FHIR, OAuth and storage URLs use the configured public namespace"
1477
+ },
1439
1478
  other: {
1440
1479
  publicOrigin: false,
1441
1480
  reason: "host/path-sensitive signing and hosted URL rewriting are not certified; use a direct endpoint"
1442
1481
  }
1443
1482
  };
1483
+ function supportsPublicIngress(service) {
1484
+ return service === "stripe" || service === "cognito" || service === "medplum";
1485
+ }
1444
1486
  function advertisedHttpBase(entry) {
1445
1487
  if (entry.publicPath !== void 0 && !entry.publicOrigin)
1446
1488
  throw new Error("publicPath requires publicOrigin");
@@ -1979,7 +2021,7 @@ data: ${JSON.stringify(data)}
1979
2021
  {
1980
2022
  protocol: c.protocol,
1981
2023
  coverage: c.coverage,
1982
- ingress: c.targetName === "stripe" ? ingressSupport.stripe : ingressSupport.other,
2024
+ ingress: supportsPublicIngress(c.targetName ?? "") ? ingressSupport[c.targetName] : ingressSupport.other,
1983
2025
  target: c.targetName,
1984
2026
  outboundPolicy: c.outboundPolicy ?? "unsupported",
1985
2027
  version: 1,
@@ -3063,11 +3105,12 @@ data: ${JSON.stringify(data)}
3063
3105
  format: "mockingbird.fleet/v1",
3064
3106
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3065
3107
  sourceId: this.ctx.id,
3108
+ ...this.ctx.options.archiveCompatibility ? { compatibility: structuredClone(this.ctx.options.archiveCompatibility.tags) } : {},
3066
3109
  namespaces: contents
3067
3110
  });
3068
3111
  }
3069
3112
  async restoreArchive(input, selectedNamespace) {
3070
- const archive = validateArchive(input);
3113
+ const archive = assertArchiveCompatibility(input, this.ctx.options.archiveCompatibility);
3071
3114
  const entries = Object.entries(archive.namespaces).filter(([ns]) => selectedNamespace === void 0 || ns === selectedNamespace);
3072
3115
  if (!entries.length)
3073
3116
  throw new Error("selected namespace absent from archive");
@@ -3651,7 +3694,7 @@ async function preflightFleet(config, options2) {
3651
3694
  if (entry.target !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(entry.target))
3652
3695
  throw new Error("target must name a supported service suffix");
3653
3696
  const service = entry.target ?? name2;
3654
- if (advertisedHttpBase(entry) && service !== "stripe")
3697
+ if (advertisedHttpBase(entry) && !supportsPublicIngress(service))
3655
3698
  throw new Error(`public ingress unsupported for ${service}; use a direct endpoint to preserve signed targets`);
3656
3699
  const target = await options2.load(service);
3657
3700
  const protocol = "protocol" in target ? target.protocol : "http";
@@ -3702,7 +3745,7 @@ async function preflightFleet(config, options2) {
3702
3745
  break;
3703
3746
  }
3704
3747
  }
3705
- targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.6.0" });
3748
+ targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.7.0" });
3706
3749
  } catch (error) {
3707
3750
  throw new Error(`service ${name2}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
3708
3751
  }
@@ -3746,6 +3789,11 @@ async function preflightFleet(config, options2) {
3746
3789
  return ordered;
3747
3790
  }
3748
3791
  function validateFleetPolicies(options2) {
3792
+ if (options2.archiveCompatibility) {
3793
+ validateCompatibilityTags(options2.archiveCompatibility.tags);
3794
+ if (options2.archiveCompatibility.missing !== void 0 && !["allow", "reject"].includes(options2.archiveCompatibility.missing))
3795
+ throw new Error("archiveCompatibility.missing must be allow or reject");
3796
+ }
3749
3797
  if (options2.journal && !options2.repository)
3750
3798
  throw new Error("durable operation journal requires an archive repository");
3751
3799
  if (options2.cors) {
@@ -4738,10 +4786,44 @@ async function startFleet(config, options2) {
4738
4786
  }
4739
4787
  }
4740
4788
 
4741
- // ../../adapters/node/dist/fleet-tools.js
4742
- import { readFile as readFile4 } from "node:fs/promises";
4789
+ // ../../adapters/node/dist/fleet-loader.js
4743
4790
  import { createRequire as createRequire2 } from "node:module";
4744
4791
  import { resolve as resolve2 } from "node:path";
4792
+ import { pathToFileURL } from "node:url";
4793
+ var suffix = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
4794
+ function createInstalledServiceLoader(options2) {
4795
+ if (!options2.projectRoot)
4796
+ throw new Error("consumer projectRoot required");
4797
+ const allowed = new Set(options2.services);
4798
+ for (const name2 of allowed)
4799
+ if (!suffix.test(name2))
4800
+ throw new Error("invalid service suffix");
4801
+ const require2 = createRequire2(resolve2(options2.projectRoot, "package.json"));
4802
+ const targets = new Map((options2.targets ?? []).map((target) => [target.name, target]));
4803
+ return async (name2) => {
4804
+ if (!suffix.test(name2) || !allowed.has(name2))
4805
+ throw new Error("service is not declared in loader allowlist");
4806
+ const own2 = targets.get(name2);
4807
+ if (own2)
4808
+ return own2;
4809
+ const specifier = `@crvouga/mockingbird-service-${name2}/server`;
4810
+ let location;
4811
+ try {
4812
+ location = require2.resolve(specifier);
4813
+ } catch {
4814
+ throw new Error(`cannot load service "${name2}": install @crvouga/mockingbird-service-${name2} in the consumer project; its /server export is required`);
4815
+ }
4816
+ const mod = await import(pathToFileURL(location).href);
4817
+ if (!mod.serveTarget || mod.serveTarget.name !== name2 || ("protocol" in mod.serveTarget ? typeof mod.serveTarget.start !== "function" : typeof mod.serveTarget.create !== "function"))
4818
+ throw new Error(`${specifier} exports no matching serveTarget`);
4819
+ return mod.serveTarget;
4820
+ };
4821
+ }
4822
+
4823
+ // ../../adapters/node/dist/fleet-tools.js
4824
+ import { readFile as readFile4 } from "node:fs/promises";
4825
+ import { createRequire as createRequire3 } from "node:module";
4826
+ import { resolve as resolve3 } from "node:path";
4745
4827
 
4746
4828
  // ../../adapters/node/dist/fleet-client.js
4747
4829
  import { randomUUID as randomUUID5 } from "node:crypto";
@@ -4755,6 +4837,14 @@ var FleetClientError = class extends Error {
4755
4837
  this.details = details;
4756
4838
  }
4757
4839
  };
4840
+ var FleetClientResponseError = class extends FleetClientError {
4841
+ code;
4842
+ constructor(code, status, origin) {
4843
+ super(status, { code, body: "omitted", ...origin ? { origin } : {} });
4844
+ this.code = code;
4845
+ this.name = "FleetClientResponseError";
4846
+ }
4847
+ };
4758
4848
  var FleetClient = class {
4759
4849
  base;
4760
4850
  options;
@@ -4767,7 +4857,14 @@ var FleetClient = class {
4767
4857
  if (url.username || url.password)
4768
4858
  throw new Error("fleet client URL must not contain credentials");
4769
4859
  url.searchParams.set("namespace", options2.namespace ?? this.options.namespace ?? "default");
4860
+ const limit = options2.maxResponseBytes ?? this.options.maxResponseBytes ?? 64 * 1024 * 1024;
4861
+ if (!Number.isSafeInteger(limit) || limit < 1)
4862
+ throw new Error("invalid response byte limit");
4863
+ const deadline = AbortSignal.timeout(this.options.timeoutMs ?? 3e4);
4864
+ const signal = options2.signal ? AbortSignal.any([options2.signal, deadline]) : deadline;
4865
+ signal.throwIfAborted();
4770
4866
  const response = await (this.options.fetch ?? fetch)(url, {
4867
+ redirect: "manual",
4771
4868
  method: options2.method ?? (options2.body === void 0 ? "GET" : "POST"),
4772
4869
  headers: {
4773
4870
  "content-type": "application/json",
@@ -4775,11 +4872,71 @@ var FleetClient = class {
4775
4872
  ...options2.idempotencyKey ? { "idempotency-key": options2.idempotencyKey } : {}
4776
4873
  },
4777
4874
  ...options2.body !== void 0 ? { body: JSON.stringify(options2.body) } : {},
4778
- signal: options2.signal ?? AbortSignal.timeout(this.options.timeoutMs ?? 3e4)
4875
+ signal
4779
4876
  });
4780
- const data = await response.json();
4781
- if (!response.ok)
4782
- throw new FleetClientError(response.status, data);
4877
+ if (response.status >= 300 && response.status < 400) {
4878
+ await response.body?.cancel();
4879
+ throw new FleetClientResponseError("redirect", response.status, url.origin);
4880
+ }
4881
+ if (Number(response.headers.get("content-length")) > limit) {
4882
+ await response.body?.cancel();
4883
+ throw new FleetClientResponseError("response_too_large", response.status);
4884
+ }
4885
+ const reader = response.body?.getReader();
4886
+ const chunks = [];
4887
+ let size = 0;
4888
+ const abort = () => {
4889
+ void reader?.cancel(signal.reason).catch(() => {
4890
+ });
4891
+ };
4892
+ signal.addEventListener("abort", abort, { once: true });
4893
+ try {
4894
+ if (reader)
4895
+ while (true) {
4896
+ signal.throwIfAborted();
4897
+ const { done, value } = await reader.read();
4898
+ signal.throwIfAborted();
4899
+ if (done)
4900
+ break;
4901
+ size += value.byteLength;
4902
+ if (size > limit) {
4903
+ await reader.cancel();
4904
+ throw new FleetClientResponseError("response_too_large", response.status);
4905
+ }
4906
+ chunks.push(value);
4907
+ }
4908
+ } finally {
4909
+ signal.removeEventListener("abort", abort);
4910
+ if (signal.aborted)
4911
+ await reader?.cancel(signal.reason).catch(() => {
4912
+ });
4913
+ reader?.releaseLock();
4914
+ }
4915
+ const bytes = new Uint8Array(size);
4916
+ let offset = 0;
4917
+ for (const chunk of chunks) {
4918
+ bytes.set(chunk, offset);
4919
+ offset += chunk.byteLength;
4920
+ }
4921
+ const text = new TextDecoder().decode(bytes);
4922
+ let data;
4923
+ try {
4924
+ data = text.length ? JSON.parse(text) : void 0;
4925
+ } catch {
4926
+ if (response.ok)
4927
+ throw new FleetClientResponseError("invalid_json", response.status);
4928
+ }
4929
+ if (!response.ok) {
4930
+ const error = data && typeof data === "object" ? data.error : void 0;
4931
+ const detail = { body: "omitted" };
4932
+ if (error && typeof error === "object")
4933
+ for (const key of ["type", "code"]) {
4934
+ const value = error[key];
4935
+ if (typeof value === "string" && /^[A-Za-z0-9_.-]{1,128}$/.test(value))
4936
+ detail[key] = value;
4937
+ }
4938
+ throw new FleetClientError(response.status, detail);
4939
+ }
4783
4940
  return data;
4784
4941
  }
4785
4942
  discover() {
@@ -4845,17 +5002,52 @@ function renderConnections(manifest, privateManifest, namespace, mapping) {
4845
5002
  const child = manifest.services[entry.service], secret = privateManifest.services[entry.service];
4846
5003
  if (!child || !secret)
4847
5004
  throw new Error(`missing service mapping ${entry.service}`);
5005
+ let endpoint;
4848
5006
  if (child.protocol === "http") {
4849
5007
  const template = child.namespaces.path;
4850
5008
  if (typeof template !== "string")
4851
5009
  throw new Error(`missing HTTP namespace mapping ${entry.service}`);
4852
- result[variable] = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
5010
+ endpoint = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
4853
5011
  } else {
4854
- const endpoint = secret.namespaces?.[namespace];
4855
- if (!endpoint)
5012
+ const selected = secret.namespaces?.[namespace];
5013
+ if (!selected)
4856
5014
  throw new Error(`missing namespace mapping ${namespace}/${entry.service}`);
4857
- result[variable] = endpoint;
5015
+ endpoint = selected;
4858
5016
  }
5017
+ const url = new URL(endpoint);
5018
+ const field = entry.field ?? "url";
5019
+ let value;
5020
+ switch (field) {
5021
+ case "url":
5022
+ value = endpoint;
5023
+ break;
5024
+ case "hostname":
5025
+ value = url.hostname.replace(/^\[|\]$/g, "");
5026
+ break;
5027
+ case "port":
5028
+ value = url.port;
5029
+ break;
5030
+ case "username":
5031
+ value = decodeURIComponent(url.username);
5032
+ break;
5033
+ case "password":
5034
+ value = decodeURIComponent(url.password);
5035
+ break;
5036
+ case "pathname":
5037
+ value = decodeURIComponent(url.pathname);
5038
+ break;
5039
+ case "database":
5040
+ value = decodeURIComponent(url.pathname.replace(/^\//, ""));
5041
+ break;
5042
+ default:
5043
+ throw new Error("unsupported connection field");
5044
+ }
5045
+ if (!value) {
5046
+ if (typeof entry.fallback !== "string")
5047
+ throw new Error(`missing connection component ${field}`);
5048
+ value = entry.fallback;
5049
+ }
5050
+ result[variable] = value;
4859
5051
  }
4860
5052
  return result;
4861
5053
  }
@@ -4879,7 +5071,7 @@ async function doctorFleet(config, options2, probes = []) {
4879
5071
  const plan = [];
4880
5072
  try {
4881
5073
  const targets = await preflightFleet(config, options2);
4882
- const require2 = createRequire2(resolve2(process.cwd(), "package.json"));
5074
+ const require2 = createRequire3(resolve3(process.cwd(), "package.json"));
4883
5075
  for (const [service, target] of targets) {
4884
5076
  let version = "development";
4885
5077
  try {
@@ -4934,7 +5126,7 @@ async function doctorFleet(config, options2, probes = []) {
4934
5126
  };
4935
5127
  }
4936
5128
  async function rehearseFleet(config, options2, input, probes = [], timeoutMs = 3e4) {
4937
- const archive = validateArchive(input);
5129
+ const archive = assertArchiveCompatibility(input, options2.archiveCompatibility);
4938
5130
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
4939
5131
  const isolated = {
4940
5132
  ...config,
@@ -4946,7 +5138,7 @@ async function rehearseFleet(config, options2, input, probes = [], timeoutMs = 3
4946
5138
  };
4947
5139
  let fleet;
4948
5140
  try {
4949
- fleet = await startFleet(isolated, { load: options2.load });
5141
+ fleet = await startFleet(isolated, options2);
4950
5142
  const client = new FleetClient(fleet.manifest.adminBase, {
4951
5143
  ...config.adminKey ? { adminKey: config.adminKey } : {}
4952
5144
  });
@@ -5321,26 +5513,7 @@ var resolveServeControls = async (values, env = process.env, base) => {
5321
5513
  normalizeBootControls(document, "adminControls");
5322
5514
  return document;
5323
5515
  };
5324
- var loadTarget = async (name2, own2) => {
5325
- if (name2 === own2.name)
5326
- return own2;
5327
- const specifier = `@crvouga/mockingbird-service-${name2}/server`;
5328
- try {
5329
- let mod;
5330
- try {
5331
- mod = await import(specifier);
5332
- } catch {
5333
- const fromProject = createRequire3(resolve3(process.cwd(), "package.json"));
5334
- mod = await import(pathToFileURL(fromProject.resolve(specifier)).href);
5335
- }
5336
- if (!mod.serveTarget)
5337
- throw new Error(`${specifier} exports no serveTarget`);
5338
- return mod.serveTarget;
5339
- } catch (error) {
5340
- const reason = error instanceof Error ? error.message : String(error);
5341
- throw new Error(`cannot load service "${name2}": ${reason}. Install @crvouga/mockingbird-service-${name2}.`);
5342
- }
5343
- };
5516
+ var loadTarget = (name2, own2) => createInstalledServiceLoader({ projectRoot: process.cwd(), services: [name2], targets: [own2] })(name2);
5344
5517
  var start = async (target, values, config) => {
5345
5518
  const adminPrefix = resolveAdminPrefix(config.adminPrefix);
5346
5519
  const runtime = await target.create(values, {
@@ -5786,9 +5959,9 @@ function stemEnglish(input) {
5786
5959
  return false;
5787
5960
  })();
5788
5961
  if (!step1bDone) {
5789
- for (const suffix of ["ingly", "edly", "ing", "ed"]) {
5790
- if (w.endsWith(suffix)) {
5791
- const stem = w.slice(0, -suffix.length);
5962
+ for (const suffix2 of ["ingly", "edly", "ing", "ed"]) {
5963
+ if (w.endsWith(suffix2)) {
5964
+ const stem = w.slice(0, -suffix2.length);
5792
5965
  if ([...stem].some(isVowel)) {
5793
5966
  w = stem;
5794
5967
  if (w.endsWith("at") || w.endsWith("bl") || w.endsWith("iz")) w += "e";
@@ -5826,9 +5999,9 @@ function stemEnglish(input) {
5826
5999
  ["alli", "al"],
5827
6000
  ["bli", "ble"]
5828
6001
  ];
5829
- for (const [suffix, repl] of step2) {
5830
- if (w.endsWith(suffix)) {
5831
- if (w.length - suffix.length >= r1) w = w.slice(0, -suffix.length) + repl;
6002
+ for (const [suffix2, repl] of step2) {
6003
+ if (w.endsWith(suffix2)) {
6004
+ if (w.length - suffix2.length >= r1) w = w.slice(0, -suffix2.length) + repl;
5832
6005
  break;
5833
6006
  }
5834
6007
  }
@@ -5847,9 +6020,9 @@ function stemEnglish(input) {
5847
6020
  ["ness", ""],
5848
6021
  ["ful", ""]
5849
6022
  ];
5850
- for (const [suffix, repl] of step3) {
5851
- if (w.endsWith(suffix)) {
5852
- if (w.length - suffix.length >= r1) w = w.slice(0, -suffix.length) + repl;
6023
+ for (const [suffix2, repl] of step3) {
6024
+ if (w.endsWith(suffix2)) {
6025
+ if (w.length - suffix2.length >= r1) w = w.slice(0, -suffix2.length) + repl;
5853
6026
  break;
5854
6027
  }
5855
6028
  }
@@ -5875,9 +6048,9 @@ function stemEnglish(input) {
5875
6048
  "er",
5876
6049
  "ic"
5877
6050
  ];
5878
- for (const suffix of step4) {
5879
- if (w.endsWith(suffix)) {
5880
- if (w.length - suffix.length >= r2) w = w.slice(0, -suffix.length);
6051
+ for (const suffix2 of step4) {
6052
+ if (w.endsWith(suffix2)) {
6053
+ if (w.length - suffix2.length >= r2) w = w.slice(0, -suffix2.length);
5881
6054
  break;
5882
6055
  }
5883
6056
  }
@@ -8085,6 +8258,12 @@ var invalidName = () => {
8085
8258
  throw pgError("syntax", "invalid name syntax", "42602");
8086
8259
  };
8087
8260
  function parseNamespaceInput(text) {
8261
+ const parsed = parseRelationInput(text);
8262
+ if ("oid" in parsed) return parsed;
8263
+ if (parsed.parts.length !== 1) invalidName();
8264
+ return { name: parsed.parts[0] };
8265
+ }
8266
+ function parseRelationInput(text) {
8088
8267
  if (text === "-") return { oid: 0 };
8089
8268
  if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
8090
8269
  const names = [];
@@ -8120,8 +8299,8 @@ function parseNamespaceInput(text) {
8120
8299
  skipSpace();
8121
8300
  if (at === text.length) invalidName();
8122
8301
  }
8123
- if (names.length !== 1) invalidName();
8124
- return { name: names[0] };
8302
+ if (names.length === 0 || names.length > 3) invalidName();
8303
+ return { parts: names };
8125
8304
  }
8126
8305
  function namespaceText(oid, name2) {
8127
8306
  if (oid === 0) return "-";
@@ -8194,6 +8373,7 @@ var TYPE_ALIASES = {
8194
8373
  regtype: "regtype",
8195
8374
  regproc: "regproc",
8196
8375
  regnamespace: "regnamespace",
8376
+ xid: "xid",
8197
8377
  oid: "oid",
8198
8378
  void: "void",
8199
8379
  record: "record",
@@ -8270,6 +8450,7 @@ var TYPE_OIDS = {
8270
8450
  regproc: 24,
8271
8451
  text: 25,
8272
8452
  oid: 26,
8453
+ xid: 28,
8273
8454
  json: 114,
8274
8455
  float4: 700,
8275
8456
  float8: 701,
@@ -8589,6 +8770,7 @@ function recordText(rec, ctx) {
8589
8770
  return `(${parts.join(",")})`;
8590
8771
  }
8591
8772
  function datumText(t, v, ctx) {
8773
+ if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
8592
8774
  if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
8593
8775
  if (v === null) throw pgError("internal", "datumText called with null");
8594
8776
  if (isArrayType(t)) return arrayText(v, ctx);
@@ -8599,6 +8781,7 @@ function datumText(t, v, ctx) {
8599
8781
  case "int2":
8600
8782
  case "int4":
8601
8783
  case "oid":
8784
+ case "xid":
8602
8785
  return String(v);
8603
8786
  case "int8":
8604
8787
  return String(v);
@@ -8663,6 +8846,12 @@ function datumText(t, v, ctx) {
8663
8846
  }
8664
8847
  var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
8665
8848
  function datumFromText(t, text, ctx) {
8849
+ if (t === "regclass") {
8850
+ const parsed = parseRelationInput(text);
8851
+ if ("oid" in parsed) return parsed.oid;
8852
+ if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
8853
+ return ctx.relationOid(parsed.parts);
8854
+ }
8666
8855
  if (t === "regnamespace") {
8667
8856
  const parsed = parseNamespaceInput(text);
8668
8857
  if ("oid" in parsed) return parsed.oid;
@@ -8684,6 +8873,7 @@ function datumFromText(t, text, ctx) {
8684
8873
  case "int8":
8685
8874
  return parseIntegerText(text, t);
8686
8875
  case "oid":
8876
+ case "xid":
8687
8877
  return parseOidText(text);
8688
8878
  case "float4":
8689
8879
  return Math.fround(parseFloatText(text, "float4"));
@@ -8840,6 +9030,8 @@ var TableData = class _TableData {
8840
9030
  schema;
8841
9031
  columns;
8842
9032
  rows;
9033
+ rowXmins = /* @__PURE__ */ new WeakMap();
9034
+ slabXmins = null;
8843
9035
  /** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
8844
9036
  slab = null;
8845
9037
  constraints;
@@ -8882,6 +9074,11 @@ var TableData = class _TableData {
8882
9074
  materializeSlab() {
8883
9075
  if (!this.slab) return;
8884
9076
  this.rows = this.slab.materialize();
9077
+ if (this.slabXmins)
9078
+ this.rows.forEach((row, index) => {
9079
+ this.rowXmins.set(row, this.slabXmins[index] ?? 2);
9080
+ });
9081
+ this.slabXmins = null;
8885
9082
  this.slab = null;
8886
9083
  this.indexStores = null;
8887
9084
  }
@@ -8915,6 +9112,10 @@ var TableData = class _TableData {
8915
9112
  } else {
8916
9113
  t.rows = this.rows.map((r) => r.slice());
8917
9114
  }
9115
+ t.rows.forEach((row, index) => {
9116
+ const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
9117
+ if (xmin !== void 0) t.rowXmins.set(row, xmin);
9118
+ });
8918
9119
  t.unlogged = this.unlogged;
8919
9120
  t.constraints = this.constraints.map((c) => ({ ...c }));
8920
9121
  t.triggers = this.triggers.map((tr) => ({ ...tr }));
@@ -9000,6 +9201,14 @@ var DatabaseState = class _DatabaseState {
9000
9201
  clock;
9001
9202
  changes = 0;
9002
9203
  oidCounter = 16384;
9204
+ /** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
9205
+ xidCounter = 3;
9206
+ transactionXid = null;
9207
+ allocateXid() {
9208
+ if (this.xidCounter > 4294967295)
9209
+ throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
9210
+ return this.xidCounter++;
9211
+ }
9003
9212
  inTransaction = false;
9004
9213
  /** Transaction-only events: included in rollback clones, never in exported snapshots. */
9005
9214
  pendingTriggers = [];
@@ -9213,6 +9422,8 @@ var DatabaseState = class _DatabaseState {
9213
9422
  s.sequenceCurrval = new Map(this.sequenceCurrval);
9214
9423
  s.tableStats = new Map(this.tableStats);
9215
9424
  s.oidCounter = this.oidCounter;
9425
+ s.xidCounter = this.xidCounter;
9426
+ s.transactionXid = this.transactionXid;
9216
9427
  for (const [name2, overloads] of this.systemFunctions) s.systemFunctions.set(name2, overloads.slice());
9217
9428
  return s;
9218
9429
  }
@@ -9232,6 +9443,8 @@ var DatabaseState = class _DatabaseState {
9232
9443
  s.sequenceCurrval = new Map(this.sequenceCurrval);
9233
9444
  s.tableStats = new Map(this.tableStats);
9234
9445
  s.oidCounter = this.oidCounter;
9446
+ s.xidCounter = this.xidCounter;
9447
+ s.transactionXid = this.transactionXid;
9235
9448
  for (const [name2, overloads] of this.systemFunctions) s.systemFunctions.set(name2, overloads.slice());
9236
9449
  return s;
9237
9450
  }
@@ -9307,6 +9520,8 @@ var DatabaseState = class _DatabaseState {
9307
9520
  this.sequenceCurrval = other.sequenceCurrval;
9308
9521
  this.tableStats = other.tableStats;
9309
9522
  this.oidCounter = other.oidCounter;
9523
+ this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
9524
+ this.transactionXid = other.transactionXid;
9310
9525
  }
9311
9526
  /** @internal Snapshot codec access to the oid allocator. */
9312
9527
  snapshotOidCounter() {
@@ -9386,6 +9601,11 @@ function validateZone(zone) {
9386
9601
  // src/expressions/context.ts
9387
9602
  var EngineCtx = class {
9388
9603
  state;
9604
+ writeXid = null;
9605
+ rowVersionXid() {
9606
+ if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
9607
+ return this.writeXid ??= this.state.allocateXid();
9608
+ }
9389
9609
  /** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
9390
9610
  txNow;
9391
9611
  /** statement timestamp */
@@ -9400,6 +9620,23 @@ var EngineCtx = class {
9400
9620
  timezone() {
9401
9621
  return this.state.getSetting("timezone") ?? "UTC";
9402
9622
  }
9623
+ relationOid(parts) {
9624
+ const target = this.state.resolveRelationSchema(parts);
9625
+ const schema = target ? this.state.schemas.get(target.schema) : void 0;
9626
+ const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
9627
+ if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
9628
+ return relation.oid;
9629
+ }
9630
+ relationName(oid) {
9631
+ for (const schema of this.state.schemas.values()) {
9632
+ for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
9633
+ if (relation.oid !== oid) continue;
9634
+ const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
9635
+ return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
9636
+ }
9637
+ }
9638
+ return null;
9639
+ }
9403
9640
  namespaceOid(name2) {
9404
9641
  const oid = builtinNamespaceOid(name2) ?? this.state.schemas.get(name2)?.oid;
9405
9642
  if (oid === void 0) throw pgError("undefined_object", `schema "${name2}" does not exist`, "3F000");
@@ -9700,7 +9937,7 @@ function castTo(env, value, target, opts = {}) {
9700
9937
  return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
9701
9938
  }
9702
9939
  if (from === "oid" && target === "regnamespace") return tv(target, v);
9703
- if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
9940
+ if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
9704
9941
  return tv(target, target === "int8" ? BigInt(v) : v);
9705
9942
  }
9706
9943
  if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
@@ -10401,6 +10638,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
10401
10638
  case "int2":
10402
10639
  case "int4":
10403
10640
  case "oid":
10641
+ case "regclass":
10642
+ case "xid":
10404
10643
  case "regnamespace":
10405
10644
  case "date":
10406
10645
  return expectNumber(a, t) - expectNumber(b, t);
@@ -10520,6 +10759,8 @@ function datumKey(t, v) {
10520
10759
  case "int2":
10521
10760
  case "int4":
10522
10761
  case "oid":
10762
+ case "regclass":
10763
+ case "xid":
10523
10764
  case "date":
10524
10765
  return `i${v}`;
10525
10766
  case "float4":
@@ -11403,8 +11644,8 @@ function toCharTimestamp(ctx, localMicros, fmt, tzOffsetSec) {
11403
11644
  else if (tryPat("TH") || tryPat("th")) {
11404
11645
  const prev = /(\d+)$/.exec(out);
11405
11646
  const n = prev ? Number.parseInt(prev[1], 10) : 0;
11406
- const suffix = ordinalSuffix(n);
11407
- out += rest.startsWith("TH") ? suffix.toUpperCase() : suffix;
11647
+ const suffix2 = ordinalSuffix(n);
11648
+ out += rest.startsWith("TH") ? suffix2.toUpperCase() : suffix2;
11408
11649
  } else {
11409
11650
  out += fmt[i];
11410
11651
  i++;
@@ -12623,7 +12864,7 @@ function claimConstraintIndexName(schema, constraint, explicit, reserved = /* @_
12623
12864
  if (used(constraint.name)) {
12624
12865
  if (explicit) throw pgError("duplicate_table", `relation "${constraint.name}" already exists`, "42P07");
12625
12866
  const base = constraint.name;
12626
- for (let suffix = 1; used(constraint.name); suffix++) constraint.name = `${base}${suffix}`;
12867
+ for (let suffix2 = 1; used(constraint.name); suffix2++) constraint.name = `${base}${suffix2}`;
12627
12868
  }
12628
12869
  reserved.add(constraint.name);
12629
12870
  }
@@ -13428,7 +13669,7 @@ function setDatabaseCatalogContext(state, context) {
13428
13669
  var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
13429
13670
  function findSequenceForCall(ctx, name2) {
13430
13671
  const parts = parseQualifiedName(name2);
13431
- const seq = ctx.state.findSequence(parts);
13672
+ const seq = /^\d+$/.test(name2) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name2)) : ctx.state.findSequence(parts);
13432
13673
  if (!seq) {
13433
13674
  throw pgError("undefined_table", `relation "${name2}" does not exist`, "42P01");
13434
13675
  }
@@ -13652,14 +13893,16 @@ function getMiscFunctions() {
13652
13893
  "pg_get_serial_sequence",
13653
13894
  strict("text", (ctx, args2) => {
13654
13895
  const tableName2 = argText(ctx, args2[0]);
13655
- const column = argText(ctx, args2[1]).toLowerCase();
13896
+ const column = argText(ctx, args2[1]);
13656
13897
  const table = ctx.state.findTable(parseQualifiedName(tableName2));
13657
13898
  if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
13658
13899
  const col = table.columns.find((c) => c.name === column);
13659
13900
  if (!col)
13660
13901
  throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
13661
- if (!col.identity) return tv("text", null);
13662
- return tv("text", col.identity.sequence.split(".").map(quoteIdent).join("."));
13902
+ const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
13903
+ (candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
13904
+ );
13905
+ return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
13663
13906
  })
13664
13907
  );
13665
13908
  m.set("format_type", (ctx, args2) => {
@@ -18603,7 +18846,7 @@ var RowScope = class {
18603
18846
  let count2 = 0;
18604
18847
  for (let i = 0; i < this.columns.length; i++) {
18605
18848
  const c = this.columns[i];
18606
- if (c.name === name3 && !c.hidden) {
18849
+ if (c.name === name3 && (!c.hidden || c.system)) {
18607
18850
  count2++;
18608
18851
  if (count2 > 1) {
18609
18852
  throw pgError("ambiguous_column", `column reference "${name3}" is ambiguous`);
@@ -18641,7 +18884,7 @@ var RowScope = class {
18641
18884
  const names = [];
18642
18885
  for (let i = 0; i < this.columns.length; i++) {
18643
18886
  const c = this.columns[i];
18644
- if (c.table === rangeVar) {
18887
+ if (c.table === rangeVar && !c.system) {
18645
18888
  types.push(c.type);
18646
18889
  values.push(this.row[i] ?? null);
18647
18890
  names.push(c.name);
@@ -19084,7 +19327,7 @@ function tryIndexedFromItem(env, item, where) {
19084
19327
  if (!table) return null;
19085
19328
  const alias = item.alias ?? item.name[item.name.length - 1];
19086
19329
  table.materializeSlab();
19087
- return tryIndexedTableRows(env, table, alias, where);
19330
+ return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
19088
19331
  }
19089
19332
  function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
19090
19333
  const parts = [];
@@ -21574,6 +21817,7 @@ var Parser = class {
21574
21817
  let sqlBody = null;
21575
21818
  let volatility = null;
21576
21819
  let strict2 = false;
21820
+ const settings = {};
21577
21821
  for (; ; ) {
21578
21822
  if (this.eatKw("language")) {
21579
21823
  language = this.peek().type === "string" ? this.next().value : this.ident(true);
@@ -21631,8 +21875,23 @@ var Parser = class {
21631
21875
  continue;
21632
21876
  }
21633
21877
  if (this.eatKw("set")) {
21634
- this.ident(true);
21635
- if (this.eatOp("=") || this.eatKw("to")) this.next();
21878
+ const key = this.ident(true).toLowerCase();
21879
+ if (this.eatKw("from")) {
21880
+ this.expectKw("current");
21881
+ settings[key] = "__from_current__";
21882
+ } else {
21883
+ if (!this.eatOp("=")) this.expectKw("to");
21884
+ const values = [];
21885
+ do {
21886
+ const value = this.next();
21887
+ if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
21888
+ this.errorAt(value, "expected setting value");
21889
+ values.push(
21890
+ key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
21891
+ );
21892
+ } while (this.eatPunct(","));
21893
+ settings[key] = values.join(", ");
21894
+ }
21636
21895
  continue;
21637
21896
  }
21638
21897
  if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
@@ -21712,7 +21971,8 @@ var Parser = class {
21712
21971
  body,
21713
21972
  sqlBody,
21714
21973
  volatility,
21715
- strict: strict2
21974
+ strict: strict2,
21975
+ settings
21716
21976
  };
21717
21977
  }
21718
21978
  parseCreateTrigger(orReplace, constraint) {
@@ -21821,8 +22081,8 @@ var Parser = class {
21821
22081
  type: "alter_sequence",
21822
22082
  name: name2,
21823
22083
  ifExists,
21824
- options: { ownedBy: void 0 },
21825
- ...{ renameTo: to }
22084
+ options: {},
22085
+ renameTo: to
21826
22086
  };
21827
22087
  }
21828
22088
  if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
@@ -24398,7 +24658,20 @@ function runFunctionBody(env, fn, args2) {
24398
24658
  }
24399
24659
  return last;
24400
24660
  }
24661
+ function withFunctionSettings(env, fn, run) {
24662
+ const state = env.ctx.state;
24663
+ const saved = new Map(state.localSettings);
24664
+ for (const [name2, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name2, value);
24665
+ try {
24666
+ return run();
24667
+ } finally {
24668
+ state.localSettings = saved;
24669
+ }
24670
+ }
24401
24671
  function callSqlFunctionScalar(env, fn, args2) {
24672
+ return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args2));
24673
+ }
24674
+ function callSqlFunctionScalarBody(env, fn, args2) {
24402
24675
  const retT = fn.returns ?? "text";
24403
24676
  if (fn.language === "plpgsql") {
24404
24677
  return callPlpgsqlScalar(env, fn, args2);
@@ -24428,6 +24701,9 @@ function callSqlFunctionScalar(env, fn, args2) {
24428
24701
  return castTo(env.ctx, tv(rawT, raw), retT, {});
24429
24702
  }
24430
24703
  function callSqlFunctionSet(env, fn, args2) {
24704
+ return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args2));
24705
+ }
24706
+ function callSqlFunctionSetBody(env, fn, args2) {
24431
24707
  if (fn.language === "plpgsql") {
24432
24708
  return callPlpgsqlSet(env, fn, args2);
24433
24709
  }
@@ -24582,15 +24858,17 @@ function executeRecursiveCte(env, cte, query) {
24582
24858
  return rel3;
24583
24859
  }
24584
24860
  function renameWithAliases(rel3, label, colAliases, what) {
24585
- if (colAliases && colAliases.length > rel3.columns.length) {
24861
+ const visibleWidth = rel3.columns.filter((column) => !column.system).length;
24862
+ if (colAliases && colAliases.length > visibleWidth) {
24586
24863
  throw pgError(
24587
24864
  "invalid_column_reference",
24588
- `table "${what}" has ${rel3.columns.length} columns available but ${colAliases.length} columns specified`,
24865
+ `table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
24589
24866
  "42P10"
24590
24867
  );
24591
24868
  }
24592
24869
  const columns = rel3.columns.map((c, i) => ({
24593
- name: colAliases?.[i] ?? c.name,
24870
+ ...c,
24871
+ name: c.system ? c.name : colAliases?.[i] ?? c.name,
24594
24872
  type: c.type === UNKNOWN ? "text" : c.type,
24595
24873
  table: label
24596
24874
  }));
@@ -24611,8 +24889,11 @@ function materializeItem(env, item, scope) {
24611
24889
  if (table) {
24612
24890
  table.materializeSlab();
24613
24891
  const rel3 = {
24614
- columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
24615
- rows: table.rows
24892
+ columns: [
24893
+ ...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
24894
+ { name: "xmin", type: "xid", table: label, hidden: true, system: true }
24895
+ ],
24896
+ rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
24616
24897
  };
24617
24898
  return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
24618
24899
  }
@@ -25242,7 +25523,7 @@ function resolveColIdx(columns, parts) {
25242
25523
  let found = -1;
25243
25524
  for (let i = 0; i < columns.length; i++) {
25244
25525
  const c = columns[i];
25245
- if (!c.hidden && c.name === name3) {
25526
+ if ((!c.hidden || c.system) && c.name === name3) {
25246
25527
  if (found !== -1) return null;
25247
25528
  found = i;
25248
25529
  }
@@ -25826,7 +26107,7 @@ function expandTargets(core, columns) {
25826
26107
  let any = false;
25827
26108
  for (let i = 0; i < columns.length; i++) {
25828
26109
  const c = columns[i];
25829
- if (c.table === label) {
26110
+ if (c.table === label && !c.system) {
25830
26111
  any = true;
25831
26112
  items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
25832
26113
  }
@@ -26431,6 +26712,7 @@ var TransactionManager = class {
26431
26712
  this.base = null;
26432
26713
  this.savepoints = [];
26433
26714
  this.state.inTransaction = false;
26715
+ this.state.transactionXid = null;
26434
26716
  this.state.localSettings.clear();
26435
26717
  this.state.pendingTriggers = [];
26436
26718
  this.state.constraintModes.clear();
@@ -26443,6 +26725,7 @@ var TransactionManager = class {
26443
26725
  this.base = null;
26444
26726
  this.savepoints = [];
26445
26727
  this.state.inTransaction = false;
26728
+ this.state.transactionXid = null;
26446
26729
  this.state.localSettings.clear();
26447
26730
  this.state.pendingTriggers = [];
26448
26731
  this.state.constraintModes.clear();
@@ -26477,6 +26760,7 @@ var TransactionManager = class {
26477
26760
  this.base = null;
26478
26761
  this.savepoints = [];
26479
26762
  this.state.inTransaction = false;
26763
+ this.state.transactionXid = null;
26480
26764
  this.freezeDepth = 0;
26481
26765
  }
26482
26766
  };
@@ -26680,6 +26964,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
26680
26964
  const updated = existing.slice();
26681
26965
  applyUpdateSets(env, table, sets, scope, updated);
26682
26966
  computeGeneratedColumns(env, table, updated);
26967
+ table.rowXmins.set(updated, env.ctx.rowVersionXid());
26683
26968
  rows[existingIdx] = updated;
26684
26969
  indexUpdateRow(env, table, existingIdx, existing, updated);
26685
26970
  checkNotNull(env, table, updated);
@@ -26765,6 +27050,7 @@ function executeInsert(env0, stmt) {
26765
27050
  checkChecks(env, table, newRow);
26766
27051
  checkUnique(env, table, newRow, rows.length);
26767
27052
  checkForeignKeys(env, table, newRow);
27053
+ table.rowXmins.set(newRow, env.ctx.rowVersionXid());
26768
27054
  rows.push(newRow);
26769
27055
  indexInsertRow(env, table, rows.length - 1, newRow);
26770
27056
  insertedCount++;
@@ -26882,6 +27168,7 @@ function executeUpdate(env0, stmt) {
26882
27168
  if (fired.row === null) continue;
26883
27169
  const finalRow = fired.row;
26884
27170
  computeGeneratedColumns(env, table, finalRow);
27171
+ table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
26885
27172
  rows[ri] = finalRow;
26886
27173
  try {
26887
27174
  checkNotNull(env, table, finalRow);
@@ -27001,6 +27288,7 @@ function handleReferencedDelete(env, table, row, depth) {
27001
27288
  for (const c of con.columns) {
27002
27289
  newRow[child.columnIndex(c)] = null;
27003
27290
  }
27291
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
27004
27292
  childRows[i] = newRow;
27005
27293
  checkNotNull(env, child, newRow);
27006
27294
  checkChecks(env, child, newRow);
@@ -27014,6 +27302,7 @@ function handleReferencedDelete(env, table, row, depth) {
27014
27302
  const ci = child.columnIndex(c);
27015
27303
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
27016
27304
  }
27305
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
27017
27306
  childRows[i] = newRow;
27018
27307
  checkNotNull(env, child, newRow);
27019
27308
  checkChecks(env, child, newRow);
@@ -27051,6 +27340,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
27051
27340
  const refIdx = table.columnIndex(con.refColumns[c]);
27052
27341
  newRow[localIdx] = newRows[r][refIdx] ?? null;
27053
27342
  }
27343
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
27054
27344
  childRows[i] = newRow;
27055
27345
  checkChecks(env, child, newRow);
27056
27346
  }
@@ -27060,6 +27350,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
27060
27350
  for (const i of idxs) {
27061
27351
  const newRow = childRows[i].slice();
27062
27352
  for (const c of con.columns) newRow[child.columnIndex(c)] = null;
27353
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
27063
27354
  childRows[i] = newRow;
27064
27355
  checkNotNull(env, child, newRow);
27065
27356
  }
@@ -27072,6 +27363,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
27072
27363
  const ci = child.columnIndex(c);
27073
27364
  newRow[ci] = columnDefault(env, child, child.columns[ci]);
27074
27365
  }
27366
+ child.rowXmins.set(newRow, env.ctx.rowVersionXid());
27075
27367
  childRows[i] = newRow;
27076
27368
  checkForeignKeys(env, child, newRow);
27077
27369
  }
@@ -30119,13 +30411,63 @@ function executeCreateSequence(env, stmt) {
30119
30411
  schema.sequences.set(name2, seq);
30120
30412
  return commandResult("CREATE SEQUENCE", 0);
30121
30413
  }
30414
+ function renameSequenceReferences(env, seq, newName) {
30415
+ const state = env.ctx.state;
30416
+ const matches2 = (value) => {
30417
+ try {
30418
+ const input = parseRelationInput(value);
30419
+ if ("oid" in input) return input.oid === seq.oid;
30420
+ return state.findSequence(input.parts)?.oid === seq.oid;
30421
+ } catch {
30422
+ return false;
30423
+ }
30424
+ };
30425
+ const rewrite = (value) => {
30426
+ if (Array.isArray(value)) return value.map(rewrite);
30427
+ if (value === null || typeof value !== "object") return value;
30428
+ const node = value;
30429
+ const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
30430
+ const rewriteLiteral = (literal2) => {
30431
+ if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
30432
+ return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
30433
+ }
30434
+ return literal2;
30435
+ };
30436
+ if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
30437
+ updated.args[0] = rewriteLiteral(updated.args[0]);
30438
+ if (node.type === "cast" && node.target && typeof node.target === "object" && "parts" in node.target && Array.isArray(node.target.parts) && node.target.parts.at(-1) === "regclass")
30439
+ updated.expr = rewriteLiteral(updated.expr);
30440
+ return updated;
30441
+ };
30442
+ for (const schema of state.schemas.values()) {
30443
+ for (const table of [...schema.tables.values()]) {
30444
+ const writable = state.ensureWritableTable(table);
30445
+ for (const column of writable.columns) {
30446
+ if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
30447
+ if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
30448
+ column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
30449
+ }
30450
+ }
30451
+ }
30452
+ }
30122
30453
  function executeAlterSequence(env, stmt) {
30123
30454
  const state = env.ctx.state;
30124
- const seq = state.findSequence(stmt.name);
30125
- if (!seq) {
30455
+ const foundSequence = state.findSequence(stmt.name);
30456
+ if (!foundSequence) {
30126
30457
  if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
30127
30458
  throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
30128
30459
  }
30460
+ const seq = state.ensureWritableSequence(foundSequence);
30461
+ if (stmt.renameTo) {
30462
+ const schema = state.getSchema(seq.schema);
30463
+ if (schema.hasRelation(stmt.renameTo))
30464
+ throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
30465
+ renameSequenceReferences(env, seq, stmt.renameTo);
30466
+ schema.sequences.delete(seq.name);
30467
+ seq.name = stmt.renameTo;
30468
+ schema.sequences.set(seq.name, seq);
30469
+ return commandResult("ALTER SEQUENCE", 0);
30470
+ }
30129
30471
  const o = stmt.options;
30130
30472
  if (o.logged !== void 0) {
30131
30473
  setSequenceLogged(state, seq, o.logged);
@@ -30183,7 +30525,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
30183
30525
  col.defaultExpr = {
30184
30526
  type: "func",
30185
30527
  name: ["nextval"],
30186
- args: [{ type: "string_lit", value: `${schema.name}.${seqName}` }]
30528
+ args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
30187
30529
  };
30188
30530
  }
30189
30531
  for (const c of def.constraints) {
@@ -30436,7 +30778,11 @@ function executeCreateTableAs(env, stmt) {
30436
30778
  const table = new TableData(schema.name, name2, columns, state.nextOid(), stmt.temp);
30437
30779
  table.unlogged = stmt.unlogged === true;
30438
30780
  if (stmt.withData) {
30439
- for (const row of rel3.rows) table.mutableRows().push(row.slice());
30781
+ for (const row of rel3.rows) {
30782
+ const stored = row.slice();
30783
+ table.rowXmins.set(stored, env.ctx.rowVersionXid());
30784
+ table.mutableRows().push(stored);
30785
+ }
30440
30786
  }
30441
30787
  schema.tables.set(name2, table);
30442
30788
  const count = stmt.withData ? table.rowCount() : 0;
@@ -30705,6 +31051,12 @@ function executeCreateFunction(env, stmt) {
30705
31051
  language: lang,
30706
31052
  body,
30707
31053
  rawBody: stmt.body,
31054
+ settings: Object.fromEntries(
31055
+ Object.entries(stmt.settings ?? {}).map(([key, value]) => [
31056
+ key,
31057
+ value === "__from_current__" ? state.getSetting(key) ?? "" : value
31058
+ ])
31059
+ ),
30708
31060
  strict: stmt.strict,
30709
31061
  oid: state.nextOid()
30710
31062
  };
@@ -30889,6 +31241,7 @@ function executeAlterTable(env, stmt) {
30889
31241
  }
30890
31242
  const next = row.slice();
30891
31243
  next[idx] = nv;
31244
+ table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
30892
31245
  rows[i] = next;
30893
31246
  }
30894
31247
  col.type = resolved.column;
@@ -30990,6 +31343,11 @@ function executeAlterTable(env, stmt) {
30990
31343
  );
30991
31344
  }
30992
31345
  table.columns[idx].name = action.to;
31346
+ for (const seq of [...schema.sequences.values()]) {
31347
+ if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
31348
+ state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
31349
+ }
31350
+ }
30993
31351
  for (const con of table.constraints) {
30994
31352
  if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
30995
31353
  con.columns = con.columns.map((c) => c === action.from ? action.to : c);
@@ -31026,6 +31384,11 @@ function executeAlterTable(env, stmt) {
31026
31384
  throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
31027
31385
  }
31028
31386
  const oldName = table.name;
31387
+ for (const seq of [...schema.sequences.values()]) {
31388
+ if (seq.ownedBy?.table === oldName) {
31389
+ state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
31390
+ }
31391
+ }
31029
31392
  schema.tables.delete(table.name);
31030
31393
  table.name = action.to;
31031
31394
  schema.tables.set(action.to, table);
@@ -32899,6 +33262,7 @@ function encodeDatabaseState(state, runtime) {
32899
33262
  writeBjv(
32900
33263
  w,
32901
33264
  {
33265
+ xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
32902
33266
  name: table.name,
32903
33267
  schema: table.schema,
32904
33268
  columns: table.columns,
@@ -32996,8 +33360,14 @@ function decodeInner(snapshot, prng, clock) {
32996
33360
  table.constraints = meta.constraints;
32997
33361
  table.triggers = meta.triggers;
32998
33362
  table.unlogged = meta.unlogged === true;
33363
+ table.slabXmins = meta.xmins ?? null;
33364
+ state.xidCounter = Math.max(
33365
+ state.xidCounter,
33366
+ (meta.xmins ?? []).reduce((max, xid) => Math.max(max, xid + 1), 3)
33367
+ );
32999
33368
  if (meta.stats) state.tableStats.set(table.oid, meta.stats);
33000
33369
  const rowCount = readVarintU32(r);
33370
+ if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
33001
33371
  const slabColumns = [];
33002
33372
  for (let c = 0; c < meta.columns.length; c++)
33003
33373
  slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
@@ -33441,6 +33811,8 @@ function validateTableMetaBjv(value) {
33441
33811
  if (!isRecord2(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
33442
33812
  if (!Array.isArray(value.columns)) throw snapshotError();
33443
33813
  for (const col of value.columns) validateColumnMeta(col);
33814
+ if (value.xmins !== void 0 && (!Array.isArray(value.xmins) || value.xmins.some((xid) => !Number.isInteger(xid) || xid < 2 || xid > 4294967295)))
33815
+ throw snapshotError();
33444
33816
  }
33445
33817
  function validateViewMetaBjv(value) {
33446
33818
  if (!isRecord2(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
@@ -33534,6 +33906,7 @@ function forceSchemaIntern(pool, state, schemas) {
33534
33906
  pool.forceId(table.name);
33535
33907
  pool.forceId(table.schema);
33536
33908
  forceBjvStrings(pool, {
33909
+ xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
33537
33910
  name: table.name,
33538
33911
  schema: table.schema,
33539
33912
  columns: table.columns,
@@ -35164,7 +35537,7 @@ var Connection = class {
35164
35537
  if (stmt?.type !== "transaction") throw pgError2("syntax", "invalid transaction command", "42601");
35165
35538
  switch (stmt.action) {
35166
35539
  case "begin":
35167
- this.transaction ??= { statements: [], savepoints: [] };
35540
+ this.transaction ??= { statements: [], savepoints: [], xid: this.database.state.allocateXid() };
35168
35541
  return command("BEGIN");
35169
35542
  case "commit": {
35170
35543
  const transaction = this.transaction;
@@ -35173,6 +35546,7 @@ var Connection = class {
35173
35546
  this.inSession(
35174
35547
  this.database,
35175
35548
  () => this.database.transaction(() => {
35549
+ this.database.state.transactionXid = transaction.xid;
35176
35550
  for (const logged of transaction.statements) this.replay(this.database, logged);
35177
35551
  })
35178
35552
  );
@@ -35223,6 +35597,7 @@ var Connection = class {
35223
35597
  workspace.state.settings = new Map(this.settings);
35224
35598
  workspace.state.settingDefaults = this.settingDefaults;
35225
35599
  workspace.transactions.begin();
35600
+ workspace.state.transactionXid = this.transaction?.xid ?? null;
35226
35601
  for (const logged of this.transaction?.statements ?? []) {
35227
35602
  this.replay(workspace, logged);
35228
35603
  }