@creatornader/agent-bridge 0.3.1 → 0.5.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 (90) hide show
  1. package/CHANGELOG.md +222 -1
  2. package/README.md +312 -12
  3. package/ROADMAP.md +88 -7
  4. package/SECURITY.md +78 -5
  5. package/SKILL.md +108 -1
  6. package/dist/archive.d.ts +2 -2
  7. package/dist/archive.js +2 -2
  8. package/dist/{bridge-service-hX1ZQp4W.d.ts → bridge-service-CNBKdYXh.d.ts} +2 -1
  9. package/dist/{bridge-store-DPVSCwfs.d.ts → bridge-store-ByJ6CaJk.d.ts} +3 -0
  10. package/dist/bridge.d.ts +25 -8
  11. package/dist/bridge.js +19 -9
  12. package/dist/{chunk-MBPZXTJA.js → chunk-7VJI2MXI.js} +285 -42
  13. package/dist/chunk-7VJI2MXI.js.map +1 -0
  14. package/dist/{chunk-4VB44KJU.js → chunk-AWE3DFZV.js} +3 -2
  15. package/dist/chunk-AWE3DFZV.js.map +1 -0
  16. package/dist/{chunk-GADH244D.js → chunk-E4OWHGUE.js} +16 -5
  17. package/dist/chunk-E4OWHGUE.js.map +1 -0
  18. package/dist/{chunk-NCO7RLBM.js → chunk-GTK4KOED.js} +108 -8
  19. package/dist/chunk-GTK4KOED.js.map +1 -0
  20. package/dist/{chunk-SPSMZOCJ.js → chunk-HUHG7XTB.js} +6 -5
  21. package/dist/chunk-HUHG7XTB.js.map +1 -0
  22. package/dist/{chunk-5GMB3A77.js → chunk-IVG4XWWS.js} +26 -14
  23. package/dist/chunk-IVG4XWWS.js.map +1 -0
  24. package/dist/{chunk-WAI2IYIQ.js → chunk-P635FAN4.js} +50 -7
  25. package/dist/chunk-P635FAN4.js.map +1 -0
  26. package/dist/{chunk-45BZGB77.js → chunk-QNXHDOJ5.js} +218 -24
  27. package/dist/chunk-QNXHDOJ5.js.map +1 -0
  28. package/dist/{chunk-UAHMP6GC.js → chunk-QPC6JHA3.js} +10 -7
  29. package/dist/chunk-QPC6JHA3.js.map +1 -0
  30. package/dist/{chunk-Q6PPMXJC.js → chunk-SN7PIVDF.js} +377 -21
  31. package/dist/chunk-SN7PIVDF.js.map +1 -0
  32. package/dist/{chunk-A6W4QALF.js → chunk-TC6A7GMF.js} +2 -2
  33. package/dist/{chunk-2DFNOLMO.js → chunk-XDNT6ZNZ.js} +9 -6
  34. package/dist/chunk-XDNT6ZNZ.js.map +1 -0
  35. package/dist/{chunk-CEXBMOI5.js → chunk-Z6JP6MYD.js} +2 -2
  36. package/dist/cli.js +5867 -438
  37. package/dist/cli.js.map +1 -1
  38. package/dist/client-runtime.d.ts +4 -2
  39. package/dist/client-runtime.js +7 -7
  40. package/dist/contracts/generate.js +1 -1
  41. package/dist/dr.d.ts +9 -2
  42. package/dist/dr.js +6 -4
  43. package/dist/{gateway-CggQ8vTC.d.ts → gateway-CW-61lvs.d.ts} +27 -3
  44. package/dist/gateway-main.js +71 -7
  45. package/dist/gateway-main.js.map +1 -1
  46. package/dist/gateway.d.ts +3 -3
  47. package/dist/gateway.js +3 -3
  48. package/dist/index.js +8 -8
  49. package/dist/{postgres-bridge-store-Bfd3hRId.d.ts → postgres-bridge-store-C9KG9Z69.d.ts} +1 -1
  50. package/dist/postgres-production-preflight.d.ts +32 -0
  51. package/dist/postgres-production-preflight.js +249 -0
  52. package/dist/postgres-production-preflight.js.map +1 -0
  53. package/dist/server.js +8 -8
  54. package/dist/sqlite-edge-store-CdMIOrho.d.ts +148 -0
  55. package/dist/sqlite.d.ts +19 -80
  56. package/dist/sqlite.js +11 -3
  57. package/docs/architecture-v2.md +292 -15
  58. package/docs/decisions/0004-client-lifecycle-and-endpoint-migration.md +204 -0
  59. package/docs/deployment.md +349 -0
  60. package/docs/troubleshooting.md +23 -0
  61. package/llms.txt +69 -1
  62. package/openapi/agent-bridge-v2.openapi.json +1151 -124
  63. package/package.json +10 -2
  64. package/schemas/agent-bridge-v2.capabilities.json +26 -1
  65. package/schemas/agent-bridge-v2.mcp.json +11 -1
  66. package/schemas/agent-bridge-v2.schema.json +167 -0
  67. package/sql/migrations/007_runtime_role.sql +8 -4
  68. package/sql/migrations/013_row_isolation.sql +71 -8
  69. package/sql/migrations/014_owner_control_plane.sql +124 -31
  70. package/sql/migrations/015_portable_archives.sql +143 -41
  71. package/sql/migrations/016_native_dr_fence.sql +102 -35
  72. package/sql/migrations/017_gateway_authority_binding.sql +99 -0
  73. package/sql/migrations/018_endpoint_migration_challenges.sql +1054 -0
  74. package/sql/migrations/019_endpoint_migration_same_successor.sql +348 -0
  75. package/sql/migrations/020_managed_authority_compat.sql +698 -0
  76. package/sql/migrations/021_native_backup_reader.sql +421 -0
  77. package/sql/setup.sql +1 -3
  78. package/dist/chunk-2DFNOLMO.js.map +0 -1
  79. package/dist/chunk-45BZGB77.js.map +0 -1
  80. package/dist/chunk-4VB44KJU.js.map +0 -1
  81. package/dist/chunk-5GMB3A77.js.map +0 -1
  82. package/dist/chunk-GADH244D.js.map +0 -1
  83. package/dist/chunk-MBPZXTJA.js.map +0 -1
  84. package/dist/chunk-NCO7RLBM.js.map +0 -1
  85. package/dist/chunk-Q6PPMXJC.js.map +0 -1
  86. package/dist/chunk-SPSMZOCJ.js.map +0 -1
  87. package/dist/chunk-UAHMP6GC.js.map +0 -1
  88. package/dist/chunk-WAI2IYIQ.js.map +0 -1
  89. /package/dist/{chunk-A6W4QALF.js.map → chunk-TC6A7GMF.js.map} +0 -0
  90. /package/dist/{chunk-CEXBMOI5.js.map → chunk-Z6JP6MYD.js.map} +0 -0
