p2s_mapper 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +214 -32
  2. package/dist/coordinates.d.ts +8 -6
  3. package/dist/coordinates.js.map +1 -1
  4. package/dist/dbIds.d.ts +1 -2
  5. package/dist/extractPerResidueConfidence.d.ts +1 -2
  6. package/dist/extractStructureSequences.d.ts +14 -15
  7. package/dist/fetchUtils.js +19 -1
  8. package/dist/fetchUtils.js.map +1 -1
  9. package/dist/index.d.ts +1 -3
  10. package/dist/index.js +2 -4
  11. package/dist/index.js.map +1 -1
  12. package/dist/isoformRanking.d.ts +3 -0
  13. package/dist/pairwiseAlignment.d.ts +1 -2
  14. package/dist/pdbEntry.d.ts +32 -0
  15. package/dist/pdbEntry.js +182 -0
  16. package/dist/pdbEntry.js.map +1 -0
  17. package/dist/pdbUniProtMapping.d.ts +9 -33
  18. package/dist/pdbUniProtMapping.js +17 -134
  19. package/dist/pdbUniProtMapping.js.map +1 -1
  20. package/dist/structureSources.d.ts +37 -13
  21. package/dist/structureSources.js +144 -57
  22. package/dist/structureSources.js.map +1 -1
  23. package/dist/structureUrls.d.ts +2 -0
  24. package/dist/structureUrls.js +11 -0
  25. package/dist/structureUrls.js.map +1 -1
  26. package/esm/coordinates.d.ts +8 -6
  27. package/esm/coordinates.js.map +1 -1
  28. package/esm/dbIds.d.ts +1 -2
  29. package/esm/extractPerResidueConfidence.d.ts +1 -2
  30. package/esm/extractStructureSequences.d.ts +14 -15
  31. package/esm/fetchUtils.js +19 -1
  32. package/esm/fetchUtils.js.map +1 -1
  33. package/esm/index.d.ts +1 -3
  34. package/esm/index.js +2 -4
  35. package/esm/index.js.map +1 -1
  36. package/esm/isoformRanking.d.ts +3 -0
  37. package/esm/pairwiseAlignment.d.ts +1 -2
  38. package/esm/pdbEntry.d.ts +32 -0
  39. package/esm/pdbEntry.js +174 -0
  40. package/esm/pdbEntry.js.map +1 -0
  41. package/esm/pdbUniProtMapping.d.ts +9 -33
  42. package/esm/pdbUniProtMapping.js +17 -131
  43. package/esm/pdbUniProtMapping.js.map +1 -1
  44. package/esm/structureSources.d.ts +37 -13
  45. package/esm/structureSources.js +139 -55
  46. package/esm/structureSources.js.map +1 -1
  47. package/esm/structureUrls.d.ts +2 -0
  48. package/esm/structureUrls.js +9 -0
  49. package/esm/structureUrls.js.map +1 -1
  50. package/package.json +3 -2
  51. package/src/coordinates.ts +3 -4
  52. package/src/dbIds.ts +1 -1
  53. package/src/extractPerResidueConfidence.ts +1 -1
  54. package/src/extractStructureSequences.ts +14 -14
  55. package/src/fetchUtils.ts +23 -1
  56. package/src/index.ts +2 -4
  57. package/src/isoformRanking.ts +3 -3
  58. package/src/pairwiseAlignment.ts +1 -1
  59. package/src/pdbEntry.ts +240 -0
  60. package/src/pdbUniProtMapping.ts +20 -158
  61. package/src/structureSources.ts +194 -70
  62. package/src/structureUrls.ts +11 -0
  63. package/dist/pdbeBestStructures.d.ts +0 -23
  64. package/dist/pdbeBestStructures.js +0 -79
  65. package/dist/pdbeBestStructures.js.map +0 -1
  66. package/dist/pdbeEntryMolecules.d.ts +0 -7
  67. package/dist/pdbeEntryMolecules.js +0 -39
  68. package/dist/pdbeEntryMolecules.js.map +0 -1
  69. package/dist/siftsNumbering.d.ts +0 -23
  70. package/dist/siftsNumbering.js +0 -44
  71. package/dist/siftsNumbering.js.map +0 -1
  72. package/esm/pdbeBestStructures.d.ts +0 -23
  73. package/esm/pdbeBestStructures.js +0 -73
  74. package/esm/pdbeBestStructures.js.map +0 -1
  75. package/esm/pdbeEntryMolecules.d.ts +0 -7
  76. package/esm/pdbeEntryMolecules.js +0 -35
  77. package/esm/pdbeEntryMolecules.js.map +0 -1
  78. package/esm/siftsNumbering.d.ts +0 -23
  79. package/esm/siftsNumbering.js +0 -40
  80. package/esm/siftsNumbering.js.map +0 -1
  81. package/src/pdbeBestStructures.ts +0 -94
  82. package/src/pdbeEntryMolecules.ts +0 -37
  83. package/src/siftsNumbering.ts +0 -61
