@opendatalabs/personal-server-ts-server 1.6.0 → 1.8.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.
@@ -105536,6 +105536,17 @@ var GENERIC_PAYMENT_TYPES = {
105536
105536
  ]
105537
105537
  };
105538
105538
 
105539
+ // ../core/dist/lineage/attestation.js
105540
+ var LINEAGE_ATTESTATION_TYPES = {
105541
+ LineageAttestation: [
105542
+ { name: "ownerAddress", type: "address" },
105543
+ { name: "scope", type: "string" },
105544
+ { name: "expectedVersion", type: "uint256" },
105545
+ { name: "dataHash", type: "bytes32" },
105546
+ { name: "sources", type: "bytes32[]" }
105547
+ ]
105548
+ };
105549
+
105539
105550
  // ../core/dist/signing/signer.js
105540
105551
  function createServerSigner(account, gatewayConfig) {
105541
105552
  return {
@@ -105568,6 +105579,14 @@ function createServerSigner(account, gatewayConfig) {
105568
105579
  message: msg
105569
105580
  });
105570
105581
  },
105582
+ async signLineageAttestation(msg) {
105583
+ return account.signTypedData({
105584
+ domain: dataRegistryDomain(gatewayConfig),
105585
+ types: LINEAGE_ATTESTATION_TYPES,
105586
+ primaryType: "LineageAttestation",
105587
+ message: { ...msg, sources: [...msg.sources] }
105588
+ });
105589
+ },
105571
105590
  async signRecordDataAccess(msg) {
105572
105591
  return account.signTypedData({
105573
105592
  domain: dataRegistryDomain(gatewayConfig),
@@ -105579,6 +105598,498 @@ function createServerSigner(account, gatewayConfig) {
105579
105598
  };
105580
105599
  }
105581
105600
 
105601
+ // ../core/dist/signing/request-signer.js
105602
+ function createRequestSigner(account) {
105603
+ return {
105604
+ async signRequest(params) {
105605
+ return buildWeb3SignedHeader({
105606
+ signMessage: (message) => account.signMessage(message),
105607
+ aud: params.aud,
105608
+ method: params.method,
105609
+ uri: params.uri,
105610
+ body: params.body,
105611
+ grantId: params.grantId
105612
+ });
105613
+ }
105614
+ };
105615
+ }
105616
+
105617
+ // ../core/dist/errors/catalog.js
105618
+ var ProtocolError = class extends Error {
105619
+ code;
105620
+ errorCode;
105621
+ details;
105622
+ constructor(code, errorCode, message, details) {
105623
+ super(message);
105624
+ this.code = code;
105625
+ this.errorCode = errorCode;
105626
+ this.details = details;
105627
+ this.name = this.constructor.name;
105628
+ }
105629
+ toJSON() {
105630
+ return {
105631
+ error: {
105632
+ code: this.code,
105633
+ errorCode: this.errorCode,
105634
+ message: this.message,
105635
+ ...this.details !== void 0 && { details: this.details }
105636
+ }
105637
+ };
105638
+ }
105639
+ };
105640
+ var MissingAuthError2 = class extends ProtocolError {
105641
+ constructor(details) {
105642
+ super(401, "MISSING_AUTH", "Missing authentication", details);
105643
+ }
105644
+ };
105645
+ var InvalidSignatureError3 = class extends ProtocolError {
105646
+ constructor(details) {
105647
+ super(401, "INVALID_SIGNATURE", "Invalid signature", details);
105648
+ }
105649
+ };
105650
+ var UnregisteredBuilderError = class extends ProtocolError {
105651
+ constructor(details) {
105652
+ super(401, "UNREGISTERED_BUILDER", "Unregistered builder", details);
105653
+ }
105654
+ };
105655
+ var NotOwnerError = class extends ProtocolError {
105656
+ constructor(details) {
105657
+ super(401, "NOT_OWNER", "Not the owner", details);
105658
+ }
105659
+ };
105660
+ var ExpiredTokenError2 = class extends ProtocolError {
105661
+ constructor(details) {
105662
+ super(401, "EXPIRED_TOKEN", "Token has expired", details);
105663
+ }
105664
+ };
105665
+ var GrantRequiredError = class extends ProtocolError {
105666
+ constructor(details) {
105667
+ super(403, "GRANT_REQUIRED", "Grant required", details);
105668
+ }
105669
+ };
105670
+ var GrantExpiredError = class extends ProtocolError {
105671
+ constructor(details) {
105672
+ super(403, "GRANT_EXPIRED", "Grant has expired", details);
105673
+ }
105674
+ };
105675
+ var GrantRevokedError = class extends ProtocolError {
105676
+ constructor(details) {
105677
+ super(403, "GRANT_REVOKED", "Grant has been revoked", details);
105678
+ }
105679
+ };
105680
+ var ScopeMismatchError = class extends ProtocolError {
105681
+ constructor(details) {
105682
+ super(403, "SCOPE_MISMATCH", "Scope not granted", details);
105683
+ }
105684
+ };
105685
+ var GrantOwnerMismatchError = class extends ProtocolError {
105686
+ constructor(details) {
105687
+ super(403, "GRANT_OWNER_MISMATCH", "Grant was not issued by this server's owner", details);
105688
+ }
105689
+ };
105690
+ var PsUnavailableError = class extends ProtocolError {
105691
+ constructor(details) {
105692
+ super(503, "PS_UNAVAILABLE", "Personal Server runtime unavailable", details);
105693
+ }
105694
+ };
105695
+ var ServerNotConfiguredError = class extends ProtocolError {
105696
+ constructor(details) {
105697
+ super(500, "SERVER_NOT_CONFIGURED", "Server is not configured", details);
105698
+ }
105699
+ };
105700
+ var LineageInvalidError = class extends ProtocolError {
105701
+ constructor(message, details) {
105702
+ super(400, "LINEAGE_INVALID", message, details);
105703
+ }
105704
+ };
105705
+ var LineageScopeUnderSourcePrefixError = class extends ProtocolError {
105706
+ constructor(details) {
105707
+ super(400, "LINEAGE_SCOPE_UNDER_SOURCE_PREFIX", `Derived scope "${details.scope}" shares its first segment with source scope "${details.sourceScope}"; a wildcard grant on that namespace would read both. Name derivatives under their own namespace.`, details);
105708
+ }
105709
+ };
105710
+ var LineageSourceUnknownError = class extends ProtocolError {
105711
+ constructor(details) {
105712
+ super(422, "LINEAGE_SOURCE_UNKNOWN", "One or more lineage sources are not data points of this owner", details);
105713
+ }
105714
+ };
105715
+ var LineageSourceLookupFailedError = class extends ProtocolError {
105716
+ constructor(details) {
105717
+ super(502, "LINEAGE_SOURCE_LOOKUP_FAILED", "Could not resolve a lineage source at the gateway", details);
105718
+ }
105719
+ };
105720
+ var LineageUnavailableError = class extends ProtocolError {
105721
+ constructor(details) {
105722
+ super(503, "LINEAGE_UNAVAILABLE", "This server is not configured to reach the gateway lineage graph (gateway URL or server signing key missing)", details);
105723
+ }
105724
+ };
105725
+ var LineageGatewayError = class extends ProtocolError {
105726
+ constructor(details) {
105727
+ super(502, "LINEAGE_GATEWAY_ERROR", `Gateway lineage request failed with status ${details.status}`, details);
105728
+ }
105729
+ };
105730
+ var LineageCascadeUnavailableError = class extends ProtocolError {
105731
+ constructor(details) {
105732
+ super(501, "LINEAGE_CASCADE_UNAVAILABLE", "DELETE ?cascade=lineage is specified but not implemented yet: the lineage walk that finds every derivative is missing. Delete scopes one at a time; each single-scope delete is durable.", details);
105733
+ }
105734
+ };
105735
+ var InvalidCascadeError = class extends ProtocolError {
105736
+ constructor(details) {
105737
+ super(400, "INVALID_CASCADE", 'Unsupported cascade mode; the only supported value is "lineage"', details);
105738
+ }
105739
+ };
105740
+ var DeleteTombstoneFailedError = class extends ProtocolError {
105741
+ constructor(details) {
105742
+ super(502, "DELETE_TOMBSTONE_FAILED", "Gateway did not acknowledge the deletion tombstone; nothing was deleted", details);
105743
+ }
105744
+ };
105745
+ var DataDeletedError = class extends ProtocolError {
105746
+ constructor(details) {
105747
+ super(410, "DATA_DELETED", "Data point has been deleted", details);
105748
+ }
105749
+ };
105750
+
105751
+ // ../core/dist/sync/data-point-id.js
105752
+ function computeDataPointId(ownerAddress, scope) {
105753
+ return keccak256(encodeAbiParameters([
105754
+ { name: "ownerAddress", type: "address" },
105755
+ { name: "scope", type: "string" }
105756
+ ], [ownerAddress.toLowerCase(), scope]));
105757
+ }
105758
+
105759
+ // ../core/dist/lineage/lineage.js
105760
+ var LINEAGE_KEY = "$lineage";
105761
+ var LINEAGE_FIELD = "lineage";
105762
+ var MAX_LINEAGE_SOURCES = 256;
105763
+ var LOCAL_SCOPE_SCAN_PAGE = 1e3;
105764
+ var BYTES32_HEX = /^0x[0-9a-fA-F]{64}$/;
105765
+ function isRecord(value) {
105766
+ return value !== null && typeof value === "object" && !Array.isArray(value);
105767
+ }
105768
+ function hasReservedLineageKey(data) {
105769
+ return Object.prototype.hasOwnProperty.call(data, LINEAGE_KEY);
105770
+ }
105771
+ function stampLineage(data, lineage) {
105772
+ return { ...data, [LINEAGE_KEY]: lineage };
105773
+ }
105774
+ var StoredLineageMalformedError = class extends Error {
105775
+ constructor(detail) {
105776
+ super(`Stored $lineage is malformed: ${detail}`);
105777
+ this.name = "StoredLineageMalformedError";
105778
+ }
105779
+ };
105780
+ function readStoredLineage(data) {
105781
+ if (!isRecord(data) || !(LINEAGE_KEY in data))
105782
+ return null;
105783
+ const value = data[LINEAGE_KEY];
105784
+ if (!isRecord(value)) {
105785
+ throw new StoredLineageMalformedError("not an object");
105786
+ }
105787
+ const sources = value.sources;
105788
+ if (!Array.isArray(sources) || !sources.every((id2) => typeof id2 === "string" && BYTES32_HEX.test(id2))) {
105789
+ throw new StoredLineageMalformedError("sources is not a list of bytes32 ids");
105790
+ }
105791
+ if (typeof value.writtenAt !== "string") {
105792
+ throw new StoredLineageMalformedError("writtenAt is not a string");
105793
+ }
105794
+ return {
105795
+ sources: sources.map((id2) => id2.toLowerCase()),
105796
+ writtenAt: value.writtenAt
105797
+ };
105798
+ }
105799
+ function extractLineageField(container) {
105800
+ if (!isRecord(container))
105801
+ return void 0;
105802
+ return container[LINEAGE_FIELD];
105803
+ }
105804
+ function parseLineageSources(value) {
105805
+ if (!Array.isArray(value)) {
105806
+ throw new LineageInvalidError(`${LINEAGE_FIELD} must be an array of data point ids (0x-prefixed 32-byte hex)`);
105807
+ }
105808
+ if (value.length > MAX_LINEAGE_SOURCES) {
105809
+ throw new LineageInvalidError(`${LINEAGE_FIELD} lists ${value.length} sources; the maximum is ${MAX_LINEAGE_SOURCES}`, { max: MAX_LINEAGE_SOURCES, count: value.length });
105810
+ }
105811
+ const seen = /* @__PURE__ */ new Set();
105812
+ const sources = [];
105813
+ for (const entry of value) {
105814
+ if (typeof entry !== "string" || !BYTES32_HEX.test(entry)) {
105815
+ throw new LineageInvalidError(`${LINEAGE_FIELD} entries must be 0x-prefixed 32-byte hex data point ids`, { entry: typeof entry === "string" ? entry : typeof entry });
105816
+ }
105817
+ const id2 = entry.toLowerCase();
105818
+ if (seen.has(id2)) {
105819
+ throw new LineageInvalidError(`${LINEAGE_FIELD} lists the same source twice`, { duplicate: id2 });
105820
+ }
105821
+ seen.add(id2);
105822
+ sources.push(id2);
105823
+ }
105824
+ return sources;
105825
+ }
105826
+ function scopeNamespace(scope) {
105827
+ const dot = scope.indexOf(".");
105828
+ return dot === -1 ? scope : scope.slice(0, dot);
105829
+ }
105830
+ function derivedScopeViolatesNaming(derivedScope, sourceScope) {
105831
+ return scopeNamespace(derivedScope) === scopeNamespace(sourceScope);
105832
+ }
105833
+ function assertDerivedScopeNaming(derivedScope, sourceScopes) {
105834
+ for (const sourceScope of sourceScopes) {
105835
+ if (derivedScopeViolatesNaming(derivedScope, sourceScope)) {
105836
+ throw new LineageScopeUnderSourcePrefixError({
105837
+ scope: derivedScope,
105838
+ sourceScope
105839
+ });
105840
+ }
105841
+ }
105842
+ }
105843
+ async function resolveLineageSources(input) {
105844
+ const ownId = computeDataPointId(input.serverOwner, input.scope);
105845
+ const self2 = input.sources.find((id2) => id2 === ownId);
105846
+ if (self2) {
105847
+ throw new LineageInvalidError("A record cannot list its own data point as a lineage source", { dataPointId: self2 });
105848
+ }
105849
+ const local = localScopesById(input.storage, input.serverOwner, new Set(input.sources));
105850
+ const resolved = [];
105851
+ const unknown2 = [];
105852
+ for (const dataPointId of input.sources) {
105853
+ const localScope = local.get(dataPointId);
105854
+ if (localScope !== void 0) {
105855
+ resolved.push({
105856
+ dataPointId,
105857
+ scope: localScope,
105858
+ version: null,
105859
+ deletedAt: null
105860
+ });
105861
+ continue;
105862
+ }
105863
+ if (!input.gateway) {
105864
+ unknown2.push(dataPointId);
105865
+ continue;
105866
+ }
105867
+ let record2;
105868
+ try {
105869
+ record2 = await input.gateway.getDataPoint(dataPointId);
105870
+ } catch (err2) {
105871
+ throw new LineageSourceLookupFailedError({
105872
+ dataPointId,
105873
+ error: err2 instanceof Error ? err2.message : String(err2)
105874
+ });
105875
+ }
105876
+ if (!record2 || record2.ownerAddress.toLowerCase() !== input.serverOwner.toLowerCase()) {
105877
+ unknown2.push(dataPointId);
105878
+ continue;
105879
+ }
105880
+ resolved.push({
105881
+ dataPointId,
105882
+ scope: record2.scope,
105883
+ version: record2.version,
105884
+ deletedAt: record2.deletedAt
105885
+ });
105886
+ }
105887
+ if (unknown2.length > 0) {
105888
+ throw new LineageSourceUnknownError({ unknown: unknown2 });
105889
+ }
105890
+ return resolved;
105891
+ }
105892
+ function localScopesById(storage, serverOwner, wanted) {
105893
+ const byId = /* @__PURE__ */ new Map();
105894
+ for (let offset = 0; ; offset += LOCAL_SCOPE_SCAN_PAGE) {
105895
+ const { scopes, total } = storage.listScopes({
105896
+ limit: LOCAL_SCOPE_SCAN_PAGE,
105897
+ offset
105898
+ });
105899
+ for (const summary of scopes) {
105900
+ const id2 = computeDataPointId(serverOwner, summary.scope);
105901
+ if (wanted.has(id2))
105902
+ byId.set(id2, summary.scope);
105903
+ }
105904
+ if (byId.size === wanted.size || scopes.length === 0 || offset + scopes.length >= total) {
105905
+ break;
105906
+ }
105907
+ }
105908
+ return byId;
105909
+ }
105910
+ async function prepareLineage(input) {
105911
+ const sources = parseLineageSources(input.field);
105912
+ if (!input.serverOwner) {
105913
+ throw new ServerNotConfiguredError({
105914
+ reason: "serverOwner is required to validate lineage sources"
105915
+ });
105916
+ }
105917
+ const resolved = await resolveLineageSources({
105918
+ scope: input.scope,
105919
+ sources,
105920
+ serverOwner: input.serverOwner,
105921
+ storage: input.storage,
105922
+ gateway: input.gateway
105923
+ });
105924
+ assertDerivedScopeNaming(input.scope, resolved.map((source) => source.scope));
105925
+ return { sources, writtenAt: input.now().toISOString() };
105926
+ }
105927
+
105928
+ // ../core/dist/lineage/gateway.js
105929
+ function isRecord2(value) {
105930
+ return value !== null && typeof value === "object" && !Array.isArray(value);
105931
+ }
105932
+ function isLineageNode(value) {
105933
+ if (!isRecord2(value))
105934
+ return false;
105935
+ if (value.redacted === true) {
105936
+ return Object.keys(value).length === 1;
105937
+ }
105938
+ if (typeof value.dataPointId !== "string")
105939
+ return false;
105940
+ return typeof value.scope === "string" && typeof value.version === "string" && (value.deletedAt === null || typeof value.deletedAt === "string");
105941
+ }
105942
+ function isGatewayProof(value) {
105943
+ return isRecord2(value) && typeof value.userSignature === "string" && typeof value.gatewaySignature === "string" && typeof value.timestamp === "number" && typeof value.status === "string" && (value.estimatedConfirmation === null || typeof value.estimatedConfirmation === "string") && (value.chainBlockHeight === null || typeof value.chainBlockHeight === "number");
105944
+ }
105945
+ function derivesDataPointId(id2, ownerAddress, scope) {
105946
+ try {
105947
+ return computeDataPointId(ownerAddress, scope).toLowerCase() === id2.toLowerCase();
105948
+ } catch {
105949
+ return false;
105950
+ }
105951
+ }
105952
+ function parseLineageView(value) {
105953
+ if (!isRecord2(value) || typeof value.dataPointId !== "string" || typeof value.ownerAddress !== "string" || typeof value.scope !== "string" || typeof value.version !== "string" || !(value.deletedAt === null || typeof value.deletedAt === "string") || !Array.isArray(value.sources) || !value.sources.every(isLineageNode) || !Array.isArray(value.derivatives) || !value.derivatives.every(isLineageNode) || !(value.grantId === void 0 || typeof value.grantId === "string") || !(value.derivativesTruncated === void 0 || value.derivativesTruncated === true)) {
105954
+ return null;
105955
+ }
105956
+ return value;
105957
+ }
105958
+ function createGatewayLineageClient(options) {
105959
+ const base = options.gatewayUrl.replace(/\/+$/, "");
105960
+ const origin = new URL(base).origin;
105961
+ const doFetch = options.fetch ?? fetch;
105962
+ async function readJson(res) {
105963
+ try {
105964
+ return await res.json();
105965
+ } catch {
105966
+ return null;
105967
+ }
105968
+ }
105969
+ return {
105970
+ async getDataPoint(dataPointId) {
105971
+ const res = await doFetch(`${base}/v1/data/${encodeURIComponent(dataPointId)}?includeDeleted=true`);
105972
+ if (res.status === 404)
105973
+ return null;
105974
+ if (!res.ok) {
105975
+ throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
105976
+ }
105977
+ const body = await readJson(res);
105978
+ const data = isRecord2(body) ? body.data : void 0;
105979
+ if (!isRecord2(data) || typeof data.id !== "string" || typeof data.ownerAddress !== "string" || typeof data.scope !== "string" || typeof data.expectedVersion !== "string") {
105980
+ throw new Error("Gateway error: malformed data point response");
105981
+ }
105982
+ if (data.id.toLowerCase() !== dataPointId.toLowerCase()) {
105983
+ throw new Error(`Gateway error: data point response is for ${data.id}, requested ${dataPointId}`);
105984
+ }
105985
+ if (!derivesDataPointId(data.id, data.ownerAddress, data.scope)) {
105986
+ throw new Error(`Gateway error: data point ${data.id} does not derive from its owner and scope`);
105987
+ }
105988
+ return {
105989
+ dataPointId: data.id,
105990
+ ownerAddress: data.ownerAddress,
105991
+ scope: data.scope,
105992
+ version: data.expectedVersion,
105993
+ deletedAt: typeof data.deletedAt === "string" ? data.deletedAt : null
105994
+ };
105995
+ },
105996
+ async getLineage(input) {
105997
+ if (!options.requestSigner) {
105998
+ throw new LineageUnavailableError({ reason: "no request signer" });
105999
+ }
106000
+ const uri = `/v1/data/${input.dataPointId.toLowerCase()}/lineage` + (input.version !== void 0 ? `/${input.version}` : "");
106001
+ const authorization = await options.requestSigner.signRequest({
106002
+ aud: origin,
106003
+ method: "GET",
106004
+ uri,
106005
+ grantId: input.grantId?.toLowerCase()
106006
+ });
106007
+ const res = await doFetch(`${base}${uri}`, {
106008
+ headers: { Authorization: authorization }
106009
+ });
106010
+ const body = await readJson(res);
106011
+ if (!res.ok)
106012
+ return { ok: false, status: res.status, body };
106013
+ const data = parseLineageView(isRecord2(body) ? body.data : void 0);
106014
+ const proof = isRecord2(body) ? body.proof : void 0;
106015
+ if (!data || !isGatewayProof(proof)) {
106016
+ return {
106017
+ ok: false,
106018
+ status: res.status,
106019
+ body: { error: "malformed lineage response", received: body }
106020
+ };
106021
+ }
106022
+ const requestedId = input.dataPointId.toLowerCase();
106023
+ const requestedGrant = input.grantId?.toLowerCase();
106024
+ const servedGrant = data.grantId?.toLowerCase();
106025
+ const viewMismatch = data.dataPointId.toLowerCase() !== requestedId || input.version !== void 0 && data.version !== input.version || requestedGrant !== servedGrant;
106026
+ if (viewMismatch) {
106027
+ return {
106028
+ ok: false,
106029
+ status: res.status,
106030
+ body: {
106031
+ error: "lineage response does not match the requested view",
106032
+ requested: {
106033
+ dataPointId: requestedId,
106034
+ version: input.version,
106035
+ grantId: requestedGrant
106036
+ },
106037
+ received: {
106038
+ dataPointId: data.dataPointId,
106039
+ version: data.version,
106040
+ grantId: servedGrant
106041
+ }
106042
+ }
106043
+ };
106044
+ }
106045
+ if (!derivesDataPointId(data.dataPointId, data.ownerAddress, data.scope)) {
106046
+ return {
106047
+ ok: false,
106048
+ status: res.status,
106049
+ body: {
106050
+ error: "lineage view does not derive from its owner and scope",
106051
+ received: {
106052
+ dataPointId: data.dataPointId,
106053
+ ownerAddress: data.ownerAddress,
106054
+ scope: data.scope
106055
+ }
106056
+ }
106057
+ };
106058
+ }
106059
+ return { ok: true, data, proof };
106060
+ },
106061
+ async registerDataPoint(params) {
106062
+ const res = await doFetch(`${base}/v1/data`, {
106063
+ method: "POST",
106064
+ headers: {
106065
+ "Content-Type": "application/json",
106066
+ Authorization: `Web3Signed ${params.signature}`
106067
+ },
106068
+ body: JSON.stringify({
106069
+ ownerAddress: params.ownerAddress,
106070
+ scope: params.scope,
106071
+ dataHash: params.dataHash,
106072
+ metadataHash: params.metadataHash,
106073
+ expectedVersion: params.expectedVersion,
106074
+ lineage: [...params.lineage],
106075
+ lineageSignature: params.lineageSignature
106076
+ })
106077
+ });
106078
+ if (!res.ok) {
106079
+ const body2 = await readJson(res);
106080
+ const detail = isRecord2(body2) && typeof body2.error === "string" && body2.error || res.statusText;
106081
+ throw new Error(`Gateway error: ${res.status} ${detail}`);
106082
+ }
106083
+ const body = await readJson(res);
106084
+ const record2 = isRecord2(body) ? body : {};
106085
+ return {
106086
+ dataPointId: typeof record2.dataPointId === "string" ? record2.dataPointId : typeof record2.id === "string" ? record2.id : void 0,
106087
+ expectedVersion: typeof record2.expectedVersion === "string" ? record2.expectedVersion : void 0
106088
+ };
106089
+ }
106090
+ };
106091
+ }
106092
+
105582
106093
  // ../lite/node_modules/@opendatalabs/vana-sdk/dist/index.browser.js
105583
106094
  init_hmac();
105584
106095
  init_sha2();
@@ -108843,6 +109354,7 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
108843
109354
  schemaId: entry.schemaId ?? null,
108844
109355
  version: version4,
108845
109356
  dataPointId: entry.dataPointId ?? null,
109357
+ afterTombstoneVersion: entry.afterTombstoneVersion ?? null,
108846
109358
  id: state.nextId,
108847
109359
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
108848
109360
  };
@@ -108936,25 +109448,34 @@ async function createPersistentPsLiteStorage(adapter, persistence = createIndexe
108936
109448
  await persist();
108937
109449
  return deleted;
108938
109450
  },
109451
+ async deleteVersion(scope, collectedAt2) {
109452
+ const entry = state.entries.find((e10) => e10.scope === scope && e10.collectedAt === collectedAt2);
109453
+ if (!entry)
109454
+ return false;
109455
+ return removeEntry(entry);
109456
+ },
108939
109457
  async deleteByFileId(fileId) {
108940
109458
  const entry = state.entries.find((e10) => e10.fileId === fileId);
108941
109459
  if (!entry)
108942
109460
  return false;
108943
- const blobPath = envelopePath(entry.scope, entry.collectedAt);
108944
- await Promise.all([
108945
- fileStore.deleteEnvelope(blobPath),
108946
- fallbackStore.deleteEnvelope(blobPath),
108947
- fileStore.deleteBlockTree?.(blockTreePath(entry.scope, entry.collectedAt)) ?? Promise.resolve(),
108948
- fallbackStore.deleteBlockTree?.(blockTreePath(entry.scope, entry.collectedAt)) ?? Promise.resolve()
108949
- ]);
108950
- state = {
108951
- ...state,
108952
- entries: state.entries.filter((e10) => e10 !== entry)
108953
- };
108954
- await persist();
108955
- return true;
109461
+ return removeEntry(entry);
108956
109462
  }
108957
109463
  };
