@volter/twin-sentry 0.1.37 → 1.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 (188) hide show
  1. package/README.md +21 -134
  2. package/api/spec/SOURCE.md +15 -0
  3. package/api/spec/doc-examples.json +12 -0
  4. package/api/spec/openapi.json.gz +0 -0
  5. package/api/spec/patches.json +5350 -0
  6. package/api/spec/sources.json +122 -0
  7. package/api/src/fetch.ts +18 -0
  8. package/api/src/generated/surface.gen.json +1 -0
  9. package/api/src/generated/ui.gen.json +1 -0
  10. package/api/src/index.ts +3 -0
  11. package/api/src/manifest.ts +136 -0
  12. package/api/src/semantics/api.ts +246 -0
  13. package/api/src/semantics/around.ts +36 -0
  14. package/api/src/semantics/doors.ts +50 -0
  15. package/api/src/semantics/index.ts +19 -0
  16. package/api/src/semantics/shared.ts +35 -0
  17. package/api/src/semantics/states.ts +17 -0
  18. package/dist/api/spec/SOURCE.md +15 -0
  19. package/dist/api/spec/doc-examples.json +12 -0
  20. package/dist/api/spec/openapi.json.gz +0 -0
  21. package/dist/api/spec/patches.json +5350 -0
  22. package/dist/api/spec/sources.json +122 -0
  23. package/dist/api/src/fetch.d.ts +2 -0
  24. package/dist/api/src/fetch.js +17 -0
  25. package/dist/api/src/fetch.ts +18 -0
  26. package/dist/api/src/generated/surface.gen.json +1 -0
  27. package/dist/api/src/generated/ui.gen.json +1 -0
  28. package/dist/api/src/index.d.ts +2 -0
  29. package/dist/api/src/index.js +3 -0
  30. package/dist/api/src/index.ts +3 -0
  31. package/dist/api/src/manifest.d.ts +2 -0
  32. package/dist/api/src/manifest.js +135 -0
  33. package/dist/api/src/manifest.ts +136 -0
  34. package/dist/api/src/semantics/api.d.ts +13 -0
  35. package/dist/api/src/semantics/api.js +267 -0
  36. package/dist/api/src/semantics/api.ts +246 -0
  37. package/dist/api/src/semantics/around.d.ts +2 -0
  38. package/dist/api/src/semantics/around.js +41 -0
  39. package/dist/api/src/semantics/around.ts +36 -0
  40. package/dist/api/src/semantics/doors.d.ts +8 -0
  41. package/dist/api/src/semantics/doors.js +39 -0
  42. package/dist/api/src/semantics/doors.ts +50 -0
  43. package/dist/api/src/semantics/index.d.ts +2 -0
  44. package/dist/api/src/semantics/index.js +15 -0
  45. package/dist/api/src/semantics/index.ts +19 -0
  46. package/dist/api/src/semantics/shared.d.ts +15 -0
  47. package/dist/api/src/semantics/shared.js +27 -0
  48. package/dist/api/src/semantics/shared.ts +35 -0
  49. package/dist/api/src/semantics/states.d.ts +24 -0
  50. package/dist/api/src/semantics/states.js +17 -0
  51. package/dist/api/src/semantics/states.ts +17 -0
  52. package/dist/generated/pack-facts.json +87 -0
  53. package/dist/ingest/spec/SOURCE.md +30 -0
  54. package/dist/ingest/spec/authentication.mdx.gz +0 -0
  55. package/dist/ingest/spec/compression.mdx.gz +0 -0
  56. package/dist/ingest/spec/doc-examples.json +216 -0
  57. package/dist/ingest/spec/envelope-items.mdx.gz +0 -0
  58. package/dist/ingest/spec/envelopes.mdx.gz +0 -0
  59. package/dist/ingest/spec/openapi.json +178 -0
  60. package/dist/ingest/spec/rate-limiting.mdx.gz +0 -0
  61. package/dist/ingest/spec/sources.json +25 -0
  62. package/dist/ingest/spec/transport.mdx.gz +0 -0
  63. package/dist/ingest/spec/write-spec.ts +192 -0
  64. package/dist/ingest/src/fetch.d.ts +2 -0
  65. package/dist/ingest/src/fetch.js +15 -0
  66. package/dist/ingest/src/fetch.ts +16 -0
  67. package/dist/ingest/src/generated/surface.gen.json +1 -0
  68. package/dist/ingest/src/generated/ui.gen.json +1 -0
  69. package/dist/ingest/src/index.d.ts +2 -0
  70. package/dist/ingest/src/index.js +3 -0
  71. package/dist/ingest/src/index.ts +3 -0
  72. package/dist/ingest/src/manifest.d.ts +2 -0
  73. package/dist/ingest/src/manifest.js +34 -0
  74. package/dist/ingest/src/manifest.ts +39 -0
  75. package/dist/ingest/src/semantics/api.d.ts +2 -0
  76. package/dist/ingest/src/semantics/api.js +240 -0
  77. package/dist/ingest/src/semantics/api.ts +188 -0
  78. package/dist/ingest/src/semantics/around.d.ts +2 -0
  79. package/dist/ingest/src/semantics/around.js +6 -0
  80. package/dist/ingest/src/semantics/around.ts +7 -0
  81. package/dist/ingest/src/semantics/index.d.ts +2 -0
  82. package/dist/ingest/src/semantics/index.js +4 -0
  83. package/dist/ingest/src/semantics/index.ts +8 -0
  84. package/dist/ingest/src/semantics/shared.d.ts +4 -0
  85. package/dist/ingest/src/semantics/shared.js +2 -0
  86. package/dist/ingest/src/semantics/shared.ts +7 -0
  87. package/dist/ingest/src/semantics/states.d.ts +1 -0
  88. package/dist/ingest/src/semantics/states.js +2 -0
  89. package/dist/ingest/src/semantics/states.ts +2 -0
  90. package/dist/journeys/coverage.json +205 -0
  91. package/dist/journeys/customer-life.json +923 -0
  92. package/dist/journeys/customer-life.outline.md +51 -0
  93. package/dist/journeys/decisions.json +170 -0
  94. package/dist/journeys/demand.json +136 -0
  95. package/dist/journeys/score.json +231 -0
  96. package/dist/journeys/unreachable.json +29 -0
  97. package/dist/journeys/vendor-examples.json +474 -0
  98. package/dist/spec/sources.json +76 -0
  99. package/dist/src/cli.js +12 -27
  100. package/dist/src/fetch.d.ts +2 -0
  101. package/dist/src/fetch.js +9 -0
  102. package/dist/src/index.d.ts +5 -15
  103. package/dist/src/index.js +12 -75
  104. package/dist/src/manifest.d.ts +2 -0
  105. package/dist/src/manifest.js +34 -0
  106. package/dist/src/semantics/shared.d.ts +87 -0
  107. package/dist/src/semantics/shared.js +411 -0
  108. package/dist/src/server.d.ts +7 -0
  109. package/dist/src/server.js +7 -0
  110. package/generated/pack-facts.json +87 -0
  111. package/ingest/spec/SOURCE.md +30 -0
  112. package/ingest/spec/authentication.mdx.gz +0 -0
  113. package/ingest/spec/compression.mdx.gz +0 -0
  114. package/ingest/spec/doc-examples.json +216 -0
  115. package/ingest/spec/envelope-items.mdx.gz +0 -0
  116. package/ingest/spec/envelopes.mdx.gz +0 -0
  117. package/ingest/spec/openapi.json +178 -0
  118. package/ingest/spec/rate-limiting.mdx.gz +0 -0
  119. package/ingest/spec/sources.json +25 -0
  120. package/ingest/spec/transport.mdx.gz +0 -0
  121. package/ingest/spec/write-spec.ts +192 -0
  122. package/ingest/src/fetch.ts +16 -0
  123. package/ingest/src/generated/surface.gen.json +1 -0
  124. package/ingest/src/generated/ui.gen.json +1 -0
  125. package/ingest/src/index.ts +3 -0
  126. package/ingest/src/manifest.ts +39 -0
  127. package/ingest/src/semantics/api.ts +188 -0
  128. package/ingest/src/semantics/around.ts +7 -0
  129. package/ingest/src/semantics/index.ts +8 -0
  130. package/ingest/src/semantics/shared.ts +7 -0
  131. package/ingest/src/semantics/states.ts +2 -0
  132. package/journeys/coverage.json +205 -0
  133. package/journeys/customer-life.json +923 -0
  134. package/journeys/customer-life.outline.md +51 -0
  135. package/journeys/decisions.json +170 -0
  136. package/journeys/demand.json +136 -0
  137. package/journeys/score.json +231 -0
  138. package/journeys/unreachable.json +29 -0
  139. package/journeys/vendor-examples.json +474 -0
  140. package/package.json +16 -42
  141. package/spec/sources.json +76 -0
  142. package/src/cli.ts +12 -24
  143. package/src/fetch.ts +10 -0
  144. package/src/index.ts +12 -143
  145. package/src/manifest.ts +40 -0
  146. package/src/semantics/shared.ts +443 -0
  147. package/src/server.ts +8 -0
  148. package/client/sentry-mirror.css +0 -99
  149. package/client/sentry-mirror.tsx +0 -352
  150. package/dist/client/sentry-mirror.bundle.js +0 -388
  151. package/dist/client/sentry-mirror.css +0 -99
  152. package/dist/client/sentry-mirror.d.ts +0 -17
  153. package/dist/client/sentry-mirror.js +0 -156
  154. package/dist/client/sentry-mirror.tsx +0 -352
  155. package/dist/src/sentry-budget.d.ts +0 -50
  156. package/dist/src/sentry-budget.js +0 -145
  157. package/dist/src/sentry-capabilities.d.ts +0 -3
  158. package/dist/src/sentry-capabilities.js +0 -1180
  159. package/dist/src/sentry-conformance.d.ts +0 -22
  160. package/dist/src/sentry-conformance.js +0 -97
  161. package/dist/src/sentry-connector.d.ts +0 -77
  162. package/dist/src/sentry-connector.js +0 -226
  163. package/dist/src/sentry-events.d.ts +0 -54
  164. package/dist/src/sentry-events.js +0 -132
  165. package/dist/src/sentry-ingest.d.ts +0 -137
  166. package/dist/src/sentry-ingest.js +0 -387
  167. package/dist/src/sentry-mirror-ui.d.ts +0 -38
  168. package/dist/src/sentry-mirror-ui.js +0 -162
  169. package/dist/src/sentry-perform-harness.d.ts +0 -9
  170. package/dist/src/sentry-perform-harness.js +0 -20
  171. package/dist/src/sentry-server.d.ts +0 -14
  172. package/dist/src/sentry-server.js +0 -27
  173. package/dist/src/sentry-twin.d.ts +0 -17
  174. package/dist/src/sentry-twin.js +0 -1739
  175. package/dist/test-fixtures/sentry-openapi-operations.SOURCE.md +0 -24
  176. package/dist/test-fixtures/sentry-openapi-operations.json +0 -1837
  177. package/src/sentry-budget.ts +0 -171
  178. package/src/sentry-capabilities.ts +0 -1222
  179. package/src/sentry-conformance.ts +0 -110
  180. package/src/sentry-connector.ts +0 -260
  181. package/src/sentry-events.ts +0 -172
  182. package/src/sentry-ingest.ts +0 -471
  183. package/src/sentry-mirror-ui.ts +0 -162
  184. package/src/sentry-perform-harness.ts +0 -19
  185. package/src/sentry-server.ts +0 -35
  186. package/src/sentry-twin.ts +0 -1615
  187. package/test-fixtures/sentry-openapi-operations.SOURCE.md +0 -24
  188. package/test-fixtures/sentry-openapi-operations.json +0 -1837