@@ -1,82 +1,166 @@
1
- // The experimental structures 3D-Beacons knows for a UniProt entry: every PDBe
2
- // entry mapped to the accession, with the UniProt range it covers and its
3
- // resolution, in one CORS-enabled call. That is what lets a page offer a
4
- // crystal structure beside a prediction without a PDB search of its own; take
5
- // the entry id from here and ask `fetchUniProtStructureMappings` for its
1
+ // The experimental structures RCSB aligns to a UniProt entry: every PDB entity
2
+ // carrying the accession, with the UniProt range it covers, then each entry's
3
+ // method, resolution and chains. Two CORS-enabled calls, which is what lets a
4
+ // page offer a crystal structure beside a prediction without a PDB search of
5
+ // its own; take the entry id from here and ask `fetchPdbEntry` for its
6
6
  // residue mapping.
7
- import { rawfetch } from "./fetchUtils.js";
8
- // Unfiltered: the `?provider=pdbe` form answered BRAF, HBB and BRCA2 with a 404
9
- // about one time in three (2026-10-09), and the parser keeps PDBe's entries
10
- // anyway.
11
- export function beaconsSummaryUrl(uniprotId) {
12
- return `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${encodeURIComponent(uniprotId)}.json`;
7
+ import { RCSB_DATA_GRAPHQL_URL, graphqlFetch } from "./pdbEntry.js";
8
+ import { isPdbId } from "./structureUrls.js";
9
+ export const RCSB_SEQUENCE_COORDINATES_URL = 'https://sequence-coordinates.rcsb.org/graphql';
10
+ export function entityAlignmentsQuery(uniprotId) {
11
+ return `{ alignments(from: UNIPROT, to: PDB_ENTITY, queryId: "${uniprotId}") {
12
+ target_alignments {
13
+ target_id
14
+ coverage { query_coverage }
15
+ aligned_regions { query_begin query_end }
16
+ }
17
+ } }`;
13
18
  }
19
+ export const ENTITY_DETAILS_QUERY = `query($ids: [String!]!) { polymer_entities(entity_ids: $ids) {
20
+ rcsb_id
21
+ rcsb_polymer_entity_container_identifiers { auth_asym_ids }
22
+ entry { rcsb_entry_info { experimental_method resolution_combined } }
23
+ } }`;
24
+ // RCSB's cap on ids per batch request
25
+ const DETAILS_BATCH = 1000;
14
26
  function isRecord(value) {
15
27
  return typeof value === 'object' && value !== null && !Array.isArray(value);
16
28
  }
17
29
  function finiteNumber(value) {
18
30
  return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
19
31
  }
32
+ function strings(value) {
33
+ return Array.isArray(value)
34
+ ? value.filter((v) => typeof v === 'string')
35
+ : [];
36
+ }
20
37
  /**
21
- * PDBe entries only, best-covering first and sharpest within a tie.
22
- *
23
- * Predicted entries (AlphaFold, SWISS-MODEL, AlphaFill) are left out because a
24
- * prediction comes from AlphaFold's own API, which answers per model. And
25
- * 3D-Beacons files SASBDB's small-angle-scattering fits under "experimentally
26
- * determined" too, with numeric ids and near-full coverage — dystrophin's best
27
- * "structure" by coverage was SASBDB 436 — which are not entries a residue
28
- * mapping exists for. Hence the `provider === 'PDBe'` gate rather than the
29
- * category alone.
38
+ * PDB entities only: the same list carries RCSB's computed models
39
+ * (`AF_AFP04637F1_1`), which a residue mapping does not exist for. The range
40
+ * spans every aligned region, as 3D-Beacons reported it.
30
41
  */
31
- export function parseExperimentalStructures(json) {
32
- const structures = isRecord(json) ? json.structures : undefined;
33
- if (!Array.isArray(structures)) {
42
+ export function parseEntityAlignments(data) {
43
+ const alignments = isRecord(data) ? data.alignments : undefined;
44
+ const targets = isRecord(alignments)
45
+ ? alignments.target_alignments
46
+ : undefined;
47
+ if (!Array.isArray(targets)) {
34
48
  return [];
35
49
  }
36
- return structures
37
- .flatMap(entry => {
38
- const s = isRecord(entry) ? entry.summary : undefined;
39
- if (!isRecord(s)) {
50
+ return targets.flatMap(target => {
51
+ if (!isRecord(target) || typeof target.target_id !== 'string') {
40
52
  return [];
41
53
  }
42
- const start = finiteNumber(s.uniprot_start);
43
- const end = finiteNumber(s.uniprot_end);
44
- const coverage = finiteNumber(s.coverage);
45
- return typeof s.model_identifier === 'string' &&
46
- s.provider === 'PDBe' &&
47
- s.model_category === 'EXPERIMENTALLY DETERMINED' &&
48
- start !== undefined &&
49
- end !== undefined &&
50
- coverage !== undefined
54
+ const [pdbId] = target.target_id.split('_');
55
+ const coverage = isRecord(target.coverage)
56
+ ? finiteNumber(target.coverage.query_coverage)
57
+ : undefined;
58
+ const regions = Array.isArray(target.aligned_regions)
59
+ ? target.aligned_regions.filter(isRecord)
60
+ : [];
61
+ const begins = regions.map(r => finiteNumber(r.query_begin));
62
+ const ends = regions.map(r => finiteNumber(r.query_end));
63
+ return pdbId !== undefined &&
64
+ isPdbId(pdbId) &&
65
+ coverage !== undefined &&
66
+ begins.length > 0 &&
67
+ begins.every(b => b !== undefined) &&
68
+ ends.every(e => e !== undefined)
51
69
  ? [
52
70
  {
53
- pdbId: s.model_identifier.toLowerCase(),
54
- method: typeof s.experimental_method === 'string'
55
- ? s.experimental_method
56
- : 'experimental',
57
- resolution: finiteNumber(s.resolution),
58
- start,
59
- end,
71
+ entityId: target.target_id,
72
+ pdbId: pdbId.toLowerCase(),
73
+ start: Math.min(...begins),
74
+ end: Math.max(...ends),
60
75
  coverage,
61
76
  },
62
77
  ]
63
78
  : [];
64
- })
65
- .sort((a, b) => b.coverage - a.coverage ||
79
+ });
80
+ }
81
+ export function parseEntityDetails(data) {
82
+ const entities = isRecord(data) ? data.polymer_entities : undefined;
83
+ const details = new Map();
84
+ for (const entity of Array.isArray(entities) ? entities : []) {
85
+ if (!isRecord(entity) || typeof entity.rcsb_id !== 'string') {
86
+ continue;
87
+ }
88
+ const ids = entity.rcsb_polymer_entity_container_identifiers;
89
+ const info = isRecord(entity.entry)
90
+ ? entity.entry.rcsb_entry_info
91
+ : undefined;
92
+ const resolutions = isRecord(info) ? info.resolution_combined : undefined;
93
+ const resolution = Array.isArray(resolutions)
94
+ ? finiteNumber(resolutions[0])
95
+ : undefined;
96
+ details.set(entity.rcsb_id, {
97
+ method: isRecord(info) && typeof info.experimental_method === 'string'
98
+ ? info.experimental_method
99
+ : 'experimental',
100
+ ...(resolution === undefined ? {} : { resolution }),
101
+ chains: strings(isRecord(ids) ? ids.auth_asym_ids : undefined),
102
+ });
103
+ }
104
+ return details;
105
+ }
106
+ /**
107
+ * One row per entry, best coverage first and sharpest within a tie. An entry
108
+ * with several entities of the protein (a construct crystallised beside a
109
+ * different fragment of itself) takes the best-covering entity's range and
110
+ * every entity's chains.
111
+ */
112
+ export function experimentalStructures(alignments, details) {
113
+ const byEntry = new Map();
114
+ for (const a of alignments) {
115
+ const d = details.get(a.entityId);
116
+ if (!d) {
117
+ continue;
118
+ }
119
+ const existing = byEntry.get(a.pdbId);
120
+ if (!existing) {
121
+ byEntry.set(a.pdbId, {
122
+ pdbId: a.pdbId,
123
+ method: d.method,
124
+ ...(d.resolution === undefined ? {} : { resolution: d.resolution }),
125
+ start: a.start,
126
+ end: a.end,
127
+ coverage: a.coverage,
128
+ chains: [...d.chains],
129
+ });
130
+ continue;
131
+ }
132
+ for (const chain of d.chains) {
133
+ if (!existing.chains.includes(chain)) {
134
+ existing.chains.push(chain);
135
+ }
136
+ }
137
+ if (a.coverage > existing.coverage) {
138
+ Object.assign(existing, {
139
+ start: a.start,
140
+ end: a.end,
141
+ coverage: a.coverage,
142
+ });
143
+ }
144
+ }
145
+ return [...byEntry.values()].sort((a, b) => b.coverage - a.coverage ||
66
146
  (a.resolution ?? Infinity) - (b.resolution ?? Infinity));
67
147
  }
68
- /** Best-effort: an unreachable API reads as "no entries", which costs a
69
- * structure suggestion and nothing else. */
148
+ const ISOFORM_SUFFIX = /-\d+$/;
149
+ /**
150
+ * Every PDB entry aligned to the accession. An accession with none, or one
151
+ * RCSB does not know, is `[]`; an isoform accession is asked as its entry,
152
+ * which is what the alignment is numbered on.
153
+ */
70
154
  export async function fetchExperimentalStructures(uniprotId, opts) {
71
- for (let attempt = 0; attempt < 2; attempt++) {
72
- const res = await rawfetch(beaconsSummaryUrl(uniprotId), opts).catch(() => undefined);
73
- if (res?.ok) {
74
- return parseExperimentalStructures(await res.json());
75
- }
76
- if (res?.status === 404 || opts?.signal?.aborted) {
77
- return [];
155
+ const alignments = parseEntityAlignments(await graphqlFetch(RCSB_SEQUENCE_COORDINATES_URL, entityAlignmentsQuery(uniprotId.replace(ISOFORM_SUFFIX, '')), undefined, opts));
156
+ const ids = alignments.map(a => a.entityId);
157
+ const details = new Map();
158
+ for (let i = 0; i < ids.length; i += DETAILS_BATCH) {
159
+ const batch = parseEntityDetails(await graphqlFetch(RCSB_DATA_GRAPHQL_URL, ENTITY_DETAILS_QUERY, { ids: ids.slice(i, i + DETAILS_BATCH) }, opts));
160
+ for (const [id, d] of batch) {
161
+ details.set(id, d);
78
162
  }
79
163
  }
80
- return [];
164
+ return experimentalStructures(alignments, details);
81
165
  }
82
166
  //# sourceMappingURL=structureSources.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"structureSources.js","sourceRoot":"","sources":["../src/structureSources.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"structureSources.js","sourceRoot":"","sources":["../src/structureSources.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,uEAAuE;AACvE,mBAAmB;AAEnB,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAI5C,MAAM,CAAC,MAAM,6BAA6B,GACxC,+CAA+C,CAAA;AAiCjD,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACrD,OAAO,yDAAyD,SAAS;;;;;;IAMvE,CAAA;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;IAIhC,CAAA;AAEJ,sCAAsC;AACtC,MAAM,aAAa,GAAG,IAAI,CAAA;AAE1B,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AAChF,CAAC;AAED,SAAS,OAAO,CAAC,KAAc;IAC7B,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACzB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QACzD,CAAC,CAAC,EAAE,CAAA;AACR,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAA;IAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC;QAClC,CAAC,CAAC,UAAU,CAAC,iBAAiB;QAC9B,CAAC,CAAC,SAAS,CAAA;IACb,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;QAC9B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC9D,OAAO,EAAE,CAAA;QACX,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;YACxC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC;YAC9C,CAAC,CAAC,SAAS,CAAA;QACb,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC;YACnD,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC;YACzC,CAAC,CAAC,EAAE,CAAA;QACN,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAA;QAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;QACxD,OAAO,KAAK,KAAK,SAAS;YACxB,OAAO,CAAC,KAAK,CAAC;YACd,QAAQ,KAAK,SAAS;YACtB,MAAM,CAAC,MAAM,GAAG,CAAC;YACjB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;YAChC,CAAC,CAAC;gBACE;oBACE,QAAQ,EAAE,MAAM,CAAC,SAAS;oBAC1B,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE;oBAC1B,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;oBAC1B,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;oBACtB,QAAQ;iBACT;aACF;YACH,CAAC,CAAC,EAAE,CAAA;IACR,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAa;IAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAA;IACnE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAA;IAChD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC7D,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5D,SAAQ;QACV,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,yCAAyC,CAAA;QAC5D,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;YACjC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe;YAC9B,CAAC,CAAC,SAAS,CAAA;QACb,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAA;QACzE,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;YAC3C,CAAC,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAC9B,CAAC,CAAC,SAAS,CAAA;QACb,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE;YAC1B,MAAM,EACJ,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,mBAAmB,KAAK,QAAQ;gBAC5D,CAAC,CAAC,IAAI,CAAC,mBAAmB;gBAC1B,CAAC,CAAC,cAAc;YACpB,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;YACnD,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;SAC/D,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAA6B,EAC7B,OAA2C;IAE3C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiC,CAAA;IACxD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;QACjC,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,SAAQ;QACV,CAAC;QACD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;gBACnB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,GAAG,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;gBACnE,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;aACtB,CAAC,CAAA;YACF,SAAQ;QACV,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC;QACD,IAAI,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE;gBACtB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,QAAQ,EAAE,CAAC,CAAC,QAAQ;aACrB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;QACvB,CAAC,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,CAC1D,CAAA;AACH,CAAC;AAED,MAAM,cAAc,GAAG,OAAO,CAAA;AAE9B;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,SAAiB,EACjB,IAAmB;IAEnB,MAAM,UAAU,GAAG,qBAAqB,CACtC,MAAM,YAAY,CAChB,6BAA6B,EAC7B,qBAAqB,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,EAC5D,SAAS,EACT,IAAI,CACL,CACF,CAAA;IACD,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAA;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,aAAa,EAAE,CAAC;QACnD,MAAM,KAAK,GAAG,kBAAkB,CAC9B,MAAM,YAAY,CAChB,qBAAqB,EACrB,oBAAoB,EACpB,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,EACxC,IAAI,CACL,CACF,CAAA;QACD,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QACpB,CAAC;IACH,CAAC;IACD,OAAO,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;AACpD,CAAC"}
@@ -9,6 +9,8 @@ export declare function uniprotEntryUrl(uniprotId: string): string;
9
9
  */
10
10
  export declare function getAlphaFoldStructureUrl(uniprotId: string, version?: string): string;
11
11
  export declare function getPdbStructureUrl(pdbId: string): string;
12
+ export declare function isPdbId(value: string): boolean;
13
+ export declare function rcsbEntryUrl(pdbId: string): string;
12
14
  /**
13
15
  * Resolve the `{ pdbId }` shorthand to a concrete structure URL, so a
14
16
  * hand-authored snapshot or a short launch URL doesn't have to know RCSB's
@@ -27,6 +27,15 @@ export function getAlphaFoldStructureUrl(uniprotId, version = ALPHAFOLD_VERSION)
27
27
  export function getPdbStructureUrl(pdbId) {
28
28
  return `https://files.rcsb.org/download/${pdbId}.cif`;
29
29
  }
30
+ // A PDB id is four characters, the first a digit: 1TUP, 6ZIO. Checked before
31
+ // a typed one reaches a fetch, so three characters on the way to four are not
32
+ // a 404 apiece.
33
+ export function isPdbId(value) {
34
+ return /^[1-9][A-Za-z0-9]{3}$/.test(value);
35
+ }
36
+ export function rcsbEntryUrl(pdbId) {
37
+ return `https://www.rcsb.org/structure/${pdbId.toUpperCase()}`;
38
+ }
30
39
  /**
31
40
  * Resolve the `{ pdbId }` shorthand to a concrete structure URL, so a
32
41
  * hand-authored snapshot or a short launch URL doesn't have to know RCSB's
@@ -1 +1 @@
1
- {"version":3,"file":"structureUrls.js","sourceRoot":"","sources":["../src/structureUrls.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"structureUrls.js","sourceRoot":"","sources":["../src/structureUrls.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "p2s_mapper",
3
- "description": "Map a transcript's translation onto a protein structure: alignment, coordinates, chain choice, SIFTS, and the AlphaFold and PDBe lookups that find the structure",
4
- "version": "1.4.0",
3
+ "description": "Map a transcript's translation onto a protein structure: alignment, coordinates, chain choice, UniProt mapping, and the AlphaFold and RCSB lookups that find the structure",
4
+ "version": "2.0.0",
5
5
  "packageManager": "pnpm@11.15.1",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,6 +25,7 @@
25
25
  "clean": "rimraf dist esm",
26
26
  "format": "prettier --write .",
27
27
  "format:check": "prettier --check .",
28
+ "docs:api": "node scripts/api-doc.ts",
28
29
  "lint": "eslint --report-unused-disable-directives --max-warnings 0",
29
30
  "typecheck": "tsc --noEmit -p tsconfig.lint.json",
30
31
  "prebuild": "pnpm clean",
@@ -19,10 +19,9 @@ import type { PairwiseAlignment } from './mappings.ts'
19
19
  * sequence; TranscriptPos the ungapped transcript sequence; AlignmentCol a
20
20
  * column of the pairwise alignment (gaps included).
21
21
  */
22
- type Branded<B extends string> = number & { readonly __brand: B }
23
- export type StructurePos = Branded<'StructurePos'>
24
- export type TranscriptPos = Branded<'TranscriptPos'>
25
- export type AlignmentCol = Branded<'AlignmentCol'>
22
+ export type StructurePos = number & { readonly __brand: 'StructurePos' }
23
+ export type TranscriptPos = number & { readonly __brand: 'TranscriptPos' }
24
+ export type AlignmentCol = number & { readonly __brand: 'AlignmentCol' }
26
25
 
27
26
  export const structurePos = (n: number) => n as StructurePos
28
27
  export const transcriptPos = (n: number) => n as TranscriptPos
package/src/dbIds.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // keyword, the regex (Ensembl patterns cover human ENS, mouse ENSMUS, zebrafish
4
4
  // ENSDAR, etc.), and a human-readable label. Recognition, label rendering, and
5
5
  // xref-query building all derive from this list, so a new ID type is one entry.
6
- type DbType = 'ensembl' | 'refseq' | 'ccds' | 'hgnc' | 'geneid'
6
+ export type DbType = 'ensembl' | 'refseq' | 'ccds' | 'hgnc' | 'geneid'
7
7
 
8
8
  const DB_ID_PATTERNS: { db: DbType; pattern: RegExp; label: string }[] = [
9
9
  { db: 'ensembl', pattern: /^ENS[A-Z]*G\d+/i, label: 'Ensembl gene' },
@@ -2,7 +2,7 @@
2
2
  // store the per-residue pLDDT in the B-factor column (B_iso_or_equiv), so the
3
3
  // first atom of each residue yields pLDDT for a predicted model and the
4
4
  // crystallographic B-factor for an experimental one.
5
- interface ConfidenceModel {
5
+ export interface ConfidenceModel {
6
6
  obj?: {
7
7
  data: {
8
8
  atomicConformation: {
@@ -20,32 +20,32 @@
20
20
  * So carry the real ids and convert through them.
21
21
  */
22
22
  export interface Entity {
23
+ /** mmCIF entity id, molstar's own bookkeeping */
23
24
  entityId: string
25
+ /** one letter per residue, observed or not */
24
26
  seq: string
27
+ /** molstar `label_seq_id` per position of `seq` */
25
28
  seqIds: number[]
26
- /** author chain ids carrying this entity, e.g. ['A', 'B'] for a homodimer;
27
- * what a user recognises from the PDB entry page, where the entity id is
28
- * molstar's own bookkeeping */
29
+ /** author chain ids carrying this entity, e.g. ['A', 'B'] for a homodimer:
30
+ * what a user recognises from the PDB entry page */
29
31
  chains: string[]
30
- /** DNA, RNA or a hybrid, by molstar's entity subtype. Its one-letter
31
- * sequence spells amino acids too (A, C, G, T, U), so it has to be kept
32
- * out of the transcript alignment rather than merely scoring low. */
32
+ /** DNA, RNA or a hybrid, by molstar's entity subtype. Its letters spell
33
+ * amino acids too (A, C, G, T, U), so it is kept out of the alignment
34
+ * rather than left to score low. */
33
35
  nucleicAcid?: boolean
34
- /** `auth_seq_id` per position: the numbering the depositors chose, which
35
- * for an RCSB entry is the one papers and UniProt cite (1TUP's position 154
36
- * is R248) and what Mol*'s own hover label shows. Display only; every
37
- * coordinate the plugin computes with stays a 0-based position, and molstar
38
- * is addressed through `seqIds`. Absent when the model has no atomic
39
- * hierarchy to read it from. See `residueNumber`. */
36
+ /** `auth_seq_id` per position: the depositors' numbering, which papers cite
37
+ * (1TUP's position 154 is R248) and Mol*'s hover shows. Display only;
38
+ * address Mol* through `seqIds`. Absent when the model has no atomic
39
+ * hierarchy. See `residueNumber`. */
40
40
  authSeqIds?: number[]
41
41
  }
42
42
 
43
- interface Column<T> {
43
+ export interface Column<T> {
44
44
  rowCount: number
45
45
  value(row: number): T
46
46
  }
47
47
 
48
- interface StructureModel {
48
+ export interface StructureModel {
49
49
  obj?: {
50
50
  data: {
51
51
  entities?: {
package/src/fetchUtils.ts CHANGED
@@ -75,10 +75,32 @@ export interface FetchOptions extends RequestInit {
75
75
  fetch?: typeof globalThis.fetch
76
76
  }
77
77
 
78
+ const USER_AGENT = 'p2s_mapper (+https://github.com/GMOD/p2s_mapper)'
79
+
80
+ /**
81
+ * AlphaFold's prediction API answers 403 to `node`, the user agent Node's fetch
82
+ * sends (measured 2026-10-11), so outside a browser every request names this
83
+ * package unless the caller named something else. A browser sends its own, and
84
+ * a script-set one would cost a CORS preflight on every call.
85
+ */
86
+ function withUserAgent(init: RequestInit) {
87
+ if (
88
+ typeof navigator !== 'undefined' &&
89
+ navigator.userAgent.startsWith('Mozilla')
90
+ ) {
91
+ return init
92
+ }
93
+ const headers = new Headers(init.headers)
94
+ if (!headers.has('user-agent')) {
95
+ headers.set('user-agent', USER_AGENT)
96
+ }
97
+ return { ...init, headers }
98
+ }
99
+
78
100
  export async function rawfetch(url: string, args?: FetchOptions) {
79
101
  const { fetch: f = globalThis.fetch, ...init } = args ?? {}
80
102
  try {
81
- return await f(url, init)
103
+ return await f(url, withUserAgent(init))
82
104
  } catch (e) {
83
105
  throw networkError(url, e)
84
106
  }
package/src/index.ts CHANGED
@@ -16,14 +16,12 @@ export * from './extractStructureSequences.ts'
16
16
  export * from './extractPerResidueConfidence.ts'
17
17
  export * from './isoformRanking.ts'
18
18
 
19
- // SIFTS
19
+ // UniProt mapping
20
20
  export * from './pdbUniProtMapping.ts'
21
- export * from './siftsNumbering.ts'
21
+ export * from './pdbEntry.ts'
22
22
 
23
23
  // Structure sources
24
24
  export * from './alphaFoldModels.ts'
25
- export * from './pdbeBestStructures.ts'
26
- export * from './pdbeEntryMolecules.ts'
27
25
  export * from './structureSources.ts'
28
26
  export * from './uniProtSearch.ts'
29
27
  export * from './dbIds.ts'
@@ -22,11 +22,11 @@ export interface RankedIsoform {
22
22
  }
23
23
 
24
24
  export interface ClassifiedIsoforms {
25
- // protein matches the structure residues, longest first
25
+ /** translates to exactly the structure's sequence, longest first */
26
26
  matches: RankedIsoform[]
27
- // has a protein sequence but doesn't match the structure, best-aligning first
27
+ /** translates to something else, best-aligning first */
28
28
  nonMatches: RankedIsoform[]
29
- // ids of the isoforms no protein sequence could be computed for
29
+ /** ids of the isoforms with no translation */
30
30
  noData: string[]
31
31
  }
32
32
 
@@ -68,7 +68,7 @@ function getScore(a: string, b: string) {
68
68
  const GAP_OPEN = -10
69
69
  const GAP_EXTEND = -0.5
70
70
 
71
- interface AlignmentResult {
71
+ export interface AlignmentResult {
72
72
  alignedSeq1: string
73
73
  alignedSeq2: string
74
74
  score: number