@@ -10,18 +10,18 @@ import {
10
10
  isSupportedLocalSqliteSchemaContract,
11
11
  sqliteSchemaContractHash,
12
12
  verifySqliteHealth
13
- } from "./chunk-5GMB3A77.js";
13
+ } from "./chunk-IVG4XWWS.js";
14
14
  import {
15
15
  preparePrivateFileLocation,
16
16
  preparePrivateSqliteLocation,
17
17
  securePrivatePath,
18
18
  securePrivateSqliteFiles,
19
19
  verifyPrivatePathAccess
20
- } from "./chunk-NCO7RLBM.js";
20
+ } from "./chunk-GTK4KOED.js";
21
21
  import {
22
22
  NATIVE_DR_ADVISORY_LOCK_KEY,
23
23
  rowIsolationReady
24
- } from "./chunk-45BZGB77.js";
24
+ } from "./chunk-QNXHDOJ5.js";
25
25
 
26
26
  // src/native-dr-bundle.ts
27
27
  import { createHash } from "crypto";
@@ -88,12 +88,19 @@ var POSTGRES_SCHEMA_FIELDS = [
88
88
  "claimedDeliveryCount",
89
89
  "readinessAttestations"
90
90
  ];
91
- var POSTGRES_EXCLUDED_DATA = [
91
+ var POSTGRES_LEGACY_EXCLUDED_DATA = [
92
92
  "agent_bridge.agent_instances",
93
93
  "agent_bridge.rate_limit_buckets",
94
94
  "agent_bridge.request_authorities",
95
95
  "agent_bridge.archive_transaction_authorizations"
96
96
  ];
97
+ var POSTGRES_EXCLUDED_DATA = [
98
+ ...POSTGRES_LEGACY_EXCLUDED_DATA,
99
+ "agent_bridge.endpoint_migration_challenges"
100
+ ];
101
+ function postgresExcludedDataForSchemaVersion(schemaVersion) {
102
+ return schemaVersion <= 17 ? POSTGRES_LEGACY_EXCLUDED_DATA : POSTGRES_EXCLUDED_DATA;
103
+ }
97
104
  function validateSchema(kind, value) {
98
105
  if (kind === "sqlite") {
99
106
  const schema2 = exactObject(value, ["applicationId", "schemaContractSha256", "userVersion"], "DR SQLite schema");
@@ -106,7 +113,7 @@ function validateSchema(kind, value) {
106
113
  }
107
114
  assertString(schema.databaseName, "DR database name");
108
115
  assertString(schema.pgDumpVersion, "DR pg_dump version");
109
- if (!Array.isArray(schema.migrations) || schema.migrations.length > 1e4) throw new NativeDrBundleError("DR PostgreSQL migration inventory is invalid");
116
+ if (!Array.isArray(schema.migrations) || schema.migrations.length === 0 || schema.migrations.length > 1e4) throw new NativeDrBundleError("DR PostgreSQL migration inventory is invalid");
110
117
  let priorVersion = 0;
111
118
  for (const raw of schema.migrations) {
112
119
  const migration = exactObject(raw, ["checksum", "name", "version"], "DR migration");
@@ -115,13 +122,17 @@ function validateSchema(kind, value) {
115
122
  }
116
123
  priorVersion = Number(migration.version);
117
124
  }
125
+ if (priorVersion !== Number(schema.schemaVersion)) {
126
+ throw new NativeDrBundleError("DR PostgreSQL schema version does not match migrations");
127
+ }
118
128
  if (!schema.tableCounts || typeof schema.tableCounts !== "object" || Array.isArray(schema.tableCounts)) throw new NativeDrBundleError("DR PostgreSQL table counts are invalid");
119
129
  for (const [table, count] of Object.entries(schema.tableCounts)) {
120
130
  if (!/^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_]*$/.test(table) || typeof count !== "string" || !/^(0|[1-9][0-9]*)$/.test(count)) {
121
131
  throw new NativeDrBundleError("DR PostgreSQL table counts are invalid");
122
132
  }
123
133
  }
124
- if (!Array.isArray(schema.excludedDataTables) || schema.excludedDataTables.length !== POSTGRES_EXCLUDED_DATA.length || schema.excludedDataTables.some((name, index) => name !== POSTGRES_EXCLUDED_DATA[index])) {
134
+ const excludedData = postgresExcludedDataForSchemaVersion(Number(schema.schemaVersion));
135
+ if (!Array.isArray(schema.excludedDataTables) || schema.excludedDataTables.length !== excludedData.length || schema.excludedDataTables.some((name, index) => name !== excludedData[index])) {
125
136
  throw new NativeDrBundleError("DR PostgreSQL excluded-data inventory is invalid");
126
137
  }
127
138
  const readiness = exactObject(schema.readinessAttestations, [
@@ -453,12 +464,19 @@ function createBoundedToolOutput(maximumBytes) {
453
464
  var POSTGRES_NATIVE_DR_ROLE_SCHEMA = "agent-bridge.postgres-native-dr-roles";
454
465
  var POSTGRES_NATIVE_DR_ROLE_VERSION = 1;
455
466
  var POSTGRES_NATIVE_DR_SERVICE = "agent_bridge_dr";
456
- var POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES = [
467
+ var POSTGRES_NATIVE_DR_LEGACY_EXCLUDED_DATA_TABLES = [
457
468
  "agent_bridge.agent_instances",
458
469
  "agent_bridge.rate_limit_buckets",
459
470
  "agent_bridge.request_authorities",
460
471
  "agent_bridge.archive_transaction_authorizations"
461
472
  ];
473
+ var POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES = [
474
+ ...POSTGRES_NATIVE_DR_LEGACY_EXCLUDED_DATA_TABLES,
475
+ "agent_bridge.endpoint_migration_challenges"
476
+ ];
477
+ function excludedDataTablesForSchemaVersion(schemaVersion) {
478
+ return schemaVersion <= 17 ? POSTGRES_NATIVE_DR_LEGACY_EXCLUDED_DATA_TABLES : POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES;
479
+ }
462
480
  var SSL_PARAMETERS = /* @__PURE__ */ new Set([
463
481
  "channel_binding",
464
482
  "sslcert",
@@ -469,7 +487,7 @@ var SSL_PARAMETERS = /* @__PURE__ */ new Set([
469
487
  "sslrootcert",
470
488
  "sslsni"
471
489
  ]);
472
- var DERIVED_ROLE = /^agent_bridge_(?:runtime|data_owner|context_reader|event_writer|control_owner|control_operator|control_auditor|archive_operator)_[0-9a-f]{16}$/;
490
+ var DERIVED_ROLE = /^agent_bridge_(?:runtime|data_owner|context_reader|event_writer|control_owner|control_operator|control_auditor|archive_operator|backup_reader)_[0-9a-f]{16}$/;
473
491
  var ROLE_NAME = /^[^\u0000-\u001f\u007f]{1,63}$/u;
474
492
  function validPostgresIdentifier(value) {
475
493
  return value !== "PUBLIC" && !value.includes(":") && ROLE_NAME.test(value) && Buffer.byteLength(value, "utf8") <= 63;
@@ -579,6 +597,9 @@ function createPostgresDrLibpqFiles(connectionUrl, directory) {
579
597
  };
580
598
  }
581
599
  function buildPgDumpArgs(outputPath, snapshot, serviceName = POSTGRES_NATIVE_DR_SERVICE) {
600
+ return buildPgDumpArgsForTables(outputPath, snapshot, serviceName, POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES);
601
+ }
602
+ function buildPgDumpArgsForTables(outputPath, snapshot, serviceName, excludedDataTables) {
582
603
  assertSafeText(outputPath, "PostgreSQL dump path");
583
604
  assertSafeText(snapshot, "PostgreSQL snapshot");
584
605
  assertSafeText(serviceName, "PostgreSQL service name");
@@ -588,7 +609,7 @@ function buildPgDumpArgs(outputPath, snapshot, serviceName = POSTGRES_NATIVE_DR_
588
609
  "--schema=agent_bridge",
589
610
  "--no-tablespaces",
590
611
  `--snapshot=${snapshot}`,
591
- ...POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES.map((table) => `--exclude-table-data=${table}`),
612
+ ...excludedDataTables.map((table) => `--exclude-table-data=${table}`),
592
613
  `--dbname=service=${serviceName}`
593
614
  ];
594
615
  }
@@ -661,6 +682,29 @@ var POSTGRES_TOC_DESCRIPTORS = [
661
682
  "ACL"
662
683
  ];
663
684
  var POSTGRES_TOC_MAX_BYTES = 16 * 1024 * 1024;
685
+ function parsePostgresDumpTocBody(entry) {
686
+ let cursor = 0;
687
+ const readDigits = () => {
688
+ const start = cursor;
689
+ while (cursor < entry.length) {
690
+ const code = entry.charCodeAt(cursor);
691
+ if (code < 48 || code > 57) break;
692
+ cursor += 1;
693
+ }
694
+ return cursor > start;
695
+ };
696
+ const readSeparator = () => {
697
+ const start = cursor;
698
+ while (entry[cursor] === " " || entry[cursor] === " ") cursor += 1;
699
+ return cursor > start;
700
+ };
701
+ if (!readDigits() || entry[cursor] !== ";") return void 0;
702
+ cursor += 1;
703
+ if (!readSeparator() || !readDigits() || !readSeparator() || !readDigits() || !readSeparator()) {
704
+ return void 0;
705
+ }
706
+ return cursor < entry.length ? entry.slice(cursor) : void 0;
707
+ }
664
708
  function validatePostgresDumpToc(text) {
665
709
  if (Buffer.byteLength(text, "utf8") > POSTGRES_TOC_MAX_BYTES) {
666
710
  throw new PostgresNativeDrError("PG_DUMP_TOC_INVALID", "PostgreSQL dump table of contents exceeds 16 MiB");
@@ -668,9 +712,8 @@ function validatePostgresDumpToc(text) {
668
712
  const entries = text.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith(";"));
669
713
  if (entries.length === 0) throw new PostgresNativeDrError("PG_DUMP_TOC_INVALID", "PostgreSQL dump table of contents is empty");
670
714
  for (const entry of entries) {
671
- const match = /^\d+;\s+\d+\s+\d+\s+(.+)$/u.exec(entry);
672
- if (!match) throw new PostgresNativeDrError("PG_DUMP_TOC_INVALID", "PostgreSQL dump table of contents has an invalid record");
673
- const body = match[1];
715
+ const body = parsePostgresDumpTocBody(entry);
716
+ if (body === void 0) throw new PostgresNativeDrError("PG_DUMP_TOC_INVALID", "PostgreSQL dump table of contents has an invalid record");
674
717
  const descriptor = POSTGRES_TOC_DESCRIPTORS.find((candidate) => body.startsWith(`${candidate} `));
675
718
  if (!descriptor) throw new PostgresNativeDrError("PG_DUMP_TOC_OUT_OF_SCOPE", "PostgreSQL dump contains an unsupported object kind");
676
719
  const remainder = body.slice(descriptor.length + 1).split(/\s+/u);
@@ -891,21 +934,62 @@ function buildPostgresMembershipStatements(inventory, serverMajor2) {
891
934
  if (!Number.isSafeInteger(serverMajor2) || serverMajor2 < 15 || serverMajor2 > 18) {
892
935
  throw new Error("PostgreSQL membership target major must be between 15 and 18");
893
936
  }
894
- return validatePostgresRoleInventory(inventory).memberships.map((membership) => {
937
+ const validated = validatePostgresRoleInventory(inventory);
938
+ const schemaOwner = validated.roles.find((role) => role.kind === "schema-owner");
939
+ const rolesByName = new Map(validated.roles.map((role) => [role.name, role]));
940
+ const orderedMemberships = [...validated.memberships].sort((left, right) => {
941
+ const leftOwnerAuthority = left.member === schemaOwner.name ? 0 : 1;
942
+ const rightOwnerAuthority = right.member === schemaOwner.name ? 0 : 1;
943
+ return leftOwnerAuthority - rightOwnerAuthority || left.role.localeCompare(right.role) || left.member.localeCompare(right.member);
944
+ });
945
+ return orderedMemberships.filter(
946
+ (membership) => rolesByName.get(membership.member).kind !== "external-principal"
947
+ ).map((membership) => {
948
+ let grant;
895
949
  if (serverMajor2 === 15) {
896
950
  if (!membership.inheritOption || !membership.setOption) {
897
951
  throw new Error("PostgreSQL 15 cannot preserve membership INHERIT FALSE or SET FALSE semantics");
898
952
  }
899
- return `GRANT ${quoteIdentifier(membership.role)} TO ${quoteIdentifier(membership.member)}${membership.adminOption ? " WITH ADMIN OPTION" : ""};`;
900
- }
901
- const options = [
902
- `ADMIN ${membership.adminOption ? "OPTION" : "FALSE"}`,
903
- `INHERIT ${membership.inheritOption ? "TRUE" : "FALSE"}`,
904
- `SET ${membership.setOption ? "TRUE" : "FALSE"}`
905
- ].join(", ");
906
- return `GRANT ${quoteIdentifier(membership.role)} TO ${quoteIdentifier(membership.member)} WITH ${options};`;
953
+ grant = `GRANT ${quoteIdentifier(membership.role)} TO ${quoteIdentifier(membership.member)}${membership.adminOption ? " WITH ADMIN OPTION" : ""};`;
954
+ } else {
955
+ const options = [
956
+ `ADMIN ${membership.adminOption ? "OPTION" : "FALSE"}`,
957
+ `INHERIT ${membership.inheritOption ? "TRUE" : "FALSE"}`,
958
+ `SET ${membership.setOption ? "TRUE" : "FALSE"}`
959
+ ].join(", ");
960
+ grant = `GRANT ${quoteIdentifier(membership.role)} TO ${quoteIdentifier(membership.member)} WITH ${options};`;
961
+ }
962
+ const role = rolesByName.get(membership.role);
963
+ const schemaOwnerGrantedDerivedMembership = membership.member !== schemaOwner.name && role.kind === "derived";
964
+ return schemaOwnerGrantedDerivedMembership ? `SET LOCAL ROLE ${quoteIdentifier(schemaOwner.name)}; ${grant} RESET ROLE;` : grant;
907
965
  });
908
966
  }
967
+ function suspendedPostgresMemberships(inventory) {
968
+ const suffix = createHash2("md5").update(inventory.databaseName).digest("hex").slice(0, 16);
969
+ const recognizedRoles = /* @__PURE__ */ new Map([
970
+ [`agent_bridge_control_operator_${suffix}`, "operator"],
971
+ [`agent_bridge_control_auditor_${suffix}`, "auditor"],
972
+ [`agent_bridge_archive_operator_${suffix}`, "archive"]
973
+ ]);
974
+ const rolesByName = new Map(inventory.roles.map((role) => [role.name, role]));
975
+ const suspended = [];
976
+ for (const membership of inventory.memberships) {
977
+ if (rolesByName.get(membership.member)?.kind !== "external-principal") continue;
978
+ const recognized = recognizedRoles.get(membership.role);
979
+ if (recognized === "archive") {
980
+ suspended.push({ kind: "archive", member: membership.member });
981
+ continue;
982
+ }
983
+ if (recognized === "operator" || recognized === "auditor") {
984
+ suspended.push({
985
+ kind: "control",
986
+ member: membership.member,
987
+ controlRole: recognized
988
+ });
989
+ }
990
+ }
991
+ return suspended;
992
+ }
909
993
  var DEFAULT_PRIVILEGE_OBJECTS = {
910
994
  r: "TABLES",
911
995
  S: "SEQUENCES",
@@ -1178,7 +1262,8 @@ async function collectPostgresRoleInventory(client, databaseName) {
1178
1262
  FROM unnest(ARRAY[
1179
1263
  'agent_bridge_runtime_','agent_bridge_data_owner_','agent_bridge_context_reader_',
1180
1264
  'agent_bridge_event_writer_','agent_bridge_control_owner_','agent_bridge_control_operator_',
1181
- 'agent_bridge_control_auditor_','agent_bridge_archive_operator_'
1265
+ 'agent_bridge_control_auditor_','agent_bridge_archive_operator_',
1266
+ 'agent_bridge_backup_reader_'
1182
1267
  ]) prefix
1183
1268
  ), object_roles AS (
1184
1269
  SELECT namespace.nspowner AS oid, 'schema-owner'::text AS kind
@@ -1257,13 +1342,14 @@ async function collectPostgresRoleInventory(client, databaseName) {
1257
1342
  const names = roleRows.rows.map((row) => row.name);
1258
1343
  const membershipRows = names.length === 0 ? { rows: [], rowCount: 0 } : await client.query(`
1259
1344
  SELECT granted.rolname AS role, member.rolname AS member,
1260
- membership.admin_option AS "adminOption",
1261
- coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true) AS "inheritOption",
1262
- coalesce((to_jsonb(membership)->>'set_option')::boolean,true) AS "setOption"
1345
+ bool_or(membership.admin_option) AS "adminOption",
1346
+ bool_or(coalesce((to_jsonb(membership)->>'inherit_option')::boolean,true)) AS "inheritOption",
1347
+ bool_or(coalesce((to_jsonb(membership)->>'set_option')::boolean,true)) AS "setOption"
1263
1348
  FROM pg_catalog.pg_auth_members membership
1264
1349
  JOIN pg_catalog.pg_roles granted ON granted.oid=membership.roleid
1265
1350
  JOIN pg_catalog.pg_roles member ON member.oid=membership.member
1266
1351
  WHERE granted.rolname=ANY($1::text[]) AND member.rolname=ANY($1::text[])
1352
+ GROUP BY granted.rolname,member.rolname
1267
1353
  ORDER BY granted.rolname,member.rolname`, [names]);
1268
1354
  if (names.length > 0) {
1269
1355
  const boundary = await client.query(`
@@ -1350,9 +1436,13 @@ async function collectSnapshotMetadata(client, checkRowReady) {
1350
1436
  }
1351
1437
  }
1352
1438
  if (migrations.length === 0) throw new PostgresNativeDrError("SOURCE_SCHEMA_EMPTY", "source has no Agent Bridge migrations");
1439
+ const schemaVersion = Math.max(...migrations.map((migration) => migration.version));
1353
1440
  const tableRows = await client.query(`
1354
- SELECT table_name AS "tableName" FROM information_schema.tables
1355
- WHERE table_schema='agent_bridge' AND table_type='BASE TABLE' ORDER BY table_name`);
1441
+ SELECT relation.relname AS "tableName"
1442
+ FROM pg_catalog.pg_class relation
1443
+ JOIN pg_catalog.pg_namespace namespace ON namespace.oid=relation.relnamespace
1444
+ WHERE namespace.nspname='agent_bridge' AND relation.relkind IN ('r','p')
1445
+ ORDER BY relation.relname`);
1356
1446
  const tableCounts = {};
1357
1447
  for (const row of tableRows.rows) {
1358
1448
  const qualified = `agent_bridge.${row.tableName}`;
@@ -1363,6 +1453,9 @@ async function collectSnapshotMetadata(client, checkRowReady) {
1363
1453
  if (!value || !/^(?:0|[1-9][0-9]*)$/u.test(value)) throw new PostgresNativeDrError("SOURCE_COUNT_INVALID", `source count is invalid for ${qualified}`);
1364
1454
  tableCounts[qualified] = value;
1365
1455
  }
1456
+ if (!tableRows.rows.some((row) => row.tableName === "deliveries")) {
1457
+ throw new PostgresNativeDrError("SOURCE_COUNT_INVALID", "source deliveries table is unavailable");
1458
+ }
1366
1459
  const claimed = await client.query(
1367
1460
  `SELECT count(*)::text AS count FROM agent_bridge.deliveries WHERE state='claimed'`
1368
1461
  );
@@ -1374,13 +1467,15 @@ async function collectSnapshotMetadata(client, checkRowReady) {
1374
1467
  SELECT agent_bridge.security_schema_ready() AS security,
1375
1468
  agent_bridge.owner_control_plane_ready() AS "ownerControl",
1376
1469
  agent_bridge.portable_archive_ready() AS "portableArchive",
1470
+ ${schemaVersion >= 21 ? 'agent_bridge.native_backup_ready() AS "nativeBackup",' : ""}
1377
1471
  agent_bridge.credential_security_prerequisite_definition() AS "securityDefinition",
1378
1472
  agent_bridge.row_isolation_catalog_definition() AS "rowIsolationDefinition",
1379
1473
  agent_bridge.owner_control_attestation_definition() AS "ownerControlDefinition",
1380
1474
  agent_bridge.portable_archive_attestation_definition() AS "portableArchiveDefinition"`);
1381
1475
  const ready = readiness.rows[0];
1382
1476
  const rowReady = await checkRowReady(client);
1383
- if (!ready?.security || !rowReady || !ready.ownerControl || !ready.portableArchive || typeof ready.securityDefinition !== "string" || typeof ready.rowIsolationDefinition !== "string" || typeof ready.ownerControlDefinition !== "string" || typeof ready.portableArchiveDefinition !== "string") {
1477
+ const authorityReady = await gatewayAuthorityReady(client, schemaVersion);
1478
+ if (!ready?.security || !rowReady || !ready.ownerControl || !ready.portableArchive || schemaVersion >= 21 && !ready.nativeBackup || !authorityReady || typeof ready.securityDefinition !== "string" || typeof ready.rowIsolationDefinition !== "string" || typeof ready.ownerControlDefinition !== "string" || typeof ready.portableArchiveDefinition !== "string") {
1384
1479
  throw new PostgresNativeDrError("SOURCE_NOT_READY", "source PostgreSQL schema failed readiness attestation");
1385
1480
  }
1386
1481
  return {
@@ -1397,6 +1492,105 @@ async function collectSnapshotMetadata(client, checkRowReady) {
1397
1492
  }
1398
1493
  };
1399
1494
  }
1495
+ async function gatewayAuthorityReady(client, schemaVersion) {
1496
+ if (schemaVersion <= 16) return true;
1497
+ const result = await client.query(`
1498
+ WITH names AS (
1499
+ SELECT ('agent_bridge_runtime_' || substr(md5(current_database()),1,16))::name AS runtime_role,
1500
+ (SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge') AS schema_owner
1501
+ ) SELECT
1502
+ agent_bridge.gateway_authority_ready()
1503
+ AND EXISTS (
1504
+ SELECT 1
1505
+ FROM pg_catalog.pg_class relation
1506
+ JOIN pg_catalog.pg_namespace namespace ON namespace.oid=relation.relnamespace
1507
+ WHERE namespace.nspname='agent_bridge' AND relation.relname='gateway_authority'
1508
+ AND relation.relkind='r' AND relation.relowner=(SELECT schema_owner FROM names)
1509
+ AND NOT relation.relrowsecurity AND NOT relation.relforcerowsecurity
1510
+ )
1511
+ AND EXISTS (
1512
+ SELECT 1 FROM pg_catalog.pg_constraint table_constraint
1513
+ WHERE table_constraint.conrelid='agent_bridge.gateway_authority'::regclass
1514
+ AND table_constraint.conname='gateway_authority_singleton'
1515
+ AND table_constraint.contype='p'
1516
+ AND table_constraint.conkey::smallint[]=ARRAY[(SELECT attribute.attnum FROM pg_catalog.pg_attribute attribute
1517
+ WHERE attribute.attrelid='agent_bridge.gateway_authority'::regclass
1518
+ AND attribute.attname='singleton' AND attribute.attnum>0 AND NOT attribute.attisdropped)]
1519
+ )
1520
+ AND EXISTS (
1521
+ SELECT 1 FROM pg_catalog.pg_constraint table_constraint
1522
+ WHERE table_constraint.conrelid='agent_bridge.gateway_authority'::regclass
1523
+ AND table_constraint.conname='gateway_authority_singleton_true'
1524
+ AND table_constraint.contype='c'
1525
+ AND regexp_replace(
1526
+ pg_get_expr(table_constraint.conbin,table_constraint.conrelid),'[[:space:]()]','','g'
1527
+ )='singleton'
1528
+ )
1529
+ AND EXISTS (
1530
+ SELECT 1 FROM pg_catalog.pg_constraint table_constraint
1531
+ WHERE table_constraint.conrelid='agent_bridge.gateway_authority'::regclass
1532
+ AND table_constraint.conname='gateway_authority_id_unique'
1533
+ AND table_constraint.contype='u'
1534
+ AND table_constraint.conkey::smallint[]=ARRAY[(SELECT attribute.attnum FROM pg_catalog.pg_attribute attribute
1535
+ WHERE attribute.attrelid='agent_bridge.gateway_authority'::regclass
1536
+ AND attribute.attname='authority_id' AND attribute.attnum>0 AND NOT attribute.attisdropped)]
1537
+ )
1538
+ AND EXISTS (
1539
+ SELECT 1
1540
+ FROM pg_catalog.pg_trigger trigger
1541
+ JOIN pg_catalog.pg_proc trigger_function ON trigger_function.oid=trigger.tgfoid
1542
+ JOIN pg_catalog.pg_namespace trigger_namespace ON trigger_namespace.oid=trigger_function.pronamespace
1543
+ WHERE trigger.tgrelid='agent_bridge.gateway_authority'::regclass
1544
+ AND trigger.tgname='gateway_authority_immutable'
1545
+ AND NOT trigger.tgisinternal AND trigger.tgenabled='O'
1546
+ AND (trigger.tgtype::integer & 1)=0
1547
+ AND (trigger.tgtype::integer & 2)=2
1548
+ AND (trigger.tgtype::integer & 56)=56
1549
+ AND trigger_function.proname='reject_gateway_authority_mutation'
1550
+ AND trigger_namespace.nspname='agent_bridge'
1551
+ AND trigger_function.proowner=(SELECT schema_owner FROM names)
1552
+ AND NOT trigger_function.prosecdef
1553
+ AND coalesce(trigger_function.proconfig @> ARRAY['search_path=""'],false)
1554
+ )
1555
+ AND EXISTS (
1556
+ SELECT 1 FROM pg_catalog.pg_proc procedure
1557
+ WHERE procedure.oid='agent_bridge.gateway_authority_ready()'::regprocedure
1558
+ AND procedure.prosecdef AND procedure.provolatile='s'
1559
+ AND procedure.proowner=(SELECT schema_owner FROM names)
1560
+ AND coalesce(procedure.proconfig @> ARRAY['search_path=""'],false)
1561
+ )
1562
+ AND EXISTS (
1563
+ SELECT 1 FROM pg_catalog.pg_proc procedure
1564
+ WHERE procedure.oid='agent_bridge.open_request_authority_bound(uuid,text,uuid)'::regprocedure
1565
+ AND procedure.prosecdef AND procedure.provolatile='v'
1566
+ AND procedure.proowner=(SELECT schema_owner FROM names)
1567
+ AND coalesce(procedure.proconfig @> ARRAY['search_path=""'],false)
1568
+ )
1569
+ AND NOT EXISTS (
1570
+ SELECT 1
1571
+ FROM unnest(ARRAY[
1572
+ 'SELECT','INSERT','UPDATE','DELETE','TRUNCATE','REFERENCES','TRIGGER'
1573
+ ]) privilege(value)
1574
+ WHERE has_table_privilege((SELECT runtime_role FROM names),
1575
+ 'agent_bridge.gateway_authority',privilege.value)
1576
+ OR has_table_privilege('public','agent_bridge.gateway_authority',privilege.value)
1577
+ )
1578
+ AND NOT EXISTS (
1579
+ SELECT 1
1580
+ FROM unnest(ARRAY['SELECT','INSERT','UPDATE','REFERENCES']) privilege(value)
1581
+ WHERE has_any_column_privilege((SELECT runtime_role FROM names),
1582
+ 'agent_bridge.gateway_authority',privilege.value)
1583
+ OR has_any_column_privilege('public','agent_bridge.gateway_authority',privilege.value)
1584
+ )
1585
+ AND has_function_privilege((SELECT runtime_role FROM names),
1586
+ 'agent_bridge.gateway_authority_ready()','EXECUTE')
1587
+ AND has_function_privilege((SELECT runtime_role FROM names),
1588
+ 'agent_bridge.open_request_authority_bound(uuid,text,uuid)','EXECUTE')
1589
+ AND NOT has_function_privilege('public','agent_bridge.gateway_authority_ready()','EXECUTE')
1590
+ AND NOT has_function_privilege('public',
1591
+ 'agent_bridge.open_request_authority_bound(uuid,text,uuid)','EXECUTE') AS ready`);
1592
+ return result.rows[0]?.ready === true;
1593
+ }
1400
1594
  function createPrivateEmptyFile(path) {
1401
1595
  const descriptor = openSync2(path, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL, 384);
1402
1596
  closeSync2(descriptor);
@@ -1434,10 +1628,16 @@ async function backupPostgresNativeDr(options) {
1434
1628
  if (!snapshot) throw new PostgresNativeDrError("SNAPSHOT_EXPORT_FAILED", "PostgreSQL did not export a disaster recovery snapshot");
1435
1629
  const metadata = await collectSnapshotMetadata(source, deps.checkRowIsolationReady);
1436
1630
  const major = serverMajor(metadata.serverVersionNum);
1631
+ const schemaVersion = Math.max(...metadata.migrations.map((migration) => migration.version));
1632
+ const excludedDataTables = excludedDataTablesForSchemaVersion(schemaVersion);
1437
1633
  const beforeInventory = await collectPostgresRoleInventory(source, metadata.databaseName);
1438
1634
  const canonicalRoles = canonicalPostgresRoleInventory(beforeInventory);
1439
1635
  const tools = await checkedTools(major, libpq.environment, options.toolDirectory, deps);
1440
- const dump = await deps.runTool(tools.pgDump, buildPgDumpArgs(dumpPath, snapshot, libpq.serviceName), libpq.environment);
1636
+ const dump = await deps.runTool(
1637
+ tools.pgDump,
1638
+ buildPgDumpArgsForTables(dumpPath, snapshot, libpq.serviceName, excludedDataTables),
1639
+ libpq.environment
1640
+ );
1441
1641
  assertToolSucceeded(dump, "PG_DUMP_FAILED", "pg_dump");
1442
1642
  verifyPrivatePathAccess(dumpPath, "file");
1443
1643
  if (statSync(dumpPath).size === 0) throw new PostgresNativeDrError("PG_DUMP_EMPTY", "pg_dump produced an empty file");
@@ -1459,7 +1659,6 @@ async function backupPostgresNativeDr(options) {
1459
1659
  transactionOpen = false;
1460
1660
  await source.query("SELECT pg_catalog.pg_advisory_unlock($1)", [NATIVE_DR_ADVISORY_LOCK_KEY]);
1461
1661
  lockHeld = false;
1462
- const schemaVersion = Math.max(...metadata.migrations.map((migration) => migration.version));
1463
1662
  const result = {
1464
1663
  backupId: validateBackupId(options.backupId ?? deps.randomId()),
1465
1664
  createdAt: deps.now().toISOString(),
@@ -1471,7 +1670,7 @@ async function backupPostgresNativeDr(options) {
1471
1670
  schemaVersion,
1472
1671
  migrations: metadata.migrations,
1473
1672
  tableCounts: metadata.tableCounts,
1474
- excludedDataTables: [...POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES],
1673
+ excludedDataTables: [...excludedDataTables],
1475
1674
  claimedDeliveryCount: metadata.claimedDeliveryCount,
1476
1675
  pgDumpVersion: tools.pgDumpVersion,
1477
1676
  roleInventorySha256: sha256(canonicalRoles),
@@ -1558,10 +1757,11 @@ function validatePostgresNativeDrSchema(value) {
1558
1757
  throw new PostgresNativeDrError("INVALID_MANIFEST", "PostgreSQL table count inventory is invalid");
1559
1758
  }
1560
1759
  }
1561
- for (const table of ["agent_bridge.deliveries", "agent_bridge.delivery_events", ...POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES]) {
1760
+ const excludedDataTables = excludedDataTablesForSchemaVersion(value.schemaVersion);
1761
+ for (const table of ["agent_bridge.deliveries", "agent_bridge.delivery_events", ...excludedDataTables]) {
1562
1762
  if (!(table in value.tableCounts)) throw new PostgresNativeDrError("INVALID_MANIFEST", `PostgreSQL table count is missing for ${table}`);
1563
1763
  }
1564
- if (JSON.stringify(value.excludedDataTables) !== JSON.stringify(POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES)) {
1764
+ if (JSON.stringify(value.excludedDataTables) !== JSON.stringify(excludedDataTables)) {
1565
1765
  throw new PostgresNativeDrError("INVALID_MANIFEST", "PostgreSQL excluded table inventory is invalid");
1566
1766
  }
1567
1767
  if (!/^(?:0|[1-9][0-9]*)$/u.test(value.claimedDeliveryCount)) throw new PostgresNativeDrError("INVALID_MANIFEST", "PostgreSQL claimed delivery count is invalid");
@@ -1669,12 +1869,24 @@ async function targetTableCounts(client) {
1669
1869
  }
1670
1870
  return counts;
1671
1871
  }
1672
- function expectedRestoredTableCounts(schema) {
1872
+ function expectedRestoredTableCounts(schema, suspendedMemberships) {
1673
1873
  const expected = { ...schema.tableCounts };
1674
- for (const table of POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES) expected[table] = "0";
1874
+ for (const table of excludedDataTablesForSchemaVersion(schema.schemaVersion)) expected[table] = "0";
1675
1875
  const deliveryEvents = expected["agent_bridge.delivery_events"];
1676
1876
  if (deliveryEvents === void 0) throw new PostgresNativeDrError("INVALID_MANIFEST", "PostgreSQL delivery event count is missing");
1677
1877
  expected["agent_bridge.delivery_events"] = (BigInt(deliveryEvents) + BigInt(schema.claimedDeliveryCount)).toString();
1878
+ for (const [kind, table] of [
1879
+ ["control", "agent_bridge.control_membership_events"],
1880
+ ["archive", "agent_bridge.archive_membership_events"]
1881
+ ]) {
1882
+ const increment = suspendedMemberships.filter((membership) => membership.kind === kind).length;
1883
+ if (increment === 0) continue;
1884
+ const current = expected[table];
1885
+ if (current === void 0) {
1886
+ throw new PostgresNativeDrError("INVALID_MANIFEST", `PostgreSQL ${kind} membership event count is missing`);
1887
+ }
1888
+ expected[table] = (BigInt(current) + BigInt(increment)).toString();
1889
+ }
1678
1890
  return expected;
1679
1891
  }
1680
1892
  function compareStringMaps(actual, expected, label) {
@@ -1765,11 +1977,17 @@ async function restorePostgresNativeDrInternal(options) {
1765
1977
  if (metadata.schemaExists || !metadata.databaseFresh) {
1766
1978
  throw new PostgresNativeDrError("TARGET_NOT_FRESH", "target must be a dedicated fresh database without user objects or default ACLs");
1767
1979
  }
1980
+ const schemaOwner = inventory.roles.find((role) => role.kind === "schema-owner");
1768
1981
  const conflicts = await target.query(
1769
- `SELECT rolname AS name FROM pg_catalog.pg_roles WHERE rolname=ANY($1::text[]) ORDER BY rolname`,
1982
+ `SELECT rolname AS name,rolname=current_user AS "isCurrentUser",
1983
+ rolsuper "isSuperuser"
1984
+ FROM pg_catalog.pg_roles WHERE rolname=ANY($1::text[]) ORDER BY rolname`,
1770
1985
  [inventory.roles.map((role) => role.name)]
1771
1986
  );
1772
- if (conflicts.rows.length > 0) throw new PostgresNativeDrError("TARGET_ROLE_CONFLICT", "target contains a role required by the backup");
1987
+ const reusesSchemaOwner = conflicts.rows.length === 1 && conflicts.rows[0]?.name === schemaOwner.name && conflicts.rows[0].isCurrentUser && conflicts.rows[0].isSuperuser;
1988
+ if (conflicts.rows.length > 0 && !reusesSchemaOwner) {
1989
+ throw new PostgresNativeDrError("TARGET_ROLE_CONFLICT", "target contains a role required by the backup");
1990
+ }
1773
1991
  await assertPostgresRestoreAuthority(target);
1774
1992
  admin = deps.createClient(administrativeDatabaseUrl(targetUrl, metadata.databaseName));
1775
1993
  await admin.connect();
@@ -1779,12 +1997,13 @@ async function restorePostgresNativeDrInternal(options) {
1779
1997
  securePrivatePath(schemaAclListPath, "file");
1780
1998
  verifyPrivatePathAccess(schemaAclListPath, "file");
1781
1999
  for (const [index, statement] of buildPostgresRoleShellStatements(inventory).entries()) {
2000
+ const role = inventory.roles[index];
2001
+ if (reusesSchemaOwner && role.name === schemaOwner.name) continue;
1782
2002
  phase = "role shell creation";
1783
2003
  restoreStarted = true;
1784
2004
  await target.query(statement);
1785
- createdRoles.push(inventory.roles[index].name);
2005
+ createdRoles.push(role.name);
1786
2006
  }
1787
- const schemaOwner = inventory.roles.find((role) => role.kind === "schema-owner");
1788
2007
  phase = "schema creation";
1789
2008
  await target.query(`CREATE SCHEMA agent_bridge AUTHORIZATION ${quoteIdentifier(schemaOwner.name)}`);
1790
2009
  phase = "schema ACL restore";
@@ -1815,6 +2034,25 @@ async function restorePostgresNativeDrInternal(options) {
1815
2034
  transactionOpen = true;
1816
2035
  phase = "membership restore";
1817
2036
  for (const statement of buildPostgresMembershipStatements(inventory, major)) await target.query(statement);
2037
+ const suspendedMemberships = suspendedPostgresMemberships(inventory);
2038
+ phase = "external membership suspension";
2039
+ for (const membership of suspendedMemberships) {
2040
+ if (membership.kind === "control") {
2041
+ await target.query(
2042
+ `INSERT INTO agent_bridge.control_membership_events(
2043
+ request_id,action,member_role,control_role,actor
2044
+ ) VALUES($1::uuid,'revoke',$2::name,$3,$4::name)`,
2045
+ [deps.randomId(), membership.member, membership.controlRole, schemaOwner.name]
2046
+ );
2047
+ } else {
2048
+ await target.query(
2049
+ `INSERT INTO agent_bridge.archive_membership_events(
2050
+ request_id,action,member_role,actor
2051
+ ) VALUES($1::uuid,'revoke',$2::name,$3::name)`,
2052
+ [deps.randomId(), membership.member, schemaOwner.name]
2053
+ );
2054
+ }
2055
+ }
1818
2056
  phase = "default privilege restore";
1819
2057
  for (const statement of buildPostgresDefaultPrivilegeStatements(inventory)) await target.query(statement);
1820
2058
  phase = "claim normalization";
@@ -1840,23 +2078,27 @@ async function restorePostgresNativeDrInternal(options) {
1840
2078
  }
1841
2079
  phase = "table count validation";
1842
2080
  const counts = await targetTableCounts(target);
1843
- compareStringMaps(counts, expectedRestoredTableCounts(schema), "restored PostgreSQL");
2081
+ compareStringMaps(counts, expectedRestoredTableCounts(schema, suspendedMemberships), "restored PostgreSQL");
1844
2082
  phase = "readiness validation";
1845
2083
  const readiness = await target.query(`
1846
2084
  SELECT agent_bridge.security_schema_ready() AS security,
1847
2085
  agent_bridge.owner_control_plane_ready() AS "ownerControl",
1848
2086
  agent_bridge.portable_archive_ready() AS "portableArchive",
2087
+ ${schema.schemaVersion >= 21 ? 'agent_bridge.native_backup_ready() AS "nativeBackup",' : ""}
1849
2088
  agent_bridge.credential_security_prerequisite_definition() AS "securityDefinition",
1850
2089
  agent_bridge.row_isolation_catalog_definition() AS "rowIsolationDefinition",
1851
2090
  agent_bridge.owner_control_attestation_definition() AS "ownerControlDefinition",
1852
2091
  agent_bridge.portable_archive_attestation_definition() AS "portableArchiveDefinition"`);
1853
2092
  const ready = readiness.rows[0];
1854
2093
  const restoredRowReady = await deps.checkRowIsolationReady(target);
2094
+ const restoredGatewayAuthorityReady = await gatewayAuthorityReady(target, schema.schemaVersion);
1855
2095
  const failedReadiness = [
1856
2096
  !ready?.security ? "security" : void 0,
1857
2097
  !restoredRowReady ? "row-isolation" : void 0,
1858
2098
  !ready?.ownerControl ? "owner-control" : void 0,
1859
- !ready?.portableArchive ? "portable-archive" : void 0
2099
+ !ready?.portableArchive ? "portable-archive" : void 0,
2100
+ schema.schemaVersion >= 21 && !ready?.nativeBackup ? "native-backup" : void 0,
2101
+ !restoredGatewayAuthorityReady ? "gateway-authority" : void 0
1860
2102
  ].filter(Boolean);
1861
2103
  if (failedReadiness.length > 0) {
1862
2104
  throw new PostgresNativeDrError("RESTORE_NOT_READY", `restored PostgreSQL schema failed readiness attestation: ${failedReadiness.join(", ")}`);
@@ -2396,6 +2638,7 @@ export {
2396
2638
  POSTGRES_NATIVE_DR_ROLE_SCHEMA,
2397
2639
  POSTGRES_NATIVE_DR_ROLE_VERSION,
2398
2640
  POSTGRES_NATIVE_DR_SERVICE,
2641
+ POSTGRES_NATIVE_DR_LEGACY_EXCLUDED_DATA_TABLES,
2399
2642
  POSTGRES_NATIVE_DR_EXCLUDED_DATA_TABLES,
2400
2643
  PostgresNativeDrError,
2401
2644
  createPostgresDrLibpqFiles,
@@ -2425,4 +2668,4 @@ export {
2425
2668
  restoreLocalSqlite,
2426
2669
  SQLITE_EDGE_APPLICATION_ID
2427
2670
  };
2428
- //# sourceMappingURL=chunk-MBPZXTJA.js.map
2671
+ //# sourceMappingURL=chunk-7VJI2MXI.js.map