109464
+ async function removeEntry(entry) {
109465
+ const blobPath = envelopePath(entry.scope, entry.collectedAt);
109466
+ await Promise.all([
109467
+ fileStore.deleteEnvelope(blobPath),
109468
+ fallbackStore.deleteEnvelope(blobPath),
109469
+ fileStore.deleteBlockTree?.(blockTreePath(entry.scope, entry.collectedAt)) ?? Promise.resolve(),
109470
+ fallbackStore.deleteBlockTree?.(blockTreePath(entry.scope, entry.collectedAt)) ?? Promise.resolve()
109471
+ ]);
109472
+ state = {
109473
+ ...state,
109474
+ entries: state.entries.filter((e10) => e10 !== entry)
109475
+ };
109476
+ await persist();
109477
+ return true;
109478
+ }
108958
109479
  if (fileStore.readEnvelopePreview) {
108959
109480
  storagePort.readEnvelopePreview = async (scope, collectedAt2, { maxBytes }) => {
108960
109481
  const path = envelopePath(scope, collectedAt2);
@@ -109588,90 +110109,6 @@ async function loadOrCreatePsLiteServerIdentity(params) {
109588
110109
  return { persisted, account };
109589
110110
  }
109590
110111
 
109591
- // ../core/dist/errors/catalog.js
109592
- var ProtocolError = class extends Error {
109593
- code;
109594
- errorCode;
109595
- details;
109596
- constructor(code, errorCode, message, details) {
109597
- super(message);
109598
- this.code = code;
109599
- this.errorCode = errorCode;
109600
- this.details = details;
109601
- this.name = this.constructor.name;
109602
- }
109603
- toJSON() {
109604
- return {
109605
- error: {
109606
- code: this.code,
109607
- errorCode: this.errorCode,
109608
- message: this.message,
109609
- ...this.details !== void 0 && { details: this.details }
109610
- }
109611
- };
109612
- }
109613
- };
109614
- var MissingAuthError2 = class extends ProtocolError {
109615
- constructor(details) {
109616
- super(401, "MISSING_AUTH", "Missing authentication", details);
109617
- }
109618
- };
109619
- var InvalidSignatureError3 = class extends ProtocolError {
109620
- constructor(details) {
109621
- super(401, "INVALID_SIGNATURE", "Invalid signature", details);
109622
- }
109623
- };
109624
- var UnregisteredBuilderError = class extends ProtocolError {
109625
- constructor(details) {
109626
- super(401, "UNREGISTERED_BUILDER", "Unregistered builder", details);
109627
- }
109628
- };
109629
- var NotOwnerError = class extends ProtocolError {
109630
- constructor(details) {
109631
- super(401, "NOT_OWNER", "Not the owner", details);
109632
- }
109633
- };
109634
- var ExpiredTokenError2 = class extends ProtocolError {
109635
- constructor(details) {
109636
- super(401, "EXPIRED_TOKEN", "Token has expired", details);
109637
- }
109638
- };
109639
- var GrantRequiredError = class extends ProtocolError {
109640
- constructor(details) {
109641
- super(403, "GRANT_REQUIRED", "Grant required", details);
109642
- }
109643
- };
109644
- var GrantExpiredError = class extends ProtocolError {
109645
- constructor(details) {
109646
- super(403, "GRANT_EXPIRED", "Grant has expired", details);
109647
- }
109648
- };
109649
- var GrantRevokedError = class extends ProtocolError {
109650
- constructor(details) {
109651
- super(403, "GRANT_REVOKED", "Grant has been revoked", details);
109652
- }
109653
- };
109654
- var ScopeMismatchError = class extends ProtocolError {
109655
- constructor(details) {
109656
- super(403, "SCOPE_MISMATCH", "Scope not granted", details);
109657
- }
109658
- };
109659
- var GrantOwnerMismatchError = class extends ProtocolError {
109660
- constructor(details) {
109661
- super(403, "GRANT_OWNER_MISMATCH", "Grant was not issued by this server's owner", details);
109662
- }
109663
- };
109664
- var PsUnavailableError = class extends ProtocolError {
109665
- constructor(details) {
109666
- super(503, "PS_UNAVAILABLE", "Personal Server runtime unavailable", details);
109667
- }
109668
- };
109669
- var ServerNotConfiguredError = class extends ProtocolError {
109670
- constructor(details) {
109671
- super(500, "SERVER_NOT_CONFIGURED", "Server is not configured", details);
109672
- }
109673
- };
109674
-
109675
110112
  // ../core/dist/auth/request.js
109676
110113
  function resolveOrigin(origin) {
109677
110114
  return typeof origin === "function" ? origin() : origin;
@@ -110323,18 +110760,47 @@ function normalizeLimit(value) {
110323
110760
  function normalizeOffset(value) {
110324
110761
  return value ?? 0;
110325
110762
  }
110326
- function isRecord(value) {
110763
+ function isRecord3(value) {
110327
110764
  return value !== null && typeof value === "object" && !Array.isArray(value);
110328
110765
  }
110766
+ var VISIBILITY_PAGE_SIZE = 200;
110329
110767
  async function listDataScopesContract(input) {
110330
110768
  const limit = normalizeLimit(input.limit);
110331
110769
  const offset = normalizeOffset(input.offset);
110332
- const result = input.storage.listScopes({
110333
- scopePrefix: input.scopePrefix,
110334
- limit,
110335
- offset
110336
- });
110337
- const scopes = await Promise.all(result.scopes.map(async (summary) => {
110770
+ let page;
110771
+ let total;
110772
+ if (input.isVisible) {
110773
+ const visible = [];
110774
+ for (let scan = 0; ; scan += VISIBILITY_PAGE_SIZE) {
110775
+ const batch = input.storage.listScopes({
110776
+ scopePrefix: input.scopePrefix,
110777
+ limit: VISIBILITY_PAGE_SIZE,
110778
+ offset: scan
110779
+ });
110780
+ for (const summary of batch.scopes) {
110781
+ const latest = input.storage.findEntry({
110782
+ scope: summary.scope,
110783
+ at: summary.latestCollectedAt
110784
+ });
110785
+ if (!latest || await input.isVisible(summary.scope, latest)) {
110786
+ visible.push(summary);
110787
+ }
110788
+ }
110789
+ if (batch.scopes.length < VISIBILITY_PAGE_SIZE)
110790
+ break;
110791
+ }
110792
+ total = visible.length;
110793
+ page = visible.slice(offset, offset + limit);
110794
+ } else {
110795
+ const result = input.storage.listScopes({
110796
+ scopePrefix: input.scopePrefix,
110797
+ limit,
110798
+ offset
110799
+ });
110800
+ page = result.scopes;
110801
+ total = result.total;
110802
+ }
110803
+ const scopes = await Promise.all(page.map(async (summary) => {
110338
110804
  const entry = input.storage.findEntry({
110339
110805
  scope: summary.scope,
110340
110806
  at: summary.latestCollectedAt
@@ -110342,7 +110808,7 @@ async function listDataScopesContract(input) {
110342
110808
  if (!entry) {
110343
110809
  return summary;
110344
110810
  }
110345
- const hasBlocks = typeof input.storage.canReadScopeBlocks === "function" ? await input.storage.canReadScopeBlocks(summary.scope, summary.latestCollectedAt) : typeof input.storage.hasScopeBlocks === "function" ? await input.storage.hasScopeBlocks(summary.scope, summary.latestCollectedAt) : false;
110811
+ const hasBlocks = typeof input.storage.hasScopeBlocks === "function" ? await input.storage.hasScopeBlocks(summary.scope, summary.latestCollectedAt) : false;
110346
110812
  return {
110347
110813
  ...summary,
110348
110814
  dataStatus: hasBlocks ? "ready" : "indexing",
@@ -110353,33 +110819,52 @@ async function listDataScopesContract(input) {
110353
110819
  ok: true,
110354
110820
  response: {
110355
110821
  scopes,
110356
- total: result.total,
110822
+ total,
110357
110823
  limit,
110358
110824
  offset
110359
110825
  }
110360
110826
  };
110361
110827
  }
110362
- function listDataVersionsContract(input) {
110828
+ async function listDataVersionsContract(input) {
110363
110829
  const scopeResult = parseDataScopeContract(input.scopeParam);
110364
110830
  if (!scopeResult.ok)
110365
110831
  return scopeResult;
110366
110832
  const limit = normalizeLimit(input.limit);
110367
110833
  const offset = normalizeOffset(input.offset);
110368
- const entries = input.storage.listVersions(scopeResult.scope, {
110369
- limit,
110370
- offset
110371
- });
110834
+ let page;
110835
+ let total;
110836
+ if (input.isVisible) {
110837
+ const visible = [];
110838
+ for (let scan = 0; ; scan += VISIBILITY_PAGE_SIZE) {
110839
+ const batch = input.storage.listVersions(scopeResult.scope, {
110840
+ limit: VISIBILITY_PAGE_SIZE,
110841
+ offset: scan
110842
+ });
110843
+ for (const entry of batch) {
110844
+ if (await input.isVisible(scopeResult.scope, entry)) {
110845
+ visible.push(entry);
110846
+ }
110847
+ }
110848
+ if (batch.length < VISIBILITY_PAGE_SIZE)
110849
+ break;
110850
+ }
110851
+ total = visible.length;
110852
+ page = visible.slice(offset, offset + limit);
110853
+ } else {
110854
+ page = input.storage.listVersions(scopeResult.scope, { limit, offset });
110855
+ total = input.storage.countVersions(scopeResult.scope);
110856
+ }
110372
110857
  return {
110373
110858
  ok: true,
110374
110859
  scope: scopeResult.scope,
110375
110860
  response: {
110376
110861
  scope: scopeResult.scope,
110377
- versions: entries.map((entry) => ({
110862
+ versions: page.map((entry) => ({
110378
110863
  fileId: entry.fileId,
110379
110864
  schemaId: entry.schemaId,
110380
110865
  collectedAt: entry.collectedAt
110381
110866
  })),
110382
- total: input.storage.countVersions(scopeResult.scope),
110867
+ total,
110383
110868
  limit,
110384
110869
  offset
110385
110870
  }
@@ -110414,7 +110899,7 @@ async function ingestDataContract(input) {
110414
110899
  const scopeResult = parseDataScopeContract(input.scopeParam);
110415
110900
  if (!scopeResult.ok)
110416
110901
  return scopeResult;
110417
- if (!isRecord(input.body)) {
110902
+ if (!isRecord3(input.body)) {
110418
110903
  return {
110419
110904
  ok: false,
110420
110905
  status: 400,
@@ -110434,7 +110919,17 @@ async function ingestDataContract(input) {
110434
110919
  }
110435
110920
  };
110436
110921
  }
110437
- const envelope = createDataFileEnvelope(scopeResult.scope, input.collectedAt, input.attribution ? stampWriterAttribution(input.body, input.attribution) : input.body);
110922
+ if (hasReservedLineageKey(input.body)) {
110923
+ return {
110924
+ ok: false,
110925
+ status: 400,
110926
+ body: {
110927
+ error: "INVALID_BODY",
110928
+ message: "Request body must not contain the reserved $lineage key"
110929
+ }
110930
+ };
110931
+ }
110932
+ const envelope = createDataFileEnvelope(scopeResult.scope, input.collectedAt, stampServerKeys(input.body, input));
110438
110933
  const writeResult = await input.storage.writeEnvelope(envelope);
110439
110934
  try {
110440
110935
  await writeBlockSidecars(input.storage, envelope);
@@ -110446,20 +110941,34 @@ async function ingestDataContract(input) {
110446
110941
  path: writeResult.relativePath,
110447
110942
  scope: scopeResult.scope,
110448
110943
  collectedAt: input.collectedAt,
110449
- sizeBytes: writeResult.sizeBytes
110944
+ sizeBytes: writeResult.sizeBytes,
110945
+ afterTombstoneVersion: input.afterTombstoneVersion ?? null
110450
110946
  });
110451
110947
  return {
110452
110948
  ok: true,
110453
110949
  scope: scopeResult.scope,
110454
110950
  collectedAt: input.collectedAt,
110455
- response: {
110456
- scope: scopeResult.scope,
110457
- collectedAt: input.collectedAt,
110458
- status: input.status
110459
- },
110951
+ response: ingestResponse(scopeResult.scope, input),
110460
110952
  writeResult
110461
110953
  };
110462
110954
  }
110955
+ function stampServerKeys(data, input) {
110956
+ let stamped = data;
110957
+ if (input.lineage)
110958
+ stamped = stampLineage(stamped, input.lineage);
110959
+ if (input.attribution) {
110960
+ stamped = stampWriterAttribution(stamped, input.attribution);
110961
+ }
110962
+ return stamped;
110963
+ }
110964
+ function ingestResponse(scope, input) {
110965
+ return {
110966
+ scope,
110967
+ collectedAt: input.collectedAt,
110968
+ status: input.status,
110969
+ ...input.lineage ? { lineage: { sources: input.lineage.sources } } : {}
110970
+ };
110971
+ }
110463
110972
  async function ingestBinaryDataContract(input) {
110464
110973
  const scopeResult = parseDataScopeContract(input.scopeParam);
110465
110974
  if (!scopeResult.ok)
@@ -110474,6 +110983,16 @@ async function ingestBinaryDataContract(input) {
110474
110983
  }
110475
110984
  };
110476
110985
  }
110986
+ if (isRecord3(input.metadata) && (hasReservedWriterKey(input.metadata) || hasReservedLineageKey(input.metadata))) {
110987
+ return {
110988
+ ok: false,
110989
+ status: 400,
110990
+ body: {
110991
+ error: "INVALID_BODY",
110992
+ message: "X-Vana-Metadata must not contain the reserved $lineage or $writtenBy keys"
110993
+ }
110994
+ };
110995
+ }
110477
110996
  const contentHash = await sha256Hex(input.bytes);
110478
110997
  const data = buildBinaryEnvelopeData({
110479
110998
  bytes: input.bytes,
@@ -110482,7 +111001,7 @@ async function ingestBinaryDataContract(input) {
110482
111001
  contentHash,
110483
111002
  metadata: input.metadata
110484
111003
  });
110485
- const envelope = createDataFileEnvelope(scopeResult.scope, input.collectedAt, input.attribution ? stampWriterAttribution(data, input.attribution) : data);
111004
+ const envelope = createDataFileEnvelope(scopeResult.scope, input.collectedAt, stampServerKeys(data, input));
110486
111005
  const writeResult = await input.storage.writeEnvelope(envelope);
110487
111006
  try {
110488
111007
  await writeBlockSidecars(input.storage, envelope);
@@ -110494,29 +111013,17 @@ async function ingestBinaryDataContract(input) {
110494
111013
  path: writeResult.relativePath,
110495
111014
  scope: scopeResult.scope,
110496
111015
  collectedAt: input.collectedAt,
110497
- sizeBytes: input.bytes.length
111016
+ sizeBytes: input.bytes.length,
111017
+ afterTombstoneVersion: input.afterTombstoneVersion ?? null
110498
111018
  });
110499
111019
  return {
110500
111020
  ok: true,
110501
111021
  scope: scopeResult.scope,
110502
111022
  collectedAt: input.collectedAt,
110503
- response: {
110504
- scope: scopeResult.scope,
110505
- collectedAt: input.collectedAt,
110506
- status: input.status
110507
- },
111023
+ response: ingestResponse(scopeResult.scope, input),
110508
111024
  writeResult
110509
111025
  };
110510
111026
  }
110511
- async function deleteDataScopeContract(input) {
110512
- const scopeResult = parseDataScopeContract(input.scopeParam);
110513
- if (!scopeResult.ok)
110514
- return scopeResult;
110515
- return {
110516
- ok: true,
110517
- deletedCount: await input.storage.deleteScope(scopeResult.scope)
110518
- };
110519
- }
110520
111027
  async function writeBlockSidecars(storage, envelope) {
110521
111028
  if (!storage.writeBlockManifest)
110522
111029
  return;
@@ -111102,6 +111609,548 @@ async function syncFileContract(input) {
111102
111609
  return contractOk({ fileId: input.fileId, status: "started" }, 202);
111103
111610
  }
111104
111611
 
111612
+ // ../core/dist/sync/tombstone.js
111613
+ var TOMBSTONE_DATA_HASH_LABEL = "vana.data-point.tombstone.v1";
111614
+ var TOMBSTONE_METADATA_HASH_LABEL = "vana.data-point.tombstone.metadata.v1";
111615
+ var TOMBSTONE_DATA_HASH = keccak256(stringToHex(TOMBSTONE_DATA_HASH_LABEL));
111616
+ var TOMBSTONE_METADATA_HASH = keccak256(stringToHex(TOMBSTONE_METADATA_HASH_LABEL));
111617
+ function isTombstoneRecord(record2) {
111618
+ return record2.dataHash.toLowerCase() === TOMBSTONE_DATA_HASH && record2.metadataHash.toLowerCase() === TOMBSTONE_METADATA_HASH;
111619
+ }
111620
+
111621
+ // ../core/dist/sync/scope-deletions.js
111622
+ var DEFAULT_SCOPE_DELETION_MAX_STALENESS_MS = 12e4;
111623
+ var DEFAULT_SCOPE_DELETION_GATEWAY_RETRY_MS = 15e3;
111624
+ var DEFAULT_MAX_LIVE_ENTRIES = 1e4;
111625
+ function createScopeDeletionTracker(options = {}) {
111626
+ const maxStalenessMs = options.maxStalenessMs ?? DEFAULT_SCOPE_DELETION_MAX_STALENESS_MS;
111627
+ const gatewayRetryMs = options.gatewayRetryMs ?? DEFAULT_SCOPE_DELETION_GATEWAY_RETRY_MS;
111628
+ const maxLiveEntries = options.maxLiveEntries ?? DEFAULT_MAX_LIVE_ENTRIES;
111629
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
111630
+ const nowMs = () => now().getTime();
111631
+ const deleted = /* @__PURE__ */ new Map();
111632
+ const live = /* @__PURE__ */ new Map();
111633
+ let lastFeedSyncMs = null;
111634
+ let lastGatewayFailureMs = null;
111635
+ const inflight = /* @__PURE__ */ new Map();
111636
+ function rememberLive(scope, at3) {
111637
+ deleted.delete(scope);
111638
+ live.delete(scope);
111639
+ live.set(scope, at3);
111640
+ while (live.size > maxLiveEntries) {
111641
+ const oldest = live.keys().next().value;
111642
+ if (oldest === void 0)
111643
+ break;
111644
+ live.delete(oldest);
111645
+ }
111646
+ }
111647
+ function rememberDeleted(scope, tombstone, source) {
111648
+ deleted.set(scope, {
111649
+ deletedAt: tombstone.deletedAt,
111650
+ version: normalizeVersion(tombstone.version),
111651
+ source,
111652
+ verifiedAtMs: nowMs()
111653
+ });
111654
+ live.delete(scope);
111655
+ }
111656
+ function isFresh(at3) {
111657
+ return at3 !== null && nowMs() - at3 <= maxStalenessMs;
111658
+ }
111659
+ function verdictFromRecord(scope, record2) {
111660
+ const deletedAt = deletionTimestamp(record2);
111661
+ if (deletedAt !== null) {
111662
+ const version4 = tombstoneVersion(record2);
111663
+ rememberDeleted(scope, { deletedAt, version: version4 }, "gateway");
111664
+ return {
111665
+ deleted: true,
111666
+ deletedAt,
111667
+ version: version4,
111668
+ source: "gateway",
111669
+ verified: true
111670
+ };
111671
+ }
111672
+ rememberLive(scope, nowMs());
111673
+ return { deleted: false, source: "gateway", verified: true };
111674
+ }
111675
+ async function lookup2(scope) {
111676
+ const feed = options.feed;
111677
+ const owner = options.serverOwner;
111678
+ if (!feed || !owner)
111679
+ return null;
111680
+ if (lastGatewayFailureMs !== null && nowMs() - lastGatewayFailureMs < gatewayRetryMs) {
111681
+ return null;
111682
+ }
111683
+ const pending = inflight.get(scope);
111684
+ if (pending)
111685
+ return pending;
111686
+ const request2 = (async () => {
111687
+ try {
111688
+ const record2 = await feed.getDataPoint({
111689
+ ownerAddress: owner,
111690
+ scope
111691
+ });
111692
+ lastGatewayFailureMs = null;
111693
+ return verdictFromRecord(scope, record2);
111694
+ } catch (err2) {
111695
+ lastGatewayFailureMs = nowMs();
111696
+ options.logger?.warn?.({
111697
+ scope,
111698
+ error: err2 instanceof Error ? err2.message : String(err2),
111699
+ retryAfterMs: gatewayRetryMs
111700
+ }, "Could not check gateway deletion state; serving last known state");
111701
+ return null;
111702
+ } finally {
111703
+ inflight.delete(scope);
111704
+ }
111705
+ })();
111706
+ inflight.set(scope, request2);
111707
+ return request2;
111708
+ }
111709
+ return {
111710
+ maxStalenessMs,
111711
+ markDeleted(scope, tombstone, source = "feed") {
111712
+ rememberDeleted(scope, tombstone, source);
111713
+ },
111714
+ markLive(scope) {
111715
+ rememberLive(scope, nowMs());
111716
+ },
111717
+ noteFeedSynced(at3, options2) {
111718
+ lastFeedSyncMs = (at3 ?? now()).getTime();
111719
+ if (!options2?.full)
111720
+ return;
111721
+ for (const tombstone of deleted.values()) {
111722
+ tombstone.verifiedAtMs = Math.max(tombstone.verifiedAtMs, lastFeedSyncMs);
111723
+ }
111724
+ },
111725
+ knownDeletion(scope) {
111726
+ const known = deleted.get(scope);
111727
+ return known === void 0 ? null : { deletedAt: known.deletedAt, version: known.version };
111728
+ },
111729
+ feedAgeMs() {
111730
+ return lastFeedSyncMs === null ? null : nowMs() - lastFeedSyncMs;
111731
+ },
111732
+ async resolve(scope, resolveOptions) {
111733
+ const known = deleted.get(scope);
111734
+ if (known !== void 0) {
111735
+ if (isFresh(known.verifiedAtMs)) {
111736
+ return {
111737
+ deleted: true,
111738
+ deletedAt: known.deletedAt,
111739
+ version: known.version,
111740
+ source: known.source,
111741
+ verified: true
111742
+ };
111743
+ }
111744
+ const rechecked = await lookup2(scope);
111745
+ if (rechecked !== null)
111746
+ return rechecked;
111747
+ return {
111748
+ deleted: true,
111749
+ deletedAt: known.deletedAt,
111750
+ version: known.version,
111751
+ source: known.source,
111752
+ verified: false
111753
+ };
111754
+ }
111755
+ if (isFresh(live.get(scope) ?? null)) {
111756
+ return { deleted: false, source: "gateway", verified: true };
111757
+ }
111758
+ const consult = resolveOptions?.consultGateway ?? "if-stale";
111759
+ if (consult === "if-stale" && isFresh(lastFeedSyncMs)) {
111760
+ return { deleted: false, source: "feed", verified: true };
111761
+ }
111762
+ return await lookup2(scope) ?? {
111763
+ deleted: false,
111764
+ source: "assumed-live",
111765
+ verified: false
111766
+ };
111767
+ }
111768
+ };
111769
+ }
111770
+ function deletionTimestamp(record2) {
111771
+ if (!record2)
111772
+ return null;
111773
+ if (record2.deletedAt)
111774
+ return record2.deletedAt;
111775
+ return isTombstoneRecord(record2) ? record2.addedAt : null;
111776
+ }
111777
+ function tombstoneVersion(record2) {
111778
+ return normalizeVersion(record2?.expectedVersion ?? null);
111779
+ }
111780
+ function normalizeVersion(value) {
111781
+ if (typeof value !== "string" || !/^\d+$/.test(value))
111782
+ return null;
111783
+ return BigInt(value) > 0n ? BigInt(value).toString() : null;
111784
+ }
111785
+ function isEntryCoveredByTombstone(entry, tombstone) {
111786
+ const version4 = normalizeVersion(tombstone.version);
111787
+ if (version4 === null)
111788
+ return true;
111789
+ const tombstoned = BigInt(version4);
111790
+ if (entry.dataPointId !== null)
111791
+ return BigInt(entry.version) <= tombstoned;
111792
+ const marker = entry.afterTombstoneVersion;
111793
+ if (marker === null || marker === void 0 || !Number.isSafeInteger(marker)) {
111794
+ return true;
111795
+ }
111796
+ return BigInt(marker) < tombstoned;
111797
+ }
111798
+
111799
+ // ../core/dist/sync/workers/delete.js
111800
+ var BLOB_DELETE_BATCH_SIZE = 15;
111801
+ function planBlobDeletions(storage, scope, tombstoneVersionValue) {
111802
+ const tombstone = { version: tombstoneVersionValue };
111803
+ const last2 = tombstoneVersionValue === null ? null : BigInt(tombstoneVersionValue);
111804
+ const keys = /* @__PURE__ */ new Set();
111805
+ const PAGE_SIZE = 500;
111806
+ for (let offset = 0; ; offset += PAGE_SIZE) {
111807
+ const entries = storage.listVersions(scope, { limit: PAGE_SIZE, offset });
111808
+ for (const entry of entries) {
111809
+ if (!isEntryCoveredByTombstone(entry, tombstone))
111810
+ continue;
111811
+ const version4 = BigInt(entry.version);
111812
+ if (last2 !== null && version4 >= 1n && version4 <= last2)
111813
+ continue;
111814
+ keys.add(version4.toString());
111815
+ }
111816
+ if (entries.length < PAGE_SIZE)
111817
+ break;
111818
+ }
111819
+ return {
111820
+ keys: [...keys].sort((a10, b10) => BigInt(a10) < BigInt(b10) ? -1 : 1),
111821
+ range: last2 === null || last2 < 1n ? null : { from: "1", to: last2.toString() }
111822
+ };
111823
+ }
111824
+ function takeFromRange(range, count) {
111825
+ const from = BigInt(range.from);
111826
+ const to3 = BigInt(range.to);
111827
+ const versions = [];
111828
+ let cursor = from;
111829
+ while (cursor <= to3 && versions.length < count) {
111830
+ versions.push(cursor.toString());
111831
+ cursor += 1n;
111832
+ }
111833
+ return {
111834
+ versions,
111835
+ rest: cursor <= to3 ? { from: cursor.toString(), to: range.to } : null
111836
+ };
111837
+ }
111838
+ function rangeSize(range) {
111839
+ return BigInt(range.to) - BigInt(range.from) + 1n;
111840
+ }
111841
+ function countPendingKeys(markers) {
111842
+ let total = 0n;
111843
+ for (const marker of markers) {
111844
+ if (marker.version !== null)
111845
+ total += 1n;
111846
+ else if (marker.range)
111847
+ total += rangeSize(marker.range);
111848
+ else
111849
+ total += 1n;
111850
+ }
111851
+ return total > BigInt(Number.MAX_SAFE_INTEGER) ? Number.MAX_SAFE_INTEGER : Number(total);
111852
+ }
111853
+ async function deleteScope(deps, scope) {
111854
+ const { storage, deleteData, pendingBlobDeletions, scopeDeletions, logger } = deps;
111855
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
111856
+ const dataPointId = deps.serverOwner ? computeDataPointId(deps.serverOwner, scope) : null;
111857
+ const result = {
111858
+ scope,
111859
+ dataPointId,
111860
+ durable: false,
111861
+ steps: {
111862
+ gateway: { status: "skipped", reason: "sync-disabled" },
111863
+ storage: { status: "skipped", reason: "sync-disabled" },
111864
+ local: { status: "skipped" }
111865
+ },
111866
+ pendingBlobDeletion: false
111867
+ };
111868
+ if (deleteData) {
111869
+ let tombstoneVersionValue = null;
111870
+ let tombstoneKnown = false;
111871
+ try {
111872
+ let outcome = await deleteData.tombstone(scope);
111873
+ if (outcome.status === "not-registered") {
111874
+ let registry2 = await registryState(deps, scope);
111875
+ if (registry2.status === "live") {
111876
+ outcome = await deleteData.tombstone(scope);
111877
+ registry2 = await registryState(deps, scope);
111878
+ }
111879
+ if (outcome.status === "not-registered" && registry2.status !== "deleted-or-absent") {
111880
+ throw registry2.status === "unknown" ? registry2.error : new Error("Scope was registered concurrently while it was being deleted; retry the delete");
111881
+ }
111882
+ }
111883
+ if (outcome.status === "not-registered") {
111884
+ result.steps.gateway = { status: "skipped", reason: "not-registered" };
111885
+ } else {
111886
+ tombstoneKnown = true;
111887
+ tombstoneVersionValue = outcome.version === null ? null : tombstoneVersion({ expectedVersion: outcome.version });
111888
+ result.steps.gateway = {
111889
+ status: "ok",
111890
+ ...outcome.status === "already-deleted" && {
111891
+ reason: "already-deleted"
111892
+ },
111893
+ version: outcome.version,
111894
+ deletedAt: outcome.deletedAt
111895
+ };
111896
+ scopeDeletions?.markDeleted(scope, {
111897
+ deletedAt: outcome.deletedAt ?? now().toISOString(),
111898
+ version: outcome.version
111899
+ }, "local-delete");
111900
+ }
111901
+ result.durable = true;
111902
+ } catch (err2) {
111903
+ const message = errorMessage2(err2);
111904
+ result.steps.gateway = { status: "failed", error: message };
111905
+ result.steps.storage = { status: "skipped", reason: "gateway-failed" };
111906
+ result.steps.local = { status: "skipped", reason: "gateway-failed" };
111907
+ logger.error({ scope, dataPointId, error: message }, "Gateway tombstone failed; scope NOT deleted (local copy kept so sync cannot resurrect a half-deleted scope)");
111908
+ return result;
111909
+ }
111910
+ const plan = planBlobDeletions(storage, scope, tombstoneVersionValue);
111911
+ const batch = plan.keys.slice(0, BLOB_DELETE_BATCH_SIZE);
111912
+ const leftovers = plan.keys.slice(BLOB_DELETE_BATCH_SIZE).map((version4) => ({ scope, version: version4 }));
111913
+ if (plan.range) {
111914
+ const taken = takeFromRange(plan.range, BLOB_DELETE_BATCH_SIZE - batch.length);
111915
+ batch.push(...taken.versions);
111916
+ if (taken.rest)
111917
+ leftovers.push({ scope, version: null, range: taken.rest });
111918
+ }
111919
+ if (tombstoneKnown && tombstoneVersionValue === null) {
111920
+ leftovers.push({ scope, version: null });
111921
+ }
111922
+ const storageStep = await deleteBlobKeys({ deleteData, pendingBlobDeletions, logger }, scope, batch, leftovers);
111923
+ result.steps.storage = storageStep.step;
111924
+ result.pendingBlobDeletion = storageStep.pending > 0;
111925
+ }
111926
+ try {
111927
+ const deletedCount = await storage.deleteScope(scope);
111928
+ result.steps.local = { status: "ok", deletedCount };
111929
+ } catch (err2) {
111930
+ const message = errorMessage2(err2);
111931
+ result.steps.local = { status: "failed", error: message };
111932
+ logger.error({ scope, error: message }, "Local scope deletion failed");
111933
+ }
111934
+ logger.info({
111935
+ scope,
111936
+ dataPointId,
111937
+ durable: result.durable,
111938
+ gateway: result.steps.gateway.status,
111939
+ storage: result.steps.storage.status,
111940
+ local: result.steps.local.status
111941
+ }, "Scope deletion finished");
111942
+ return result;
111943
+ }
111944
+ async function deleteBlobKeys(deps, scope, batch, leftovers) {
111945
+ const { deleteData, pendingBlobDeletions, logger } = deps;
111946
+ let outcome;
111947
+ try {
111948
+ outcome = batch.length > 0 && deleteData ? await deleteData.deleteBlobVersions(scope, batch) : { deleted: [], missing: [], failed: [] };
111949
+ } catch (err2) {
111950
+ outcome = {
111951
+ deleted: [],
111952
+ missing: [],
111953
+ failed: batch.map((version4) => ({ version: version4, error: errorMessage2(err2) }))
111954
+ };
111955
+ }
111956
+ const completed = [...outcome.deleted, ...outcome.missing].map((version4) => ({ scope, version: version4 }));
111957
+ const remaining = [
111958
+ ...outcome.failed.map(({ version: version4 }) => ({ scope, version: version4 })),
111959
+ ...leftovers
111960
+ ];
111961
+ const remainingKeys = countPendingKeys(remaining);
111962
+ let recorded = remainingKeys;
111963
+ if (pendingBlobDeletions) {
111964
+ try {
111965
+ if (completed.length > 0)
111966
+ await pendingBlobDeletions.remove(completed);
111967
+ if (remaining.length > 0)
111968
+ await pendingBlobDeletions.add(remaining);
111969
+ } catch (markerErr) {
111970
+ recorded = 0;
111971
+ logger.error({ scope, error: errorMessage2(markerErr), keys: remainingKeys }, "Could not record pending blob deletion markers");
111972
+ }
111973
+ } else if (remaining.length > 0) {
111974
+ recorded = 0;
111975
+ logger.error({ scope, keys: remainingKeys }, "Blob deletions left unfinished with no marker store to retry them");
111976
+ }
111977
+ const counts = {
111978
+ blobsDeleted: outcome.deleted.length,
111979
+ blobsMissing: outcome.missing.length,
111980
+ blobsPending: remainingKeys
111981
+ };
111982
+ if (outcome.failed.length > 0) {
111983
+ const first = outcome.failed[0];
111984
+ logger.warn({
111985
+ scope,
111986
+ failed: outcome.failed.length,
111987
+ pending: recorded,
111988
+ error: first.error
111989
+ }, "Storage blob deletion failed for some keys after gateway tombstone; will retry");
111990
+ return {
111991
+ step: {
111992
+ status: "failed",
111993
+ error: `${outcome.failed.length} blob delete(s) failed: ${first.error}`,
111994
+ ...counts
111995
+ },
111996
+ pending: recorded
111997
+ };
111998
+ }
111999
+ if (remaining.length > 0) {
112000
+ logger.info({ scope, ...counts }, "Storage blob deletion continues on later sync cycles (rate-limited batch)");
112001
+ return { step: { status: "deferred", ...counts }, pending: recorded };
112002
+ }
112003
+ return { step: { status: "ok", ...counts }, pending: 0 };
112004
+ }
112005
+ async function retryPendingBlobDeletions(deps) {
112006
+ const { deleteData, pendingBlobDeletions, logger } = deps;
112007
+ const result = {
112008
+ completed: [],
112009
+ superseded: [],
112010
+ failed: [],
112011
+ remaining: 0
112012
+ };
112013
+ if (!deleteData || !pendingBlobDeletions)
112014
+ return result;
112015
+ let markers = await pendingBlobDeletions.list();
112016
+ if (markers.length === 0)
112017
+ return result;
112018
+ for (const marker of markers.filter((key) => key.version === null && !key.range)) {
112019
+ const registry2 = await registryState(deps, marker.scope);
112020
+ if (registry2.status === "unknown") {
112021
+ result.failed.push({
112022
+ scope: marker.scope,
112023
+ version: null,
112024
+ error: registry2.error.message
112025
+ });
112026
+ continue;
112027
+ }
112028
+ if (registry2.status === "live") {
112029
+ await pendingBlobDeletions.remove([marker]);
112030
+ result.superseded.push(marker.scope);
112031
+ logger.warn({
112032
+ scope: marker.scope,
112033
+ dataPointId: registry2.record.id,
112034
+ version: registry2.record.expectedVersion
112035
+ }, "Scope was re-added after its tombstone; dropping the unexpanded blob deletion marker so the live version's ciphertext survives");
112036
+ continue;
112037
+ }
112038
+ const plan = planBlobDeletions(deps.storage ?? { listVersions: () => [] }, marker.scope, registry2.status === "deleted" ? registry2.version : null);
112039
+ const expanded = plan.keys.map((version4) => ({
112040
+ scope: marker.scope,
112041
+ version: version4
112042
+ }));
112043
+ if (plan.range) {
112044
+ expanded.push({ scope: marker.scope, version: null, range: plan.range });
112045
+ }
112046
+ await pendingBlobDeletions.remove([marker]);
112047
+ await pendingBlobDeletions.add(expanded);
112048
+ }
112049
+ markers = await pendingBlobDeletions.list();
112050
+ let budget = BLOB_DELETE_BATCH_SIZE;
112051
+ const byScope = /* @__PURE__ */ new Map();
112052
+ const exactOrigin = /* @__PURE__ */ new Set();
112053
+ const advancedRanges = [];
112054
+ const enqueue = (scope, version4) => {
112055
+ const versions = byScope.get(scope) ?? [];
112056
+ versions.push(version4);
112057
+ byScope.set(scope, versions);
112058
+ };
112059
+ for (const marker of markers) {
112060
+ if (budget === 0)
112061
+ break;
112062
+ if (marker.version !== null) {
112063
+ enqueue(marker.scope, marker.version);
112064
+ exactOrigin.add(`${marker.scope}\0${marker.version}`);
112065
+ budget -= 1;
112066
+ }
112067
+ }
112068
+ for (const marker of markers) {
112069
+ if (budget === 0)
112070
+ break;
112071
+ if (marker.version === null && marker.range) {
112072
+ const taken = takeFromRange(marker.range, budget);
112073
+ for (const version4 of taken.versions)
112074
+ enqueue(marker.scope, version4);
112075
+ budget -= taken.versions.length;
112076
+ advancedRanges.push({
112077
+ old: marker,
112078
+ next: taken.rest ? { scope: marker.scope, version: null, range: taken.rest } : null
112079
+ });
112080
+ }
112081
+ }
112082
+ for (const [scope, versions] of byScope) {
112083
+ let outcome;
112084
+ try {
112085
+ outcome = await deleteData.deleteBlobVersions(scope, versions);
112086
+ } catch (err2) {
112087
+ const message = errorMessage2(err2);
112088
+ outcome = {
112089
+ deleted: [],
112090
+ missing: [],
112091
+ failed: versions.map((version4) => ({ version: version4, error: message }))
112092
+ };
112093
+ }
112094
+ const completed = [...outcome.deleted, ...outcome.missing].filter((version4) => exactOrigin.has(`${scope}\0${version4}`)).map((version4) => ({ scope, version: version4 }));
112095
+ if (completed.length > 0)
112096
+ await pendingBlobDeletions.remove(completed);
112097
+ result.completed.push(...[...outcome.deleted, ...outcome.missing].map((version4) => ({ scope, version: version4 })));
112098
+ const failedFromRange = outcome.failed.filter(({ version: version4 }) => !exactOrigin.has(`${scope}\0${version4}`)).map(({ version: version4 }) => ({ scope, version: version4 }));
112099
+ if (failedFromRange.length > 0) {
112100
+ await pendingBlobDeletions.add(failedFromRange);
112101
+ }
112102
+ for (const failure of outcome.failed) {
112103
+ result.failed.push({ scope, ...failure });
112104
+ }
112105
+ if (outcome.deleted.length + outcome.missing.length > 0) {
112106
+ logger.info({
112107
+ scope,
112108
+ deleted: outcome.deleted.length,
112109
+ missing: outcome.missing.length
112110
+ }, "Completed pending blob deletions");
112111
+ }
112112
+ if (outcome.failed.length > 0) {
112113
+ logger.warn({
112114
+ scope,
112115
+ failed: outcome.failed.length,
112116
+ error: outcome.failed[0].error
112117
+ }, "Pending blob deletion failed again");
112118
+ }
112119
+ }
112120
+ for (const { old, next } of advancedRanges) {
112121
+ await pendingBlobDeletions.remove([old]);
112122
+ if (next)
112123
+ await pendingBlobDeletions.add([next]);
112124
+ }
112125
+ result.remaining = (await pendingBlobDeletions.list()).length;
112126
+ return result;
112127
+ }
112128
+ async function registryState(deps, scope) {
112129
+ if (!deps.dataPointFeed || !deps.serverOwner) {
112130
+ return { status: "deleted-or-absent" };
112131
+ }
112132
+ let record2;
112133
+ try {
112134
+ record2 = await deps.dataPointFeed.getDataPoint({
112135
+ ownerAddress: deps.serverOwner,
112136
+ scope
112137
+ });
112138
+ } catch (err2) {
112139
+ return {
112140
+ status: "unknown",
112141
+ error: err2 instanceof Error ? err2 : new Error(String(err2))
112142
+ };
112143
+ }
112144
+ if (record2 === null)
112145
+ return { status: "deleted-or-absent" };
112146
+ if (deletionTimestamp(record2) === null)
112147
+ return { status: "live", record: record2 };
112148
+ return { status: "deleted", version: tombstoneVersion(record2) };
112149
+ }
112150
+ function errorMessage2(err2) {
112151
+ return err2 instanceof Error ? err2.message : String(err2);
112152
+ }
112153
+
111105
112154
  // ../core/dist/payment/x402.js
111106
112155
  function generateRecordId() {
111107
112156
  const bytes2 = new Uint8Array(32);
@@ -111582,6 +112631,51 @@ async function handleX402Cycle(input) {
111582
112631
  function collectedAt(now) {
111583
112632
  return now().toISOString().replace(/\.\d{3}Z$/, "Z");
111584
112633
  }
112634
+ async function resolveReadDeletion(deps, scope, entry) {
112635
+ if (!deps.scopeDeletions)
112636
+ return null;
112637
+ const verdict = await deps.scopeDeletions.resolve(scope, {
112638
+ consultGateway: entry ? "if-stale" : "always"
112639
+ });
112640
+ if (!verdict.deleted)
112641
+ return null;
112642
+ if (entry && !isEntryCoveredByTombstone(entry, verdict)) {
112643
+ return null;
112644
+ }
112645
+ return {
112646
+ scope,
112647
+ dataPointId: deps.serverOwner ? computeDataPointId(deps.serverOwner, scope) : null,
112648
+ deletedAt: verdict.deletedAt
112649
+ };
112650
+ }
112651
+ async function assertScopeNotDeleted(deps, scope, entry) {
112652
+ const deletion = await resolveReadDeletion(deps, scope, entry);
112653
+ if (deletion)
112654
+ throw new DataDeletedError(deletion);
112655
+ }
112656
+ function discoveryVisibility(deps) {
112657
+ if (!deps.scopeDeletions)
112658
+ return void 0;
112659
+ return async (scope, entry) => await resolveReadDeletion(deps, scope, entry) === null;
112660
+ }
112661
+ async function ingestTombstoneMarker(deps, scope) {
112662
+ if (!deps.scopeDeletions)
112663
+ return null;
112664
+ const verdict = await deps.scopeDeletions.resolve(scope);
112665
+ if (!verdict.deleted || verdict.version === null)
112666
+ return null;
112667
+ const version4 = Number(verdict.version);
112668
+ return Number.isSafeInteger(version4) ? version4 : null;
112669
+ }
112670
+ function apiLoggerAsLogger(logger) {
112671
+ const noop = () => void 0;
112672
+ return {
112673
+ debug: (payload, message) => (logger?.debug ?? noop)(payload, message ?? ""),
112674
+ info: (payload, message) => (logger?.info ?? noop)(payload, message ?? ""),
112675
+ warn: (payload, message) => (logger?.warn ?? noop)(payload, message ?? ""),
112676
+ error: (payload, message) => (logger?.error ?? noop)(payload, message ?? "")
112677
+ };
112678
+ }
111585
112679
  function notifyNewData(syncManager) {
111586
112680
  if (!syncManager)
111587
112681
  return;
@@ -111613,6 +112707,30 @@ function reportPersonalServerReadFulfillment(deps, event) {
111613
112707
  warnReadFulfillmentReporterFailed(deps, event, err2);
111614
112708
  }
111615
112709
  }
112710
+ async function prepareWriteLineage(deps, scope, field) {
112711
+ if (field === void 0 || field === null)
112712
+ return void 0;
112713
+ return prepareLineage({
112714
+ scope,
112715
+ field,
112716
+ serverOwner: deps.serverOwner,
112717
+ storage: deps.storage,
112718
+ gateway: deps.lineageGateway,
112719
+ now: deps.now ?? (() => /* @__PURE__ */ new Date())
112720
+ });
112721
+ }
112722
+ function resolveLineageGrantView(authResult) {
112723
+ if (authResult === void 0 || authResult.grantId === "owner" || authResult.grantId === "policy-bypass") {
112724
+ return { grantId: void 0 };
112725
+ }
112726
+ const grantId = authResult.grantId;
112727
+ if (typeof grantId !== "string" || grantId === "" || grantId === "unknown") {
112728
+ throw new GrantRequiredError({
112729
+ reason: "a lineage read by a builder needs a resolved grant"
112730
+ });
112731
+ }
112732
+ return { grantId };
112733
+ }
111616
112734
  async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111617
112735
  return withApiErrors(async () => {
111618
112736
  const url2 = new URL(request2.url);
@@ -111625,7 +112743,8 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111625
112743
  storage: deps.storage,
111626
112744
  scopePrefix: url2.searchParams.get("scopePrefix") ?? void 0,
111627
112745
  limit: normalizeLimit2(url2.searchParams.get("limit"), 20),
111628
- offset: normalizeLimit2(url2.searchParams.get("offset"), 0)
112746
+ offset: normalizeLimit2(url2.searchParams.get("offset"), 0),
112747
+ isVisible: discoveryVisibility(deps)
111629
112748
  });
111630
112749
  return jsonResponse(result.response);
111631
112750
  }
@@ -111634,16 +112753,78 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111634
112753
  if (request2.method !== "GET")
111635
112754
  return methodNotAllowed();
111636
112755
  await deps.auth.authorizeBuilderList(request2);
111637
- const result = listDataVersionsContract({
112756
+ const result = await listDataVersionsContract({
111638
112757
  storage: deps.storage,
111639
112758
  scopeParam: decodePathPart(parts[0]),
111640
112759
  limit: normalizeLimit2(url2.searchParams.get("limit"), 20),
111641
- offset: normalizeLimit2(url2.searchParams.get("offset"), 0)
112760
+ offset: normalizeLimit2(url2.searchParams.get("offset"), 0),
112761
+ isVisible: discoveryVisibility(deps)
111642
112762
  });
111643
112763
  if (!result.ok)
111644
112764
  return contractErrorResponse(result);
112765
+ if (result.response.total === 0) {
112766
+ await assertScopeNotDeleted(deps, result.scope, void 0);
112767
+ }
111645
112768
  return jsonResponse(result.response);
111646
112769
  }
112770
+ if ((parts.length === 2 || parts.length === 3) && parts[1] === "lineage") {
112771
+ if (request2.method !== "GET")
112772
+ return methodNotAllowed();
112773
+ const scopeResult = parseDataScopeContract(decodePathPart(parts[0]));
112774
+ if (!scopeResult.ok)
112775
+ return contractErrorResponse(scopeResult);
112776
+ if (url2.searchParams.has("version")) {
112777
+ return errorResponse(400, "INVALID_VERSION", "version is a path segment (/v1/data/:scope/lineage/:version), not a query parameter");
112778
+ }
112779
+ if (url2.search.length > 0) {
112780
+ return errorResponse(400, "INVALID_QUERY", "lineage reads take no query parameters; the version is a path segment and the grant view is the signed grantId claim");
112781
+ }
112782
+ const version4 = parts.length === 3 ? decodePathPart(parts[2]) : void 0;
112783
+ if (version4 !== void 0 && !/^[1-9]\d*$/.test(version4)) {
112784
+ return errorResponse(400, "INVALID_VERSION", "version must be a positive decimal integer");
112785
+ }
112786
+ const authResult = await deps.auth.authorizeBuilderRead({
112787
+ request: request2,
112788
+ scope: scopeResult.scope,
112789
+ grantId: selectedGrantId(request2, url2)
112790
+ });
112791
+ if (!deps.serverOwner) {
112792
+ throw new ServerNotConfiguredError({
112793
+ reason: "serverOwner is required to resolve the data point id"
112794
+ });
112795
+ }
112796
+ if (!deps.lineageGateway)
112797
+ throw new LineageUnavailableError();
112798
+ const { grantId } = resolveLineageGrantView(authResult);
112799
+ let result;
112800
+ try {
112801
+ result = await deps.lineageGateway.getLineage({
112802
+ dataPointId: computeDataPointId(deps.serverOwner, scopeResult.scope),
112803
+ version: version4,
112804
+ grantId
112805
+ });
112806
+ } catch (err2) {
112807
+ if (err2 instanceof ProtocolError)
112808
+ throw err2;
112809
+ throw new LineageGatewayError({
112810
+ status: 0,
112811
+ body: { error: err2 instanceof Error ? err2.message : String(err2) }
112812
+ });
112813
+ }
112814
+ if (!result.ok) {
112815
+ if (result.status === 404) {
112816
+ return errorResponse(404, "NOT_FOUND", version4 ? `Scope "${scopeResult.scope}" has no registered version ${version4}` : `Scope "${scopeResult.scope}" is not registered at the gateway`);
112817
+ }
112818
+ if (result.status === 403) {
112819
+ throw new ProtocolError(403, "LINEAGE_FORBIDDEN", "The gateway refused the lineage view for this grant", { gateway: result.body });
112820
+ }
112821
+ throw new LineageGatewayError({
112822
+ status: result.status,
112823
+ body: result.body
112824
+ });
112825
+ }
112826
+ return jsonResponse({ data: result.data, proof: result.proof });
112827
+ }
111647
112828
  if (parts.length !== 1)
111648
112829
  return notFound();
111649
112830
  const scopeParam = decodePathPart(parts[0]);
@@ -111665,6 +112846,7 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111665
112846
  fileId: url2.searchParams.get("fileId") ?? selectedEntry?.fileId ?? void 0,
111666
112847
  at: url2.searchParams.get("at") ?? void 0
111667
112848
  });
112849
+ await assertScopeNotDeleted(deps, scopeResult.scope, selectedEntry);
111668
112850
  const isOwnerSignal = authResult?.grantId === "owner" || authResult?.grantId === "policy-bypass";
111669
112851
  const builder = authResult?.builder;
111670
112852
  const resolvedGrantId = !isOwnerSignal && authResult?.grantId ? authResult.grantId : void 0;
@@ -111719,8 +112901,12 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111719
112901
  fileId: url2.searchParams.get("fileId") ?? void 0,
111720
112902
  at: url2.searchParams.get("at") ?? void 0
111721
112903
  });
111722
- if (!result.ok)
112904
+ if (!result.ok) {
112905
+ if (result.status === 404) {
112906
+ await assertScopeNotDeleted(deps, scopeResult.scope, void 0);
112907
+ }
111723
112908
  return contractErrorResponse(result);
112909
+ }
111724
112910
  const logId = deps.createLogId?.() ?? crypto.randomUUID();
111725
112911
  const timestamp = (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
111726
112912
  const ipAddress = request2.headers.get("x-forwarded-for") ?? request2.headers.get("x-real-ip") ?? "unknown";
@@ -111800,6 +112986,7 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111800
112986
  return failWrite(contractErrorResponse(scopeResult));
111801
112987
  const collectedAtValue = collectedAt(deps.now ?? (() => /* @__PURE__ */ new Date()));
111802
112988
  const status2 = deps.syncManager ? "syncing" : "stored";
112989
+ const afterTombstoneVersion = await ingestTombstoneMarker(deps, scopeResult.scope);
111803
112990
  const logBuilderWrite = async () => {
111804
112991
  if (!writeAuth)
111805
112992
  return;
@@ -111825,16 +113012,20 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111825
113012
  };
111826
113013
  if (!isJsonContentType(request2)) {
111827
113014
  const bytes2 = new Uint8Array(await request2.arrayBuffer());
113015
+ const metadata = parseMetadataHeader(request2.headers.get("x-vana-metadata"));
113016
+ const lineage2 = await prepareWriteLineage(deps, scopeResult.scope, extractLineageField(metadata));
111828
113017
  const result2 = await ingestBinaryDataContract({
111829
113018
  storage: deps.storage,
111830
113019
  scopeParam: scopeResult.scope,
111831
113020
  bytes: bytes2,
111832
113021
  mimeType: binaryMimeType(request2),
111833
113022
  filename: binaryFilename(request2),
111834
- metadata: parseMetadataHeader(request2.headers.get("x-vana-metadata")),
113023
+ metadata,
111835
113024
  collectedAt: collectedAtValue,
111836
113025
  status: status2,
111837
- attribution: writeAuth?.attribution
113026
+ attribution: writeAuth?.attribution,
113027
+ lineage: lineage2,
113028
+ afterTombstoneVersion
111838
113029
  });
111839
113030
  if (!result2.ok)
111840
113031
  return failWrite(contractErrorResponse(result2));
@@ -111854,13 +113045,16 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111854
113045
  const parsed = await parseJsonObjectBody(request2, "Request body must be valid JSON");
111855
113046
  if (!parsed.ok)
111856
113047
  return failWrite(contractResponse(parsed.result));
113048
+ const lineage = await prepareWriteLineage(deps, scopeResult.scope, extractLineageField(parsed.body));
111857
113049
  const result = await ingestDataContract({
111858
113050
  storage: deps.storage,
111859
113051
  scopeParam: scopeResult.scope,
111860
113052
  body: parsed.body,
111861
113053
  collectedAt: collectedAtValue,
111862
113054
  status: status2,
111863
- attribution: writeAuth?.attribution
113055
+ attribution: writeAuth?.attribution,
113056
+ lineage,
113057
+ afterTombstoneVersion
111864
113058
  });
111865
113059
  if (!result.ok)
111866
113060
  return failWrite(contractErrorResponse(result));
@@ -111889,22 +113083,54 @@ async function handlePersonalServerDataRequest(request2, deps, options = {}) {
111889
113083
  }
111890
113084
  if (request2.method === "DELETE") {
111891
113085
  await deps.auth.authorizeOwner(request2);
113086
+ const cascade = url2.searchParams.get("cascade");
113087
+ if (cascade !== null && cascade !== "lineage") {
113088
+ throw new InvalidCascadeError({ cascade });
113089
+ }
111892
113090
  const parsed = parseDataScopeContract(scopeParam);
111893
- if (parsed.ok && deps.syncManager?.deleteScopeRemote) {
111894
- try {
111895
- await deps.syncManager.deleteScopeRemote(parsed.scope);
111896
- } catch (err2) {
111897
- deps.logger?.info?.({ scope: scopeParam, error: err2.message }, "Remote scope deletion failed; proceeding with local delete");
111898
- }
113091
+ if (!parsed.ok)
113092
+ return contractErrorResponse(parsed);
113093
+ if (cascade === "lineage") {
113094
+ throw new LineageCascadeUnavailableError({ scope: parsed.scope });
111899
113095
  }
111900
- const result = await deleteDataScopeContract({
113096
+ const result = deps.syncManager?.deleteScope ? await deps.syncManager.deleteScope(parsed.scope) : await deleteScope({
111901
113097
  storage: deps.storage,
111902
- scopeParam
111903
- });
111904
- if (!result.ok)
111905
- return contractErrorResponse(result);
111906
- deps.logger?.info?.({ scope: scopeParam, deletedCount: result.deletedCount }, "Scope deleted");
111907
- return new Response(null, { status: 204 });
113098
+ serverOwner: deps.serverOwner,
113099
+ deleteData: null,
113100
+ logger: apiLoggerAsLogger(deps.logger)
113101
+ }, parsed.scope);
113102
+ if (result.steps.gateway.status === "failed") {
113103
+ throw new DeleteTombstoneFailedError({
113104
+ scope: parsed.scope,
113105
+ result
113106
+ });
113107
+ }
113108
+ try {
113109
+ await deps.accessLogWriter.write({
113110
+ logId: deps.createLogId?.() ?? crypto.randomUUID(),
113111
+ grantId: "owner",
113112
+ builder: deps.serverOwner ?? "owner",
113113
+ action: "delete",
113114
+ scope: parsed.scope,
113115
+ timestamp: (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
113116
+ ipAddress: request2.headers.get("x-forwarded-for") ?? request2.headers.get("x-real-ip") ?? "unknown",
113117
+ userAgent: request2.headers.get("user-agent") ?? "unknown"
113118
+ });
113119
+ } catch (err2) {
113120
+ deps.logger?.warn?.({
113121
+ scope: parsed.scope,
113122
+ error: err2 instanceof Error ? err2.message : String(err2)
113123
+ }, "Delete access-log entry failed; scope already deleted");
113124
+ }
113125
+ deps.logger?.info?.({
113126
+ scope: parsed.scope,
113127
+ durable: result.durable,
113128
+ gateway: result.steps.gateway.status,
113129
+ storage: result.steps.storage.status,
113130
+ local: result.steps.local.status,
113131
+ deletedCount: result.steps.local.deletedCount
113132
+ }, "Scope deleted");
113133
+ return jsonResponse(result, { status: 200 });
111908
113134
  }
111909
113135
  return methodNotAllowed();
111910
113136
  });
@@ -112214,6 +113440,16 @@ var McpDataReadError = class extends Error {
112214
113440
  };
112215
113441
  function createMcpDataReadClient(options) {
112216
113442
  const basePath = options.basePath ?? "/v1/data";
113443
+ async function assertScopeReadable(scope, entry) {
113444
+ try {
113445
+ await assertScopeNotDeleted(options.dataApiDeps, scope, entry);
113446
+ } catch (err2) {
113447
+ if (err2 instanceof ProtocolError) {
113448
+ throw new McpDataReadError(err2.code, err2.toJSON());
113449
+ }
113450
+ throw err2;
113451
+ }
113452
+ }
112217
113453
  async function authorizeScopeRead(params) {
112218
113454
  const safeScope = encodeURIComponent(params.scope);
112219
113455
  const signingUri = `${basePath}/${safeScope}`;
@@ -112301,6 +113537,9 @@ function createMcpDataReadClient(options) {
112301
113537
  const entry = storage.findEntry({ scope });
112302
113538
  if (!entry)
112303
113539
  return null;
113540
+ if (await resolveReadDeletion(options.dataApiDeps, scope, entry)) {
113541
+ return null;
113542
+ }
112304
113543
  const hasBlocks = typeof storage.hasScopeBlocks === "function" ? await storage.hasScopeBlocks(scope, entry.collectedAt) : false;
112305
113544
  return {
112306
113545
  scope,
@@ -112329,6 +113568,7 @@ function createMcpDataReadClient(options) {
112329
113568
  message: `No data found for scope "${scope}"`
112330
113569
  });
112331
113570
  }
113571
+ await assertScopeReadable(scope, selectedEntry);
112332
113572
  const { request: request2, authResult } = await authorizeScopeRead({
112333
113573
  scope,
112334
113574
  grantId,
@@ -112386,6 +113626,7 @@ function createMcpDataReadClient(options) {
112386
113626
  message: `No data found for scope "${scope}"`
112387
113627
  });
112388
113628
  }
113629
+ await assertScopeReadable(scope, selectedEntry);
112389
113630
  const { request: request2, authResult } = await authorizeScopeRead({
112390
113631
  scope,
112391
113632
  grantId,
@@ -116049,15 +117290,15 @@ var makeIssue = (params) => {
116049
117290
  message: issueData.message
116050
117291
  };
116051
117292
  }
116052
- let errorMessage2 = "";
117293
+ let errorMessage3 = "";
116053
117294
  const maps = errorMaps.filter((m10) => !!m10).slice().reverse();
116054
117295
  for (const map2 of maps) {
116055
- errorMessage2 = map2(fullIssue, { data, defaultError: errorMessage2 }).message;
117296
+ errorMessage3 = map2(fullIssue, { data, defaultError: errorMessage3 }).message;
116056
117297
  }
116057
117298
  return {
116058
117299
  ...issueData,
116059
117300
  path: fullPath,
116060
- message: errorMessage2
117301
+ message: errorMessage3
116061
117302
  };
116062
117303
  };
116063
117304
  function addIssueToContext(ctx, issueData) {
@@ -121337,19 +122578,19 @@ var getRefs = (options) => {
121337
122578
  };
121338
122579
 
121339
122580
  // ../../node_modules/zod-to-json-schema/dist/esm/errorMessages.js
121340
- function addErrorMessage(res, key, errorMessage2, refs) {
122581
+ function addErrorMessage(res, key, errorMessage3, refs) {
121341
122582
  if (!refs?.errorMessages)
121342
122583
  return;
121343
- if (errorMessage2) {
122584
+ if (errorMessage3) {
121344
122585
  res.errorMessage = {
121345
122586
  ...res.errorMessage,
121346
- [key]: errorMessage2
122587
+ [key]: errorMessage3
121347
122588
  };
121348
122589
  }
121349
122590
  }
121350
- function setResponseValueAndErrors(res, key, value, errorMessage2, refs) {
122591
+ function setResponseValueAndErrors(res, key, value, errorMessage3, refs) {
121351
122592
  res[key] = value;
121352
- addErrorMessage(res, key, errorMessage2, refs);
122593
+ addErrorMessage(res, key, errorMessage3, refs);
121353
122594
  }
121354
122595
 
121355
122596
  // ../../node_modules/zod-to-json-schema/dist/esm/getRelativePath.js
@@ -122660,8 +123901,8 @@ var Protocol = class {
122660
123901
  if (queuedMessage.type === "response") {
122661
123902
  resolver(message);
122662
123903
  } else {
122663
- const errorMessage2 = message;
122664
- const error51 = new McpError(errorMessage2.error.code, errorMessage2.error.message, errorMessage2.error.data);
123904
+ const errorMessage3 = message;
123905
+ const error51 = new McpError(errorMessage3.error.code, errorMessage3.error.message, errorMessage3.error.data);
122665
123906
  resolver(error51);
122666
123907
  }
122667
123908
  } else {
@@ -123961,23 +125202,23 @@ var Server = class extends Protocol {
123961
125202
  const wrappedHandler = async (request2, extra) => {
123962
125203
  const validatedRequest = safeParse3(CallToolRequestSchema, request2);
123963
125204
  if (!validatedRequest.success) {
123964
- const errorMessage2 = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
123965
- throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${errorMessage2}`);
125205
+ const errorMessage3 = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
125206
+ throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${errorMessage3}`);
123966
125207
  }
123967
125208
  const { params } = validatedRequest.data;
123968
125209
  const result = await Promise.resolve(handler(request2, extra));
123969
125210
  if (params.task) {
123970
125211
  const taskValidationResult = safeParse3(CreateTaskResultSchema, result);
123971
125212
  if (!taskValidationResult.success) {
123972
- const errorMessage2 = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
123973
- throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage2}`);
125213
+ const errorMessage3 = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
125214
+ throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage3}`);
123974
125215
  }
123975
125216
  return taskValidationResult.data;
123976
125217
  }
123977
125218
  const validationResult = safeParse3(CallToolResultSchema, result);
123978
125219
  if (!validationResult.success) {
123979
- const errorMessage2 = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
123980
- throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call result: ${errorMessage2}`);
125220
+ const errorMessage3 = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
125221
+ throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call result: ${errorMessage3}`);
123981
125222
  }
123982
125223
  return validationResult.data;
123983
125224
  };
@@ -124693,12 +125934,12 @@ var McpServer = class {
124693
125934
  * @param errorMessage - The error message.
124694
125935
  * @returns The tool error result.
124695
125936
  */
124696
- createToolError(errorMessage2) {
125937
+ createToolError(errorMessage3) {
124697
125938
  return {
124698
125939
  content: [
124699
125940
  {
124700
125941
  type: "text",
124701
- text: errorMessage2
125942
+ text: errorMessage3
124702
125943
  }
124703
125944
  ],
124704
125945
  isError: true
@@ -124716,8 +125957,8 @@ var McpServer = class {
124716
125957
  const parseResult = await safeParseAsync3(schemaToParse, args);
124717
125958
  if (!parseResult.success) {
124718
125959
  const error51 = "error" in parseResult ? parseResult.error : "Unknown error";
124719
- const errorMessage2 = getParseErrorMessage(error51);
124720
- throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage2}`);
125960
+ const errorMessage3 = getParseErrorMessage(error51);
125961
+ throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage3}`);
124721
125962
  }
124722
125963
  return parseResult.data;
124723
125964
  }
@@ -124741,8 +125982,8 @@ var McpServer = class {
124741
125982
  const parseResult = await safeParseAsync3(outputObj, result.structuredContent);
124742
125983
  if (!parseResult.success) {
124743
125984
  const error51 = "error" in parseResult ? parseResult.error : "Unknown error";
124744
- const errorMessage2 = getParseErrorMessage(error51);
124745
- throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${errorMessage2}`);
125985
+ const errorMessage3 = getParseErrorMessage(error51);
125986
+ throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${errorMessage3}`);
124746
125987
  }
124747
125988
  }
124748
125989
  /**
@@ -124954,8 +126195,8 @@ var McpServer = class {
124954
126195
  const parseResult = await safeParseAsync3(argsObj, request2.params.arguments);
124955
126196
  if (!parseResult.success) {
124956
126197
  const error51 = "error" in parseResult ? parseResult.error : "Unknown error";
124957
- const errorMessage2 = getParseErrorMessage(error51);
124958
- throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${request2.params.name}: ${errorMessage2}`);
126198
+ const errorMessage3 = getParseErrorMessage(error51);
126199
+ throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${request2.params.name}: ${errorMessage3}`);
124959
126200
  }
124960
126201
  const args = parseResult.data;
124961
126202
  const cb2 = prompt.callback;
@@ -127051,6 +128292,7 @@ function createPsLiteRuntime(options) {
127051
128292
  accessLogWriter,
127052
128293
  readFulfillmentReporter: options.readFulfillmentReporter,
127053
128294
  syncManager: options.syncManager ?? null,
128295
+ scopeDeletions: options.scopeDeletions,
127054
128296
  now,
127055
128297
  createLogId,
127056
128298
  // x402 payment enforcement for builder reads. Only engages with a
@@ -127070,7 +128312,8 @@ function createPsLiteRuntime(options) {
127070
128312
  // recordDataAccess attributes the read to the correct owner; if
127071
128313
  // serverOwner is absent the accessRecord is safely omitted.
127072
128314
  serverOwner: options.serverOwner,
127073
- serverSigner: x402ServerSigner
128315
+ serverSigner: x402ServerSigner,
128316
+ lineageGateway: options.lineageGateway
127074
128317
  }, { basePath: dataPrefix });
127075
128318
  }
127076
128319
  if (url2.pathname.startsWith("/auth/device")) {
@@ -127526,6 +128769,45 @@ var OrphanedEntryError = class extends Error {
127526
128769
  this.name = "OrphanedEntryError";
127527
128770
  }
127528
128771
  };
128772
+ var DeletedScopeEntryError = class extends Error {
128773
+ constructor(path, deletedAt) {
128774
+ super(`Dropped local entry for a scope deleted at ${deletedAt}: ${path}`);
128775
+ this.name = "DeletedScopeEntryError";
128776
+ }
128777
+ };
128778
+ async function dropIfCoveredByDeletion(deps, entry, tombstone, deletedAt, uploaded) {
128779
+ const version4 = tombstoneVersion(tombstone);
128780
+ if (!isEntryCoveredByTombstone(entry, { version: version4 }))
128781
+ return;
128782
+ if (uploaded) {
128783
+ try {
128784
+ await deps.storageAdapter.delete(uploaded.url);
128785
+ } catch (err2) {
128786
+ const message = err2 instanceof Error ? err2.message : String(err2);
128787
+ if (deps.pendingBlobDeletions) {
128788
+ await deps.pendingBlobDeletions.add([
128789
+ { scope: entry.scope, version: String(entry.version) }
128790
+ ]);
128791
+ }
128792
+ deps.logger.warn({
128793
+ scope: entry.scope,
128794
+ url: uploaded.url,
128795
+ error: message,
128796
+ queuedForCleanup: Boolean(deps.pendingBlobDeletions)
128797
+ }, "Could not delete the ciphertext uploaded for an entry the tombstone covers");
128798
+ }
128799
+ }
128800
+ await deps.storage.deleteVersion(entry.scope, entry.collectedAt);
128801
+ deps.logger.warn({
128802
+ path: entry.path,
128803
+ scope: entry.scope,
128804
+ deletedAt,
128805
+ tombstoneVersion: version4,
128806
+ entryVersion: entry.version,
128807
+ afterTombstoneVersion: entry.afterTombstoneVersion ?? null
128808
+ }, "Dropped unsynced local entry: the gateway reports its scope as deleted");
128809
+ throw new DeletedScopeEntryError(entry.path, deletedAt);
128810
+ }
127529
128811
  function isMissingPayloadError(err2) {
127530
128812
  return err2 instanceof Error && err2.code === "ENOENT";
127531
128813
  }
@@ -127544,6 +128826,20 @@ async function uploadOne(deps, entry) {
127544
128826
  }
127545
128827
  throw err2;
127546
128828
  }
128829
+ let registerVersion = BigInt(entry.version);
128830
+ if (!entry.dataPointId && deps.dataPointFeed) {
128831
+ const remote = await deps.dataPointFeed.getDataPoint({
128832
+ ownerAddress: serverOwner,
128833
+ scope: entry.scope
128834
+ });
128835
+ const deletedAt = deletionTimestamp(remote);
128836
+ if (remote && deletedAt !== null) {
128837
+ await dropIfCoveredByDeletion(deps, entry, remote, deletedAt);
128838
+ const afterTombstone = BigInt(remote.expectedVersion) + 1n;
128839
+ if (afterTombstone > registerVersion)
128840
+ registerVersion = afterTombstone;
128841
+ }
128842
+ }
127547
128843
  const scopeKey = deriveScopeKey(masterKey, entry.scope);
127548
128844
  const scopeKeyHex = uint8ToHex(scopeKey);
127549
128845
  const plaintext = new TextEncoder().encode(JSON.stringify(envelope));
@@ -127554,7 +128850,7 @@ async function uploadOne(deps, entry) {
127554
128850
  collectedAt: entry.collectedAt,
127555
128851
  sizeBytes: encrypted.byteLength
127556
128852
  })));
127557
- const storageKey = `${entry.scope}/${entry.version}`;
128853
+ const storageKey = `${entry.scope}/${registerVersion}`;
127558
128854
  let url2 = await storageAdapter.upload(storageKey, encrypted);
127559
128855
  let dataPointId;
127560
128856
  if (entry.dataPointId) {
@@ -127568,14 +128864,35 @@ async function uploadOne(deps, entry) {
127568
128864
  metadataHash,
127569
128865
  expectedVersion: version4
127570
128866
  });
127571
- const dataPointResult = await gateway.registerDataPoint({
128867
+ const registration = {
127572
128868
  ownerAddress: serverOwner,
127573
128869
  scope: entry.scope,
127574
128870
  dataHash,
127575
128871
  metadataHash,
127576
128872
  expectedVersion: String(version4),
127577
128873
  signature: addDataSignature
127578
- });
128874
+ };
128875
+ const lineage = readStoredLineage(envelope.data);
128876
+ let dataPointResult;
128877
+ if (lineage) {
128878
+ if (!deps.lineageGateway) {
128879
+ throw new Error(`Cannot register derivative ${entry.path} (scope=${entry.scope}): lineage registration needs a gateway URL (lineageGateway is not configured)`);
128880
+ }
128881
+ const lineageSignature = await signer.signLineageAttestation({
128882
+ ownerAddress: serverOwner,
128883
+ scope: entry.scope,
128884
+ expectedVersion: version4,
128885
+ dataHash,
128886
+ sources: lineage.sources
128887
+ });
128888
+ dataPointResult = await deps.lineageGateway.registerDataPoint({
128889
+ ...registration,
128890
+ lineage: lineage.sources,
128891
+ lineageSignature
128892
+ });
128893
+ } else {
128894
+ dataPointResult = await gateway.registerDataPoint(registration);
128895
+ }
127579
128896
  const id2 = dataPointResult.dataPointId ?? null;
127580
128897
  if (!id2) {
127581
128898
  throw new Error(`Gateway registerDataPoint did not return a dataPointId for ${entry.path} (scope=${entry.scope}, version=${version4})`);
@@ -127583,11 +128900,23 @@ async function uploadOne(deps, entry) {
127583
128900
  return id2;
127584
128901
  };
127585
128902
  try {
127586
- dataPointId = await registerAt(BigInt(entry.version));
128903
+ dataPointId = await registerAt(registerVersion);
128904
+ if (registerVersion !== BigInt(entry.version)) {
128905
+ await storage.updateEntryVersion(entry.path, Number(registerVersion));
128906
+ }
127587
128907
  } catch (err2) {
127588
128908
  if (!isStaleVersionConflict(err2))
127589
128909
  throw err2;
127590
- const record2 = await gateway.getDataPoint(computeDataPointId(serverOwner, entry.scope));
128910
+ const record2 = deps.dataPointFeed ? await deps.dataPointFeed.getDataPoint({
128911
+ ownerAddress: serverOwner,
128912
+ scope: entry.scope
128913
+ }) : await gateway.getDataPoint(computeDataPointId(serverOwner, entry.scope));
128914
+ const conflictDeletedAt = record2 ? deletionTimestamp(record2) : null;
128915
+ if (record2 && conflictDeletedAt !== null) {
128916
+ await dropIfCoveredByDeletion(deps, entry, record2, conflictDeletedAt, {
128917
+ url: url2
128918
+ });
128919
+ }
127591
128920
  if (record2 && record2.dataHash.toLowerCase() === dataHash.toLowerCase()) {
127592
128921
  dataPointId = record2.id;
127593
128922
  const adoptedVersion = Number(record2.expectedVersion);
@@ -127613,6 +128942,7 @@ async function uploadOne(deps, entry) {
127613
128942
  }
127614
128943
  }
127615
128944
  await storage.updateDataPointId(entry.path, dataPointId);
128945
+ deps.scopeDeletions?.markLive(entry.scope);
127616
128946
  }
127617
128947
  logger.info({
127618
128948
  path: entry.path,
@@ -127632,7 +128962,7 @@ async function uploadAll(deps, options) {
127632
128962
  const result = await uploadOne(deps, entry);
127633
128963
  results.push(result);
127634
128964
  } catch (err2) {
127635
- if (err2 instanceof OrphanedEntryError) {
128965
+ if (err2 instanceof OrphanedEntryError || err2 instanceof DeletedScopeEntryError) {
127636
128966
  continue;
127637
128967
  }
127638
128968
  const error51 = err2;
@@ -127660,11 +128990,100 @@ function parseGatewayNextVersion(message) {
127660
128990
  return Number(storedValue[1]) + 1;
127661
128991
  return null;
127662
128992
  }
127663
- function computeDataPointId(ownerAddress, scope) {
127664
- return keccak256(encodeAbiParameters([
127665
- { name: "ownerAddress", type: "address" },
127666
- { name: "scope", type: "string" }
127667
- ], [ownerAddress.toLowerCase(), scope]));
128993
+
128994
+ // ../core/dist/sync/data-point-feed.js
128995
+ function createGatewayDataPointFeed(options) {
128996
+ const base = options.gatewayUrl.replace(/\/+$/, "");
128997
+ const fetchImpl = options.fetch ?? globalThis.fetch;
128998
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
128999
+ return {
129000
+ async listDataPointsByOwner(owner, cursor, listOptions) {
129001
+ const params = new URLSearchParams({ user: owner });
129002
+ if (cursor !== null)
129003
+ params.set("cursor", cursor);
129004
+ if (listOptions?.since)
129005
+ params.set("since", listOptions.since);
129006
+ if (listOptions?.limit !== void 0) {
129007
+ params.set("limit", String(listOptions.limit));
129008
+ }
129009
+ if (listOptions?.includeDeleted)
129010
+ params.set("includeDeleted", "true");
129011
+ const res = await fetchImpl(`${base}/v1/data?${params.toString()}`);
129012
+ if (!res.ok) {
129013
+ throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
129014
+ }
129015
+ const envelope = await res.json();
129016
+ const nextCursor = envelope.pagination?.hasMore === false ? null : envelope.pagination?.nextCursor ?? null;
129017
+ const rows = envelope.data?.dataPoints ?? [];
129018
+ return {
129019
+ dataPoints: rows.map((row) => normalizeRecord(row)),
129020
+ cursor: nextCursor
129021
+ };
129022
+ },
129023
+ async getDataPoint(input) {
129024
+ const dataPointId = computeDataPointId(input.ownerAddress, input.scope);
129025
+ const res = await fetchImpl(`${base}/v1/data/${dataPointId}?includeDeleted=true`);
129026
+ if (res.status === 404)
129027
+ return null;
129028
+ if (res.status === 410) {
129029
+ const body2 = await res.json().catch(() => null);
129030
+ const echoed = unwrap(body2);
129031
+ const deletedAt = stringField(echoed, "deletedAt") ?? now().toISOString();
129032
+ return {
129033
+ id: dataPointId,
129034
+ ownerAddress: input.ownerAddress,
129035
+ scope: input.scope,
129036
+ dataHash: stringField(echoed, "dataHash") ?? TOMBSTONE_DATA_HASH,
129037
+ metadataHash: stringField(echoed, "metadataHash") ?? TOMBSTONE_METADATA_HASH,
129038
+ expectedVersion: stringField(echoed, "expectedVersion") ?? "0",
129039
+ addedAt: stringField(echoed, "addedAt") ?? deletedAt,
129040
+ deletedAt
129041
+ };
129042
+ }
129043
+ if (!res.ok) {
129044
+ throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
129045
+ }
129046
+ const body = await res.json();
129047
+ return normalizeRecord(unwrap(body));
129048
+ }
129049
+ };
129050
+ }
129051
+ function unwrap(body) {
129052
+ if (typeof body !== "object" || body === null)
129053
+ return null;
129054
+ const record2 = body;
129055
+ if (typeof record2.data === "object" && record2.data !== null) {
129056
+ return record2.data;
129057
+ }
129058
+ return record2;
129059
+ }
129060
+ function stringField(record2, key) {
129061
+ const value = record2?.[key];
129062
+ return typeof value === "string" ? value : void 0;
129063
+ }
129064
+ function normalizeRecord(row) {
129065
+ const record2 = row ?? {};
129066
+ const deletedAt = record2.deletedAt;
129067
+ return {
129068
+ ...record2,
129069
+ deletedAt: typeof deletedAt === "string" ? deletedAt : null
129070
+ };
129071
+ }
129072
+ function feedFromGatewayClient(gateway) {
129073
+ return {
129074
+ async listDataPointsByOwner(owner, cursor, listOptions) {
129075
+ const { includeDeleted: _includeDeleted, ...sdkOptions } = listOptions ?? {};
129076
+ const result = Object.keys(sdkOptions).length > 0 ? await gateway.listDataPointsByOwner(owner, cursor, sdkOptions) : await gateway.listDataPointsByOwner(owner, cursor);
129077
+ return {
129078
+ dataPoints: result.dataPoints.map((row) => normalizeRecord(row)),
129079
+ cursor: result.cursor
129080
+ };
129081
+ },
129082
+ async getDataPoint(input) {
129083
+ const row = await gateway.getDataPoint(computeDataPointId(input.ownerAddress, input.scope));
129084
+ return row === null ? null : normalizeRecord(row);
129085
+ }
129086
+ };
127668
129087
  }
127669
129088
 
127670
129089
  // ../core/dist/sync/issues.js
@@ -128004,10 +129423,43 @@ async function downloadAll(deps, options = {}) {
128004
129423
  if (options.fullReconcile || repairSummary.missingEnvelopeEntries > 0) {
128005
129424
  options.retryMemory?.onListingReset();
128006
129425
  }
128007
- const { dataPoints, cursor: nextCursor } = await gateway.listDataPointsByOwner(serverOwner, lastCursor);
129426
+ const feed = deps.dataPointFeed ?? feedFromGatewayClient(gateway);
129427
+ const { dataPoints, cursor: nextCursor } = await feed.listDataPointsByOwner(serverOwner, lastCursor, { includeDeleted: true });
129428
+ if (deps.scopeDeletions) {
129429
+ for (const dataPoint of dataPoints) {
129430
+ const deletedAt = deletionTimestamp(dataPoint);
129431
+ if (deletedAt !== null) {
129432
+ deps.scopeDeletions.markDeleted(dataPoint.scope, {
129433
+ deletedAt,
129434
+ version: tombstoneVersion(dataPoint)
129435
+ });
129436
+ } else {
129437
+ deps.scopeDeletions.markLive(dataPoint.scope);
129438
+ }
129439
+ }
129440
+ if (nextCursor === null) {
129441
+ deps.scopeDeletions.noteFeedSynced(void 0, {
129442
+ full: lastCursor === null
129443
+ });
129444
+ }
129445
+ }
128008
129446
  const results = [];
128009
129447
  let failed = false;
128010
129448
  for (const dataPoint of dataPoints) {
129449
+ const deletedAt = deletionTimestamp(dataPoint);
129450
+ if (deletedAt !== null) {
129451
+ try {
129452
+ await reconcileDeletedDataPoint(deps, dataPoint, deletedAt);
129453
+ } catch (err2) {
129454
+ logger.error({
129455
+ dataPointId: dataPoint.id,
129456
+ scope: dataPoint.scope,
129457
+ error: err2.message
129458
+ }, "Failed to reconcile deleted data point locally");
129459
+ failed = true;
129460
+ }
129461
+ continue;
129462
+ }
128011
129463
  const retryKey = downloadRetryKey(dataPoint);
128012
129464
  const decision = options.retryMemory?.decide(retryKey) ?? "attempt";
128013
129465
  if (decision === "give-up") {
@@ -128063,6 +129515,49 @@ async function downloadAll(deps, options = {}) {
128063
129515
  }
128064
129516
  return results;
128065
129517
  }
129518
+ async function reconcileDeletedDataPoint(deps, record2, deletedAt) {
129519
+ const tombstone = { version: tombstoneVersion(record2) };
129520
+ const tombstoned = tombstone.version === null ? null : BigInt(tombstone.version);
129521
+ const orphanKeys = [];
129522
+ const { storage, logger } = deps;
129523
+ const PAGE_SIZE = 500;
129524
+ const stale = [];
129525
+ let kept = 0;
129526
+ for (let offset = 0; ; offset += PAGE_SIZE) {
129527
+ const entries = storage.listVersions(record2.scope, {
129528
+ limit: PAGE_SIZE,
129529
+ offset
129530
+ });
129531
+ for (const entry of entries) {
129532
+ if (isEntryCoveredByTombstone(entry, tombstone)) {
129533
+ stale.push({ scope: entry.scope, collectedAt: entry.collectedAt });
129534
+ if (entry.dataPointId === null && (tombstoned === null || BigInt(entry.version) > tombstoned)) {
129535
+ orphanKeys.push({
129536
+ scope: entry.scope,
129537
+ version: String(entry.version)
129538
+ });
129539
+ }
129540
+ } else {
129541
+ kept += 1;
129542
+ }
129543
+ }
129544
+ if (entries.length < PAGE_SIZE)
129545
+ break;
129546
+ }
129547
+ let removed = 0;
129548
+ for (const version4 of stale) {
129549
+ if (await storage.deleteVersion(version4.scope, version4.collectedAt)) {
129550
+ removed += 1;
129551
+ }
129552
+ }
129553
+ if (orphanKeys.length > 0 && deps.pendingBlobDeletions) {
129554
+ await deps.pendingBlobDeletions.add(orphanKeys);
129555
+ }
129556
+ if (removed > 0 || kept > 0) {
129557
+ logger.info({ dataPointId: record2.id, scope: record2.scope, deletedAt, removed, kept }, "Reconciled gateway deletion against local index");
129558
+ }
129559
+ return { scope: record2.scope, deletedAt, removed, kept };
129560
+ }
128066
129561
  async function repairLocalMissingBlockSidecars(deps) {
128067
129562
  const { storage, logger, diagnostics } = deps;
128068
129563
  if (!storage.writeBlockManifest || !storage.hasScopeBlocks) {
@@ -128221,28 +129716,6 @@ async function repairMissingBlockSidecars(storage, logger, ctx, entry, diagnosti
128221
129716
  }
128222
129717
  }
128223
129718
 
128224
- // ../core/dist/sync/workers/delete.js
128225
- async function deleteScopeRemote(deps, scope) {
128226
- const { storage, logger } = deps;
128227
- let syncedVersions = 0;
128228
- const PAGE_SIZE = 1e3;
128229
- for (let offset = 0; ; offset += PAGE_SIZE) {
128230
- const entries = storage.listVersions(scope, { limit: PAGE_SIZE, offset });
128231
- syncedVersions += entries.filter((e10) => e10.dataPointId !== null).length;
128232
- if (entries.length < PAGE_SIZE)
128233
- break;
128234
- }
128235
- if (syncedVersions > 0) {
128236
- logger.warn({ scope, syncedVersions }, "Remote scope deletion is not supported on the DPv2 gateway (no de-registration endpoint); local data was removed but the remote data point(s) and ciphertext blob(s) remain");
128237
- }
128238
- return {
128239
- scope,
128240
- filesDeregistered: 0,
128241
- blobsDeleted: 0,
128242
- errors: []
128243
- };
128244
- }
128245
-
128246
129719
  // ../core/dist/sync/engine/sync-manager.js
128247
129720
  var MAX_ERRORS = 10;
128248
129721
  function createSyncManager(uploadDeps, downloadDeps, options) {
@@ -128260,12 +129733,28 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
128260
129733
  let rerunRequested = false;
128261
129734
  let needsFullReconcile = true;
128262
129735
  const downloadRetryMemory = createDownloadRetryMemory();
129736
+ const dataPointFeed = downloadDeps.dataPointFeed ?? uploadDeps.dataPointFeed;
129737
+ const scopeDeletions = uploadDeps.scopeDeletions ?? downloadDeps.scopeDeletions;
129738
+ const workerUploadDeps = {
129739
+ ...uploadDeps,
129740
+ pendingBlobDeletions: uploadDeps.pendingBlobDeletions ?? options?.pendingBlobDeletions
129741
+ };
129742
+ const workerDownloadDeps = {
129743
+ ...downloadDeps,
129744
+ pendingBlobDeletions: downloadDeps.pendingBlobDeletions ?? options?.pendingBlobDeletions
129745
+ };
129746
+ let mutationQueue = Promise.resolve();
129747
+ function exclusive(operation) {
129748
+ const run = mutationQueue.then(operation, operation);
129749
+ mutationQueue = run.catch(() => void 0);
129750
+ return run;
129751
+ }
128263
129752
  async function runCycle() {
128264
129753
  if (cycleInFlight) {
128265
129754
  rerunRequested = true;
128266
129755
  return cycleInFlight;
128267
129756
  }
128268
- cycleInFlight = (async () => {
129757
+ cycleInFlight = exclusive(async () => {
128269
129758
  do {
128270
129759
  rerunRequested = false;
128271
129760
  const canRun = await (options?.canSync?.() ?? { ok: true });
@@ -128276,7 +129765,19 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
128276
129765
  }
128277
129766
  blocked = null;
128278
129767
  try {
128279
- const uploadResults = await uploadAll(uploadDeps, {
129768
+ await retryPendingBlobDeletions({
129769
+ deleteData: options?.deleteData,
129770
+ pendingBlobDeletions: options?.pendingBlobDeletions,
129771
+ dataPointFeed,
129772
+ serverOwner: uploadDeps.serverOwner,
129773
+ storage: uploadDeps.storage,
129774
+ logger: uploadDeps.logger
129775
+ });
129776
+ } catch (err2) {
129777
+ uploadDeps.logger.warn({ error: err2.message }, "Pending blob deletion retry failed");
129778
+ }
129779
+ try {
129780
+ const uploadResults = await uploadAll(workerUploadDeps, {
128280
129781
  batchSize: uploadBatchSize,
128281
129782
  onError(entry, error51) {
128282
129783
  pushError({
@@ -128300,7 +129801,7 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
128300
129801
  }
128301
129802
  try {
128302
129803
  const fullReconcile = needsFullReconcile;
128303
- const downloadResults = await downloadAll(downloadDeps, {
129804
+ const downloadResults = await downloadAll(workerDownloadDeps, {
128304
129805
  fullReconcile,
128305
129806
  retryMemory: downloadRetryMemory
128306
129807
  });
@@ -128322,7 +129823,7 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
128322
129823
  }
128323
129824
  lastSync = (/* @__PURE__ */ new Date()).toISOString();
128324
129825
  } while (rerunRequested && isRunning);
128325
- })();
129826
+ });
128326
129827
  try {
128327
129828
  await cycleInFlight;
128328
129829
  } finally {
@@ -128411,13 +129912,291 @@ function createSyncManager(uploadDeps, downloadDeps, options) {
128411
129912
  uploadDeps.logger.debug("New data notification received");
128412
129913
  scheduleNotifiedCycle();
128413
129914
  },
128414
- async deleteScopeRemote(scope) {
128415
- await deleteScopeRemote(uploadDeps, scope);
129915
+ deleteScope(scope) {
129916
+ return exclusive(() => deleteScope({
129917
+ storage: uploadDeps.storage,
129918
+ serverOwner: uploadDeps.serverOwner,
129919
+ deleteData: options?.deleteData,
129920
+ pendingBlobDeletions: options?.pendingBlobDeletions,
129921
+ scopeDeletions,
129922
+ dataPointFeed,
129923
+ logger: uploadDeps.logger
129924
+ }, scope));
128416
129925
  }
128417
129926
  };
128418
129927
  return manager;
128419
129928
  }
128420
129929
 
129930
+ // ../core/dist/sync/delete-data-port.js
129931
+ function createGatewayDeleteDataPort(options) {
129932
+ const gatewayBase = options.gatewayUrl.replace(/\/+$/, "");
129933
+ const storageBase = options.storage.endpoint.replace(/\/+$/, "");
129934
+ const fetchImpl = options.fetch ?? globalThis.fetch;
129935
+ const owner = options.serverOwner.toLowerCase();
129936
+ async function sendTombstone(scope, dataPointId, version4) {
129937
+ const signature = await options.signer.signAddData({
129938
+ ownerAddress: options.serverOwner,
129939
+ scope,
129940
+ dataHash: TOMBSTONE_DATA_HASH,
129941
+ metadataHash: TOMBSTONE_METADATA_HASH,
129942
+ expectedVersion: version4
129943
+ });
129944
+ return fetchImpl(`${gatewayBase}/v1/data/${dataPointId}`, {
129945
+ method: "DELETE",
129946
+ headers: {
129947
+ "Content-Type": "application/json",
129948
+ Authorization: `Web3Signed ${signature}`
129949
+ },
129950
+ body: JSON.stringify({
129951
+ ownerAddress: options.serverOwner,
129952
+ scope,
129953
+ expectedVersion: String(version4),
129954
+ signature
129955
+ })
129956
+ });
129957
+ }
129958
+ return {
129959
+ async tombstone(scope) {
129960
+ const dataPointId = computeDataPointId(options.serverOwner, scope);
129961
+ const current = await options.dataPointFeed.getDataPoint({
129962
+ ownerAddress: options.serverOwner,
129963
+ scope
129964
+ });
129965
+ if (current === null) {
129966
+ return { status: "not-registered", dataPointId };
129967
+ }
129968
+ if (current.deletedAt !== null) {
129969
+ return {
129970
+ status: "already-deleted",
129971
+ dataPointId,
129972
+ version: current.expectedVersion,
129973
+ deletedAt: current.deletedAt
129974
+ };
129975
+ }
129976
+ let version4 = BigInt(current.expectedVersion) + 1n;
129977
+ let res = await sendTombstone(scope, dataPointId, version4);
129978
+ if (res.status === 409) {
129979
+ const body2 = await res.json().catch(() => null);
129980
+ const conflict = unwrap2(body2);
129981
+ const nextExplicit = integerField(conflict, "nextExpectedVersion") ?? integerField(body2, "nextExpectedVersion");
129982
+ const currentExpected = integerField(conflict, "currentExpectedVersion") ?? integerField(body2, "currentExpectedVersion");
129983
+ const legacyNext = parseGatewayNextVersion(detailFromBody(body2, res.statusText));
129984
+ const next = nextExplicit !== null ? nextExplicit : currentExpected !== null ? currentExpected + 1n : legacyNext !== null ? BigInt(legacyNext) : null;
129985
+ if (next === null) {
129986
+ throw new Error(`Gateway error: 409 ${detailFromBody(body2, res.statusText)}`);
129987
+ }
129988
+ version4 = next;
129989
+ res = await sendTombstone(scope, dataPointId, version4);
129990
+ }
129991
+ if (res.status === 404) {
129992
+ return { status: "not-registered", dataPointId };
129993
+ }
129994
+ if (res.status === 410) {
129995
+ const body2 = await res.json().catch(() => null);
129996
+ const echoed = unwrap2(body2);
129997
+ let winning = normalizeVersionString(stringField2(echoed, "expectedVersion"));
129998
+ let deletedAt = stringField2(echoed, "deletedAt");
129999
+ if (winning === null) {
130000
+ const reread = await options.dataPointFeed.getDataPoint({ ownerAddress: options.serverOwner, scope }).catch(() => null);
130001
+ if (reread && reread.deletedAt !== null) {
130002
+ winning = normalizeVersionString(reread.expectedVersion);
130003
+ deletedAt = deletedAt ?? reread.deletedAt;
130004
+ }
130005
+ }
130006
+ return {
130007
+ status: "already-deleted",
130008
+ dataPointId,
130009
+ version: winning,
130010
+ deletedAt
130011
+ };
130012
+ }
130013
+ if (!res.ok) {
130014
+ throw new Error(`Gateway error: ${res.status} ${await errorDetail(res)}`);
130015
+ }
130016
+ const body = await res.json().catch(() => null);
130017
+ const row = unwrap2(body);
130018
+ return {
130019
+ status: "tombstoned",
130020
+ dataPointId: stringField2(row, "dataPointId") ?? dataPointId,
130021
+ version: stringField2(row, "expectedVersion") ?? String(version4),
130022
+ deletedAt: stringField2(row, "deletedAt")
130023
+ };
130024
+ },
130025
+ async deleteBlobVersions(scope, versions) {
130026
+ const outcome = {
130027
+ deleted: [],
130028
+ missing: [],
130029
+ failed: []
130030
+ };
130031
+ for (const version4 of versions) {
130032
+ const path = `/v1/chains/${options.storage.chainId}/blobs/${owner}/${encodeURIComponent(scope)}/${encodeURIComponent(version4)}`;
130033
+ try {
130034
+ const authorization = await buildWeb3SignedHeader({
130035
+ signMessage: (message) => options.storage.signMessage(message),
130036
+ aud: storageBase,
130037
+ method: "DELETE",
130038
+ uri: path
130039
+ });
130040
+ const res = await fetchImpl(`${storageBase}${path}`, {
130041
+ method: "DELETE",
130042
+ headers: { authorization }
130043
+ });
130044
+ if (res.status === 404) {
130045
+ outcome.missing.push(version4);
130046
+ } else if (res.ok) {
130047
+ outcome.deleted.push(version4);
130048
+ } else {
130049
+ outcome.failed.push({
130050
+ version: version4,
130051
+ error: `vana-storage delete failed: ${res.status} ${res.statusText}`
130052
+ });
130053
+ }
130054
+ } catch (err2) {
130055
+ outcome.failed.push({
130056
+ version: version4,
130057
+ error: err2 instanceof Error ? err2.message : String(err2)
130058
+ });
130059
+ }
130060
+ }
130061
+ return outcome;
130062
+ }
130063
+ };
130064
+ }
130065
+ async function errorDetail(res) {
130066
+ const body = await res.json().catch(() => null);
130067
+ return detailFromBody(body, res.statusText);
130068
+ }
130069
+ function detailFromBody(body, fallback) {
130070
+ if (typeof body === "object" && body !== null) {
130071
+ const record2 = body;
130072
+ if (typeof record2.error === "string")
130073
+ return record2.error;
130074
+ if (typeof record2.message === "string")
130075
+ return record2.message;
130076
+ if (typeof record2.error === "object" && record2.error !== null) {
130077
+ const nested = record2.error;
130078
+ if (typeof nested.message === "string")
130079
+ return nested.message;
130080
+ }
130081
+ }
130082
+ return fallback;
130083
+ }
130084
+ function normalizeVersionString(value) {
130085
+ if (value === null || !/^\d+$/.test(value))
130086
+ return null;
130087
+ const parsed = BigInt(value);
130088
+ return parsed > 0n ? parsed.toString() : null;
130089
+ }
130090
+ function integerField(record2, key) {
130091
+ if (typeof record2 !== "object" || record2 === null)
130092
+ return null;
130093
+ const value = record2[key];
130094
+ if (typeof value === "number" && Number.isSafeInteger(value)) {
130095
+ return BigInt(value);
130096
+ }
130097
+ if (typeof value === "string" && /^\d+$/.test(value))
130098
+ return BigInt(value);
130099
+ return null;
130100
+ }
130101
+ function unwrap2(body) {
130102
+ if (typeof body !== "object" || body === null)
130103
+ return null;
130104
+ const record2 = body;
130105
+ if (typeof record2.data === "object" && record2.data !== null) {
130106
+ return record2.data;
130107
+ }
130108
+ return record2;
130109
+ }
130110
+ function stringField2(record2, key) {
130111
+ const value = record2?.[key];
130112
+ return typeof value === "string" ? value : null;
130113
+ }
130114
+
130115
+ // ../core/dist/sync/pending-blob-deletions.js
130116
+ function markerId(key) {
130117
+ const range = key.range ? `${key.range.from}-${key.range.to}` : "";
130118
+ return `${key.scope}\0${key.version ?? ""}\0${range}`;
130119
+ }
130120
+ function normalizeRange(value) {
130121
+ if (typeof value !== "object" || value === null)
130122
+ return void 0;
130123
+ const { from, to: to3 } = value;
130124
+ if (typeof from !== "string" || typeof to3 !== "string" || !/^\d+$/.test(from) || !/^\d+$/.test(to3) || BigInt(from) > BigInt(to3)) {
130125
+ return void 0;
130126
+ }
130127
+ return { from, to: to3 };
130128
+ }
130129
+ function normalizePendingBlobDeletions(stored) {
130130
+ if (!Array.isArray(stored))
130131
+ return [];
130132
+ const keys = [];
130133
+ for (const item of stored) {
130134
+ if (typeof item === "string") {
130135
+ keys.push({ scope: item, version: null });
130136
+ } else if (typeof item === "object" && item !== null && typeof item.scope === "string") {
130137
+ const version4 = item.version;
130138
+ const range = typeof version4 === "string" ? void 0 : normalizeRange(item.range);
130139
+ keys.push({
130140
+ scope: item.scope,
130141
+ version: typeof version4 === "string" ? version4 : null,
130142
+ ...range ? { range } : {}
130143
+ });
130144
+ }
130145
+ }
130146
+ return keys;
130147
+ }
130148
+ function createPendingBlobDeletionStore(kv) {
130149
+ let queue = Promise.resolve();
130150
+ function serialized(operation) {
130151
+ const run = queue.then(operation, operation);
130152
+ queue = run.catch(() => void 0);
130153
+ return run;
130154
+ }
130155
+ async function current() {
130156
+ return normalizePendingBlobDeletions(await kv.read());
130157
+ }
130158
+ return {
130159
+ list() {
130160
+ return serialized(current);
130161
+ },
130162
+ add(keys) {
130163
+ return serialized(async () => {
130164
+ if (keys.length === 0)
130165
+ return;
130166
+ const existing = await current();
130167
+ const known = new Set(existing.map(markerId));
130168
+ const next = [...existing];
130169
+ for (const key of keys) {
130170
+ const id2 = markerId(key);
130171
+ if (known.has(id2))
130172
+ continue;
130173
+ known.add(id2);
130174
+ next.push({
130175
+ scope: key.scope,
130176
+ version: key.version,
130177
+ ...key.range ? { range: { ...key.range } } : {}
130178
+ });
130179
+ }
130180
+ if (next.length === existing.length)
130181
+ return;
130182
+ await kv.write(next);
130183
+ });
130184
+ },
130185
+ remove(keys) {
130186
+ return serialized(async () => {
130187
+ if (keys.length === 0)
130188
+ return;
130189
+ const existing = await current();
130190
+ const gone = new Set(keys.map(markerId));
130191
+ const next = existing.filter((key) => !gone.has(markerId(key)));
130192
+ if (next.length === existing.length)
130193
+ return;
130194
+ await kv.write(next);
130195
+ });
130196
+ }
130197
+ };
130198
+ }
130199
+
128421
130200
  // ../core/dist/storage/adapters/sdk.js
128422
130201
  function createSdkStorageAdapter(providerOrFactory, options) {
128423
130202
  let cachedProvider;
@@ -128478,8 +130257,11 @@ function copyBytes(data) {
128478
130257
 
128479
130258
  // ../core/dist/storage/adapters/vana.js
128480
130259
  var DEFAULT_VANA_STORAGE_ENDPOINT = "https://storage.vana.org";
130260
+ function resolveVanaStorageEndpoint(config2) {
130261
+ return (config2.storage.config.vana?.apiUrl ?? DEFAULT_VANA_STORAGE_ENDPOINT).replace(/\/+$/, "");
130262
+ }
128481
130263
  function createVanaSyncStorageAdapter(params) {
128482
- const endpoint = (params.config.storage.config.vana?.apiUrl ?? DEFAULT_VANA_STORAGE_ENDPOINT).replace(/\/+$/, "");
130264
+ const endpoint = resolveVanaStorageEndpoint(params.config);
128483
130265
  const owner = params.serverOwner.toLowerCase();
128484
130266
  const chainId = params.config.gateway.chainId;
128485
130267
  return createSdkStorageAdapter(createVanaStorageProvider({
@@ -128534,6 +130316,7 @@ async function resolvePsLiteOwner(input) {
128534
130316
 
128535
130317
  // ../lite/dist/sync.js
128536
130318
  var SYNC_CURSOR_KEY = "sync-cursor-v1";
130319
+ var PENDING_BLOB_DELETIONS_KEY = "pending-blob-deletions-v1";
128537
130320
  function createBrowserLogger(logger) {
128538
130321
  const fallback = {
128539
130322
  info: console.info.bind(console),
@@ -128564,6 +130347,19 @@ function createPsLiteSyncCursor(stateStore) {
128564
130347
  }
128565
130348
  };
128566
130349
  }
130350
+ function createPsLitePendingBlobDeletionStore(stateStore) {
130351
+ return createPendingBlobDeletionStore({
130352
+ async read() {
130353
+ const state = await stateStore.get(PENDING_BLOB_DELETIONS_KEY);
130354
+ if (!state)
130355
+ return null;
130356
+ return normalizePendingBlobDeletions(state.keys ?? state.scopes);
130357
+ },
130358
+ async write(keys) {
130359
+ await stateStore.set(PENDING_BLOB_DELETIONS_KEY, { keys });
130360
+ }
130361
+ });
130362
+ }
128567
130363
  function buildDownloadDiagnosticsHook(recorder) {
128568
130364
  return {
128569
130365
  onDownloadStart(fileId) {
@@ -128649,6 +130445,20 @@ async function createPsLiteSyncManager(options) {
128649
130445
  });
128650
130446
  const cursor = createPsLiteSyncCursor(options.stateStore);
128651
130447
  const logger = createBrowserLogger(options.logger);
130448
+ const dataPointFeed = options.dataPointFeed ?? createGatewayDataPointFeed({ gatewayUrl: options.config.gateway.url });
130449
+ const scopeDeletions = options.scopeDeletions ?? createScopeDeletionTracker({ feed: dataPointFeed, serverOwner, logger });
130450
+ const deleteData = createGatewayDeleteDataPort({
130451
+ gatewayUrl: options.config.gateway.url,
130452
+ dataPointFeed,
130453
+ serverOwner,
130454
+ signer,
130455
+ storage: {
130456
+ endpoint: resolveVanaStorageEndpoint(options.config),
130457
+ chainId: options.config.gateway.chainId,
130458
+ signMessage: (message) => options.serverAccount.signMessage(message)
130459
+ }
130460
+ });
130461
+ const pendingBlobDeletions = createPsLitePendingBlobDeletionStore(options.stateStore);
128652
130462
  const downloadDiagnostics = options.diagnostics ? buildDownloadDiagnosticsHook(options.diagnostics) : void 0;
128653
130463
  const syncManager = createSyncManager({
128654
130464
  storage: options.storage,
@@ -128657,7 +130467,10 @@ async function createPsLiteSyncManager(options) {
128657
130467
  signer,
128658
130468
  masterKey,
128659
130469
  serverOwner,
128660
- logger
130470
+ logger,
130471
+ lineageGateway: options.lineageGateway,
130472
+ dataPointFeed,
130473
+ scopeDeletions
128661
130474
  }, {
128662
130475
  storage: options.storage,
128663
130476
  storageAdapter,
@@ -128666,8 +130479,12 @@ async function createPsLiteSyncManager(options) {
128666
130479
  masterKey,
128667
130480
  serverOwner,
128668
130481
  logger,
128669
- diagnostics: downloadDiagnostics
130482
+ diagnostics: downloadDiagnostics,
130483
+ dataPointFeed,
130484
+ scopeDeletions
128670
130485
  }, {
130486
+ deleteData,
130487
+ pendingBlobDeletions,
128671
130488
  async canSync() {
128672
130489
  try {
128673
130490
  const serverInfo = await gateway.getServer(options.serverAccount.address);
@@ -128689,7 +130506,7 @@ async function createPsLiteSyncManager(options) {
128689
130506
  }
128690
130507
  });
128691
130508
  syncManager.start();
128692
- return { syncManager, serverOwner };
130509
+ return { syncManager, serverOwner, dataPointFeed, scopeDeletions };
128693
130510
  }
128694
130511
 
128695
130512
  // ../lite/dist/persistence.js
@@ -128750,9 +130567,14 @@ async function createIndexedDbPsLiteRuntime(options) {
128750
130567
  contracts: config2.gateway.contracts
128751
130568
  });
128752
130569
  const diagnostics = options.diagnostics ?? new DiagnosticsRecorder();
130570
+ const lineageGateway = createGatewayLineageClient({
130571
+ gatewayUrl: config2.gateway.url,
130572
+ requestSigner: createRequestSigner(identity.account)
130573
+ });
128753
130574
  let syncManager = options.syncManager ?? null;
130575
+ let scopeDeletions = options.scopeDeletions;
128754
130576
  if (!syncManager && config2.sync.enabled) {
128755
- syncManager = (await createPsLiteSyncManager({
130577
+ const sync = await createPsLiteSyncManager({
128756
130578
  config: config2,
128757
130579
  stateStore,
128758
130580
  storage,
@@ -128760,9 +130582,14 @@ async function createIndexedDbPsLiteRuntime(options) {
128760
130582
  ownerAddress: options.ownerAddress,
128761
130583
  serverAccount: identity.account,
128762
130584
  gateway,
130585
+ dataPointFeed: options.dataPointFeed,
130586
+ scopeDeletions,
128763
130587
  diagnostics,
128764
- logger: options.logger
128765
- })).syncManager;
130588
+ logger: options.logger,
130589
+ lineageGateway
130590
+ });
130591
+ syncManager = sync.syncManager;
130592
+ scopeDeletions = sync.scopeDeletions;
128766
130593
  }
128767
130594
  let runtimeRef = null;
128768
130595
  const auth = options.auth ?? createWeb3SignedPsLiteAuth({
@@ -128791,7 +130618,9 @@ async function createIndexedDbPsLiteRuntime(options) {
128791
130618
  serverOwner,
128792
130619
  serverSigner,
128793
130620
  syncManager,
130621
+ scopeDeletions,
128794
130622
  diagnostics,
130623
+ lineageGateway,
128795
130624
  saveConfig: async (nextConfig) => {
128796
130625
  const saved = await savePsLiteConfig(stateStore, nextConfig);
128797
130626
  Object.assign(config2, saved);