package/package.json CHANGED
@@ -1,40 +1,35 @@
1
1
  {
2
2
  "name": "@volter/twin-sentry",
3
- "version": "0.1.37",
4
- "description": "Local Sentry twin — a faithful, stateful local Sentry error-monitoring API your real `@sentry/node` SDK talks to unmodified. Ingest captureException events into grouped issues, browse the Web API + dashboard mirror, simulate, and fork. Built on @volter/world-core.",
3
+ "version": "1.0.0",
4
+ "description": "Sentry Protocol 3 twin: demanded SDK envelopes, release/source-map APIs, account project and client-key setup, and derived vendor-backed reads.",
5
5
  "keywords": [
6
6
  "twin",
7
- "local",
8
- "mock",
9
- "mirror",
10
- "simulator",
11
- "fixtures",
12
- "testing",
13
- "sdk",
14
- "api",
15
- "localstack",
16
7
  "sentry",
17
- "error-monitoring",
18
- "observability"
8
+ "error-tracking",
9
+ "envelope",
10
+ "sentry-cli",
11
+ "source-maps"
19
12
  ],
20
13
  "author": "Volter (https://github.com/volter-ai)",
21
14
  "license": "Apache-2.0",
22
15
  "files": [
23
16
  "src",
24
- "client",
25
- "test-fixtures",
17
+ "journeys",
18
+ "api",
19
+ "spec",
20
+ "ingest",
26
21
  "README.md",
27
22
  "LICENSE",
28
23
  "!**/*.test.ts",
29
- "!**/*.test.tsx",
30
- "dist"
24
+ "dist",
25
+ "generated"
31
26
  ],
32
27
  "repository": {
33
28
  "type": "git",
34
- "url": "git+https://github.com/volter-ai/twin.git",
35
- "directory": "packages/twin/sentry"
29
+ "url": "git+https://github.com/volter-ai/twin-packs-p3.git",
30
+ "directory": "sentry"
36
31
  },
37
- "homepage": "https://world.volter.ai/twins/sentry",
32
+ "homepage": "https://github.com/volter-ai/twin-packs-p3/tree/main/sentry#readme",
38
33
  "type": "module",
39
34
  "exports": {
40
35
  ".": {
@@ -45,29 +40,8 @@
45
40
  "bin": {
46
41
  "world-sentry": "dist/src/cli.js"
47
42
  },
48
- "scripts": {
49
- "test": "bun test src/*.test.ts",
50
- "typecheck": "tsc --noEmit",
51
- "build": "node ../../../scripts/publish/build.mjs",
52
- "prepack": "node ../../../scripts/publish/prepare-publish.mjs prepack",
53
- "postpack": "node ../../../scripts/publish/prepare-publish.mjs postpack"
54
- },
55
- "dependencies": {
56
- "react": "^19.2.7",
57
- "react-dom": "^19.2.7"
58
- },
59
43
  "peerDependencies": {
60
- "@volter/world-core": "2.0.37"
61
- },
62
- "devDependencies": {
63
- "@volter/world-core": "2.0.37",
64
- "@volter/world-tooling": "0.1.0",
65
- "@sentry/node": "^10.64.0",
66
- "@types/bun": "^1.2.20",
67
- "@types/node": "^24.0.0",
68
- "@types/react": "^19.2.17",
69
- "@types/react-dom": "^19.2.3",
70
- "typescript": "^5.9.0"
44
+ "@volter/world-core": "^3.0.38"
71
45
  },
72
46
  "engines": {
73
47
  "node": ">=22.3"
@@ -0,0 +1,76 @@
1
+ {
2
+ "https://raw.githubusercontent.com/getsentry/sentry/2efdd4760a75a3d395e3534b7f66a7fbb0c3f22e/src/sentry/api/serializers/models/project_key.py": {
3
+ "status": 200,
4
+ "checked": "2026-10-03",
5
+ "quotes": {
6
+ "ProjectKeySerializerResponse": true
7
+ }
8
+ },
9
+ "https://raw.githubusercontent.com/getsentry/sentry/2efdd4760a75a3d395e3534b7f66a7fbb0c3f22e/src/sentry/features/permanent.py": {
10
+ "status": 200,
11
+ "checked": "2026-10-03",
12
+ "quotes": {
13
+ "organizations:advanced-search": true,
14
+ "organizations:change-alerts": true,
15
+ "organizations:crash-rate-alerts": true,
16
+ "organizations:custom-symbol-sources": true,
17
+ "organizations:data-forwarding": true,
18
+ "organizations:discover-basic": true,
19
+ "organizations:discover-query": true,
20
+ "organizations:event-attachments": true,
21
+ "organizations:integrations-alert-rule": true,
22
+ "organizations:integrations-chat-unfurl": true,
23
+ "organizations:integrations-codeowners": true,
24
+ "organizations:integrations-enterprise-alert-rule": true,
25
+ "organizations:integrations-enterprise-incident-management": true,
26
+ "organizations:integrations-event-hooks": true,
27
+ "organizations:integrations-incident-management": true,
28
+ "organizations:integrations-issue-basic": true,
29
+ "organizations:integrations-issue-sync": true,
30
+ "organizations:integrations-scm-multi-org": true,
31
+ "organizations:integrations-stacktrace-link": true,
32
+ "organizations:integrations-ticket-rules": true,
33
+ "organizations:integrations-vercel": true,
34
+ "organizations:performance-view": true,
35
+ "organizations:relay": true,
36
+ "organizations:sso-basic": true,
37
+ "organizations:sso-saml2": true,
38
+ "organizations:team-insights": true,
39
+ "organizations:team-roles": true,
40
+ "organizations:uptime": true
41
+ }
42
+ },
43
+ "https://raw.githubusercontent.com/getsentry/sentry/2efdd4760a75a3d395e3534b7f66a7fbb0c3f22e/src/sentry/features/temporary.py": {
44
+ "status": 200,
45
+ "checked": "2026-10-03",
46
+ "quotes": {
47
+ "organizations:dashboards-basic": true,
48
+ "organizations:dashboards-edit": true,
49
+ "organizations:insight-modules": true,
50
+ "organizations:invite-members": true,
51
+ "organizations:sentry-app-schema-form-migration": true,
52
+ "organizations:session-replay-ui": true
53
+ }
54
+ },
55
+ "https://raw.githubusercontent.com/getsentry/sentry/2efdd4760a75a3d395e3534b7f66a7fbb0c3f22e/src/sentry/models/projectkey.py": {
56
+ "status": 200,
57
+ "checked": "2026-10-03",
58
+ "quotes": {
59
+ "secret_key = ProjectKey.generate_api_key()": true
60
+ }
61
+ },
62
+ "https://raw.githubusercontent.com/getsentry/sentry/2efdd4760a75a3d395e3534b7f66a7fbb0c3f22e/src/sentry/projectoptions/defaults.py": {
63
+ "status": 200,
64
+ "checked": "2026-10-03",
65
+ "quotes": {
66
+ "sentry:default_loader_version": true
67
+ }
68
+ },
69
+ "https://raw.githubusercontent.com/getsentry/sentry/2efdd4760a75a3d395e3534b7f66a7fbb0c3f22e/src/sentry/utils/numbers.py": {
70
+ "status": 200,
71
+ "checked": "2026-10-03",
72
+ "quotes": {
73
+ "0123456789ABCDEFGHJKMNPQRSTVWXYZ": true
74
+ }
75
+ }
76
+ }
package/src/cli.ts CHANGED
@@ -1,34 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { keepProcessAlive } from '@volter/world-core/lifecycle';
3
- // world-sentry CLI: serve the Sentry API twin (ingestion + Web API), the dashboard mirror
4
- // UI, or run conformance. (Conformance lives in dev-tooling; cli.ts must not import it, so
5
- // it's loaded lazily only when the `conformance` command is invoked.)
2
+ // world-sentry: serve the sentry twin.
6
3
  import { hasFlag, optionValue } from '@volter/world-core/args';
7
- import { createSentryTwinServer } from './sentry-server.ts';
8
- import { createSentryMirrorServer } from './sentry-mirror-ui.ts';
9
- import { defaultDsn } from './sentry-ingest.ts';
4
+ import { keepProcessAlive } from '@volter/world-core/lifecycle';
5
+ import { createSentryTwinServer } from './server.ts';
10
6
 
11
7
  const [cmd, ...rest] = process.argv.slice(2);
12
8
  const port = Number(optionValue(rest, '--port', '0')) || undefined;
13
9
  const root = optionValue(rest, '--root') || undefined;
14
- const readOnly = hasFlag(rest, '--read-only'); // a twin accepts writes/events unless read-only
10
+ const readOnly = hasFlag(rest, '--read-only');
11
+ // the World's managed Postgres, which the runtime binds a pack declaring managedDatabase to
12
+ const database = optionValue(rest, '--database') || undefined;
13
+ // the World's scenario file, for a model vendor's turns
14
+ const scenarioPath = optionValue(rest, '--scenario') || undefined;
15
15
 
16
- if (cmd === 'serve') {
17
- const s = await createSentryTwinServer({ readOnly, ...(root ? { root } : {}), ...(port ? { port } : {}) });
18
- const origin = `http://127.0.0.1:${s.port}`;
19
- process.stdout.write(`sentry twin (ingest + Web API)${readOnly ? ' [read-only]' : ''} at ${origin}\n`);
20
- process.stdout.write(` point @sentry/node at DSN: ${defaultDsn(origin)}\n`);
21
- await keepProcessAlive();
22
- } else if (cmd === 'mirror') {
23
- const s = await createSentryMirrorServer({ ...(root ? { root } : {}), ...(port ? { port } : {}) });
24
- process.stdout.write(`sentry mirror UI (dashboard) at http://127.0.0.1:${s.port}\n`);
16
+ if (cmd === 'serve' || cmd === undefined) {
17
+ const s = await createSentryTwinServer({ readOnly, ...(root ? { root } : {}), ...(port ? { port } : {}), ...(database ? { database } : {}), ...(scenarioPath ? { scenarioPath } : {}) });
18
+ process.stdout.write(`sentry twin${readOnly ? ' [read-only]' : ''} at http://127.0.0.1:${s.port}\n`);
25
19
  await keepProcessAlive();
26
- } else if (cmd === 'conformance') {
27
- // dev-only: dynamic import so the conformance module never enters the runtime entrypoints.
28
- const { checkSentryConformance } = await import('./sentry-conformance.ts');
29
- const report = await checkSentryConformance({ ...(root ? { root } : {}) });
30
- process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
31
- if (!report.ok) process.exitCode = 1;
32
20
  } else {
33
- process.stdout.write('Usage: world-sentry serve|mirror|conformance [--port N] [--root DIR] [--read-only]\n');
21
+ process.stdout.write('Usage: world-sentry serve [--port N] [--root DIR] [--read-only] [--database URL] [--scenario FILE]\n');
34
22
  }
package/src/fetch.ts ADDED
@@ -0,0 +1,10 @@
1
+ // GENERATED by scripts/create-pack.ts (--init, --index): a fixed file. The kernel serves the vendor's discovery door and
2
+ // sends each request to the lane its manifest's routes name (architecture, "Other wires: lanes").
3
+ import { createVendorFetch, type DerivedFetch, type PackFetchOptions } from '@volter/world-core';
4
+ import { manifest } from './manifest.ts';
5
+ import { createApiLaneFetch, manifest as api_manifest } from '../api/src/index.ts';
6
+ import { createIngestLaneFetch, manifest as ingest_manifest } from '../ingest/src/index.ts';
7
+
8
+ export function createSentryFetch(options: PackFetchOptions = {}): DerivedFetch {
9
+ return createVendorFetch(manifest, { "api": { fetch: createApiLaneFetch(options), manifest: api_manifest }, "ingest": { fetch: createIngestLaneFetch(options), manifest: ingest_manifest } });
10
+ }
package/src/index.ts CHANGED
@@ -1,145 +1,14 @@
1
- // @volter/twin-sentry — the Sentry twin (one vendor, one package), built on the shared
2
- // @volter/world-core kernel. Two API families over local event-sourced state: INGESTION (the
3
- // `@sentry/node` store/envelope endpoints → grouped issues) and the WEB API (/api/0/...:
4
- // issues, events, projects, keys/DSN, releases, deploys, orgs, teams, alert rules), plus
5
- // signed alert webhooks and a React dashboard mirror. No real Sentry is ever contacted.
6
- // (Conformance tooling lives in @volter/world-tooling, a dev dependency — not shipped here.)
7
- export { handleSentryTwinRequest } from './sentry-twin.ts';
8
- export type { SentryRequest, SentryResponse } from './sentry-twin.ts';
9
- export { createSentryTwinFetch, createSentryTwinServer, type SentryTwinFetchOptions } from './sentry-server.ts';
10
- export {
11
- defaultDsn,
12
- DEFAULT_ORG,
13
- DEFAULT_PROJECT,
14
- DEFAULT_PROJECT_ID,
15
- DEFAULT_PUBLIC_KEY,
16
- ensureDefaultProject,
17
- envelopeEvents,
18
- eventCulprit,
19
- eventTitle,
20
- fingerprintText,
21
- hashFingerprint,
22
- ingestEvent,
23
- issueIdFor,
24
- normalizeFingerprintText,
25
- parseEnvelope,
26
- publicKeyFromAuthHeader,
27
- publicKeyFromDsn,
28
- resolveProjectKey,
29
- resolvePublicKey,
30
- } from './sentry-ingest.ts';
31
- export type { IngestOutcome, ParsedEnvelope, ResolvedKey, SentryEventPayload, SentryExceptionValue, SentryFrame } from './sentry-ingest.ts';
32
- export {
33
- computeSentrySignature,
34
- constructSentryWebhook,
35
- emitIssueAlert,
36
- listAlertRules,
37
- registerAlertRule,
38
- SentrySignatureVerificationError,
39
- verifySentrySignature,
40
- } from './sentry-events.ts';
41
- export type { AlertTrigger, SentryWebhook, SentryWebhookAction, SentryWebhookDelivery } from './sentry-events.ts';
42
- export {
43
- liveSentryExecute,
44
- mapIssue,
45
- mapProject,
46
- mapRelease,
47
- pullSentryIssues,
48
- pullSentryProjects,
49
- pullSentryReleases,
50
- pushSentryAction,
51
- sentryRequestForAction,
52
- syncSentryFromReal,
53
- } from './sentry-connector.ts';
54
- export type { SentryExecute, LiveSentryOptions } from './sentry-connector.ts';
55
- // The client-side rate budget — the fail-closed backstop `liveSentryExecute` routes every live
56
- // request through. The MECHANISM is the kernel's shared, vendor-agnostic `RateBudget`; what lives
57
- // here is Sentry's DECLARATION (window/ceiling/per-endpoint weights) plus the vendor-bound
58
- // bindings. Exported so an operator can inspect spend (`snapshot`) and so a caller can catch
59
- // `SentryBudgetError` by type; there is deliberately no export that disables the guard.
60
- export {
61
- SENTRY_BUDGET_CEILING,
62
- SENTRY_BUDGET_MAX_RETRY_AFTER_S,
63
- SENTRY_BUDGET_WINDOW_MS,
64
- SENTRY_CALL_WEIGHTS,
65
- SENTRY_RATE_BUDGET,
66
- SentryBudget,
67
- SentryBudgetError,
68
- sentryBudgetPath,
69
- sentryCallWeight,
70
- } from './sentry-budget.ts';
71
- export type { SentryBudgetErrorKind, SentryBudgetOptions, SentryBudgetReservation, SentryBudgetSnapshot } from './sentry-budget.ts';
72
- export {
73
- buildSentryMirrorClient,
74
- createSentryMirrorServer,
75
- eventTags,
76
- formatCount,
77
- latestStacktrace,
78
- levelTone,
79
- sentryMirrorHtml,
80
- statusTone,
81
- timeAgo,
82
- } from './sentry-mirror-ui.ts';
83
- export type { IssueRow, StackFrame } from './sentry-mirror-ui.ts';
1
+ // @volter/twin-sentry — the sentry twin (Protocol 3). A fixed file (create-pack): the descriptor is the manifest's, and the
2
+ // kernel derives the vendor-backed half from the generated surface (architecture, "The real-system adapters").
3
+ import { packOf, registerPack, type DerivedSurface } from '@volter/world-core';
4
+ import { manifest } from './manifest.ts';
5
+ import { manifest as apiManifest } from '../api/src/manifest.ts';
6
+ import apiSurface from '../api/src/generated/surface.gen.json' with { type: 'json' };
7
+ import { manifest as ingestManifest } from '../ingest/src/manifest.ts';
8
+ import ingestSurface from '../ingest/src/generated/surface.gen.json' with { type: 'json' };
84
9
 
85
- // Registry descriptor: the pack self-describes so tooling can discover it. A consumer does
86
- // `registerPack(pack)` after importing this package.
87
- import type { TwinPack } from '@volter/world-core';
88
- import { SENTRY_RATE_BUDGET as RATE_BUDGET } from './sentry-budget.ts';
89
- import { performSentryAction, syncSentryFromRemote } from './sentry-connector.ts';
10
+ export { createSentryFetch } from './fetch.ts';
11
+ export { createSentryTwinServer } from './server.ts';
12
+ export { manifest };
90
13
 
91
- export const pack: TwinPack = {
92
- // PROTOCOL 2 (docs/contributing/architecture.md#protocol-2-the-pack-is-a-plugin): the pack is a plugin — its wire, its tree, and its half of the real
93
- // state system. Moved 2026-09-08. TRIAGE is what crosses to Sentry — an issue resolved, assigned, muted;
94
- // everything else this twin holds is something Sentry told it.
95
- protocol: '2',
96
- refresh: { every: '2m', webhook: true, onDemand: { atMost: '30s' } },
97
- stateSystem: { perform: performSentryAction, refresh: syncSentryFromRemote },
98
- // the round trip: an organization, then a project in it — the two things a Sentry account is made of
99
- // the round trip: an organization, a team in it, then a project under that team — Sentry's own create
100
- // path for a project is /teams/:org/:team/projects/, not the organization
101
- roundTrip: [
102
- { method: 'POST', path: '/api/0/organizations/', body: { name: 'Round Trip', slug: 'round-trip' }, headers: { authorization: 'Bearer round-trip' } },
103
- { method: 'POST', path: '/api/0/organizations/round-trip/teams/', body: { name: 'Round Trip', slug: 'round-trip' }, headers: { authorization: 'Bearer round-trip' } },
104
- { method: 'POST', path: '/api/0/teams/round-trip/round-trip/projects/', body: { name: 'Round Trip', platform: 'node' }, headers: { authorization: 'Bearer round-trip' } },
105
- // a project's slug is unique inside its org, so the create above rightly refuses a second one on a
106
- // branch that already has it — the vendor's own truth. The last write is therefore the one a world
107
- // repeats freely: triage on the project's own issue stream.
108
- { method: 'PUT', path: '/api/0/projects/round-trip/round-trip/', body: { platform: 'node', digestsMinDelay: 60 }, headers: { authorization: 'Bearer round-trip' } },
109
- ],
110
- parityOrigin: 'http://twin',
111
- vendor: 'sentry',
112
- // The SAME object sentry-budget.ts declares at module load — one source of truth, so registering
113
- // the pack and importing the connector can never arm two different ceilings.
114
- rateBudget: RATE_BUDGET,
115
- transport: 'rest',
116
- archetype: 'crud',
117
- bin: 'world-sentry',
118
- resources: ['organization', 'team', 'project', 'project_key', 'issue', 'event', 'event_attachment', 'session', 'project_ownership', 'codeowners', 'project_filter', 'release', 'release_file', 'deploy', 'alert_rule', 'metric_alert', 'org_integration'],
119
- specSource: 'Sentry API reference (https://docs.sentry.io/api/) — ingest store/envelope + Web API /api/0/',
120
- description: 'Sentry REST twin — SDK ingestion → grouped issues, Web API, signed alert webhooks, dashboard mirror.',
121
- // Adoption + interception, moved off the central maps unchanged (descriptor-first back-migration, adding-a-twin.md §3,
122
- // 2026-08-31). The four canonical clients plus the further first-party @sentry
123
- // framework SDKs of the same ingest surface — battery-observed: sentry was the single
124
- // most-missed vendor, 13 repos, largely via these — and the whole `@sentry/` scope so a
125
- // satellite package like `@sentry/cli` still detects.
126
- adoption: {
127
- // Sentry's official Python SDK - the one distribution behind every Python integration.
128
- pypi: ['sentry-sdk'],
129
- sdks: [
130
- '@sentry/node', '@sentry/browser', '@sentry/react', '@sentry/nextjs',
131
- '@sentry/vue', '@sentry/sveltekit', '@sentry/astro', '@sentry/remix',
132
- '@sentry/electron', '@sentry/react-native',
133
- ],
134
- scopes: ['@sentry/'],
135
- // 'APPSMITHSENTRY' — appsmith names its DSN APPSMITH_SENTRY_DSN, an app-prefixed Sentry
136
- // credential for the same ingest surface (ladder classification 2026-09-02).
137
- envStems: ['SENTRY', 'APPSMITHSENTRY'],
138
- },
139
- // sentry.io (the web/REST API) plus the per-organization DSN ingest hosts
140
- // (`o<org-id>.ingest.sentry.io`), which need the suffix form.
141
- hosts: [{ host: 'sentry.io' }, { suffix: '.ingest.sentry.io' }],
142
- // The @sentry/node SDK POSTs to <dsn-host>/api/:projectId/envelope/; the dashboard hits
143
- // /api/0/. The dev proxy forwards both prefixes to the twin and strips the sentry.io host.
144
- browserRouting: { apiPathPrefix: '/api/', loaderHost: 'https://sentry.io' },
145
- };
14
+ export const pack = registerPack(packOf(manifest, { "api": { manifest: apiManifest, surface: apiSurface as unknown as DerivedSurface }, "ingest": { manifest: ingestManifest, surface: ingestSurface as unknown as DerivedSurface } }));
@@ -0,0 +1,40 @@
1
+ // Sentry's manifest: a vendor of two APIs, each a lane (architecture, "Other wires: lanes"): the web API that sentry-cli
2
+ // and integrations call (`api`, from Sentry's OpenAPI document), and the ingestion endpoint every SDK sends its envelopes
3
+ // to (`ingest`, written from Sentry's SDK developer documentation). A DSN names its organization's ingest host
4
+ // (`o<id>.ingest[.<region>].sentry.io`); the API is sentry.io's, and a region's (us.sentry.io, de.sentry.io).
5
+ import type { VendorManifest } from '@volter/world-core';
6
+
7
+ export const manifest: VendorManifest = {
8
+ vendor: 'sentry',
9
+ discovery: {
10
+ twinOf: 'Sentry: the envelopes its SDKs send (errors, transactions, sessions, replays, profiles, cron check-ins, feedback, logs, metrics), and its web API for events, issues, releases and source maps',
11
+ stores: 'organizations, projects and client keys, auth tokens (by their SHA-256), events and issues, and every other envelope item; releases and artifact bundles',
12
+ },
13
+ lanes: {
14
+ routes: [
15
+ { lane: 'ingest', host: '(^|\\.)ingest(\\.[a-z]+)?\\.sentry\\.io$' },
16
+ { lane: 'api', host: '^([a-z]+\\.)?sentry\\.io$' },
17
+ ],
18
+ default: 'api',
19
+ },
20
+ descriptor: {
21
+ protocol: '3',
22
+ transport: 'rest',
23
+ archetype: 'crud',
24
+ bin: 'world-sentry',
25
+ resources: ['organization', 'project', 'project_key', 'event', 'issue', 'release', 'monitor', 'check_in'],
26
+ specSource: "Sentry's OpenAPI document (api/spec, sentry-api-schema 98ec014, patched with evidence) and its SDK developer documentation's envelope endpoint (ingest/spec)",
27
+ description: 'Sentry twin — the envelope endpoint every SDK sends to (events grouped into issues, transactions, sessions, replays, profiles, check-ins, feedback, logs, metrics), and release and source-map APIs used by Cal.com, Postiz and Rallly, account project/key setup, and core vendor-backed reads.',
28
+ adoption: { sdks: ['@sentry/astro', '@sentry/browser', '@sentry/electron', '@sentry/nextjs', '@sentry/node', '@sentry/nestjs', '@sentry/react', '@sentry/react-native', '@sentry/remix', '@sentry/sveltekit', '@sentry/vue', '@sentry/cli'], pypi: ['sentry-sdk'], envStems: ['APPSMITHSENTRY', 'SENTRY'] },
29
+ hosts: [{ host: 'sentry.io' }, { host: 'us.sentry.io' }, { host: 'de.sentry.io' }, { suffix: '.ingest.sentry.io' }, { suffix: '.ingest.us.sentry.io' }, { suffix: '.ingest.de.sentry.io' }],
30
+ endpointEnvNone: "an SDK sends to its DSN's host and sentry-cli to SENTRY_URL (sentry.io by default); the DSN the World issues names the World's ingest host, claimed by the host rules",
31
+ // Bootstrap: account sign-up, first credential and the project/key named by this env, stable at every boot.
32
+ credentialDoor: {
33
+ path: '/_twin/app-credentials', body: {},
34
+ fill: {
35
+ SENTRY_DSN: 'dsn', NEXT_PUBLIC_SENTRY_DSN: 'dsn', NEXT_PUBLIC_SENTRY_DSN_CLIENT: 'dsn', SENTRY_FRONT_DSN: 'dsn', SENTRY_DSN_API: 'dsn', VITE_SENTRY_DSN: 'dsn', EXPO_PUBLIC_SENTRY_DSN: 'dsn',
36
+ SENTRY_AUTH_TOKEN: 'auth_token', SENTRY_ORG: 'org', SENTRY_ORGANIZATION: 'org', SENTRY_PROJECT: 'project',
37
+ },
38
+ },
39
+ },
40
+ };