@volter/twin-sentry 0.1.37 → 1.0.1

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 (189) hide show
  1. package/README.md +28 -140
  2. package/api/spec/SOURCE.md +32 -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 +137 -0
  12. package/api/src/semantics/api.ts +247 -0
  13. package/api/src/semantics/around.ts +36 -0
  14. package/api/src/semantics/doors.ts +76 -0
  15. package/api/src/semantics/index.ts +19 -0
  16. package/api/src/semantics/shared.ts +31 -0
  17. package/api/src/semantics/states.ts +17 -0
  18. package/dist/api/spec/SOURCE.md +32 -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 +136 -0
  33. package/dist/api/src/manifest.ts +137 -0
  34. package/dist/api/src/semantics/api.d.ts +13 -0
  35. package/dist/api/src/semantics/api.js +269 -0
  36. package/dist/api/src/semantics/api.ts +247 -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 +5 -0
  41. package/dist/api/src/semantics/doors.js +71 -0
  42. package/dist/api/src/semantics/doors.ts +76 -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 +14 -0
  47. package/dist/api/src/semantics/shared.js +26 -0
  48. package/dist/api/src/semantics/shared.ts +31 -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/ingest/spec/SOURCE.md +30 -0
  53. package/dist/ingest/spec/authentication.mdx.gz +0 -0
  54. package/dist/ingest/spec/compression.mdx.gz +0 -0
  55. package/dist/ingest/spec/doc-examples.json +216 -0
  56. package/dist/ingest/spec/envelope-items.mdx.gz +0 -0
  57. package/dist/ingest/spec/envelopes.mdx.gz +0 -0
  58. package/dist/ingest/spec/openapi.json +178 -0
  59. package/dist/ingest/spec/rate-limiting.mdx.gz +0 -0
  60. package/dist/ingest/spec/sources.json +25 -0
  61. package/dist/ingest/spec/transport.mdx.gz +0 -0
  62. package/dist/ingest/spec/write-spec.ts +192 -0
  63. package/dist/ingest/src/fetch.d.ts +2 -0
  64. package/dist/ingest/src/fetch.js +15 -0
  65. package/dist/ingest/src/fetch.ts +16 -0
  66. package/dist/ingest/src/generated/surface.gen.json +1 -0
  67. package/dist/ingest/src/generated/ui.gen.json +1 -0
  68. package/dist/ingest/src/index.d.ts +2 -0
  69. package/dist/ingest/src/index.js +3 -0
  70. package/dist/ingest/src/index.ts +3 -0
  71. package/dist/ingest/src/manifest.d.ts +2 -0
  72. package/dist/ingest/src/manifest.js +37 -0
  73. package/dist/ingest/src/manifest.ts +42 -0
  74. package/dist/ingest/src/semantics/api.d.ts +2 -0
  75. package/dist/ingest/src/semantics/api.js +240 -0
  76. package/dist/ingest/src/semantics/api.ts +188 -0
  77. package/dist/ingest/src/semantics/around.d.ts +2 -0
  78. package/dist/ingest/src/semantics/around.js +6 -0
  79. package/dist/ingest/src/semantics/around.ts +7 -0
  80. package/dist/ingest/src/semantics/index.d.ts +2 -0
  81. package/dist/ingest/src/semantics/index.js +4 -0
  82. package/dist/ingest/src/semantics/index.ts +8 -0
  83. package/dist/ingest/src/semantics/shared.d.ts +4 -0
  84. package/dist/ingest/src/semantics/shared.js +2 -0
  85. package/dist/ingest/src/semantics/shared.ts +7 -0
  86. package/dist/ingest/src/semantics/states.d.ts +1 -0
  87. package/dist/ingest/src/semantics/states.js +2 -0
  88. package/dist/ingest/src/semantics/states.ts +2 -0
  89. package/dist/journeys/coverage.json +205 -0
  90. package/dist/journeys/customer-life.json +921 -0
  91. package/dist/journeys/customer-life.outline.md +51 -0
  92. package/dist/journeys/decisions.json +170 -0
  93. package/dist/journeys/demand.json +92 -0
  94. package/dist/journeys/first-use.json +22 -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 +13 -75
  104. package/dist/src/manifest.d.ts +2 -0
  105. package/dist/src/manifest.js +35 -0
  106. package/dist/src/semantics/shared.d.ts +88 -0
  107. package/dist/src/semantics/shared.js +407 -0
  108. package/dist/src/server.d.ts +7 -0
  109. package/dist/src/server.js +7 -0
  110. package/generated/pack-facts.json +101 -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 +42 -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 +921 -0
  134. package/journeys/customer-life.outline.md +51 -0
  135. package/journeys/decisions.json +170 -0
  136. package/journeys/demand.json +92 -0
  137. package/journeys/first-use.json +22 -0
  138. package/journeys/score.json +231 -0
  139. package/journeys/unreachable.json +29 -0
  140. package/journeys/vendor-examples.json +474 -0
  141. package/package.json +22 -47
  142. package/spec/sources.json +76 -0
  143. package/src/cli.ts +12 -24
  144. package/src/fetch.ts +10 -0
  145. package/src/index.ts +13 -143
  146. package/src/manifest.ts +41 -0
  147. package/src/semantics/shared.ts +439 -0
  148. package/src/server.ts +8 -0
  149. package/client/sentry-mirror.css +0 -99
  150. package/client/sentry-mirror.tsx +0 -352
  151. package/dist/client/sentry-mirror.bundle.js +0 -388
  152. package/dist/client/sentry-mirror.css +0 -99
  153. package/dist/client/sentry-mirror.d.ts +0 -17
  154. package/dist/client/sentry-mirror.js +0 -156
  155. package/dist/client/sentry-mirror.tsx +0 -352
  156. package/dist/src/sentry-budget.d.ts +0 -50
  157. package/dist/src/sentry-budget.js +0 -145
  158. package/dist/src/sentry-capabilities.d.ts +0 -3
  159. package/dist/src/sentry-capabilities.js +0 -1180
  160. package/dist/src/sentry-conformance.d.ts +0 -22
  161. package/dist/src/sentry-conformance.js +0 -97
  162. package/dist/src/sentry-connector.d.ts +0 -77
  163. package/dist/src/sentry-connector.js +0 -226
  164. package/dist/src/sentry-events.d.ts +0 -54
  165. package/dist/src/sentry-events.js +0 -132
  166. package/dist/src/sentry-ingest.d.ts +0 -137
  167. package/dist/src/sentry-ingest.js +0 -387
  168. package/dist/src/sentry-mirror-ui.d.ts +0 -38
  169. package/dist/src/sentry-mirror-ui.js +0 -162
  170. package/dist/src/sentry-perform-harness.d.ts +0 -9
  171. package/dist/src/sentry-perform-harness.js +0 -20
  172. package/dist/src/sentry-server.d.ts +0 -14
  173. package/dist/src/sentry-server.js +0 -27
  174. package/dist/src/sentry-twin.d.ts +0 -17
  175. package/dist/src/sentry-twin.js +0 -1739
  176. package/dist/test-fixtures/sentry-openapi-operations.SOURCE.md +0 -24
  177. package/dist/test-fixtures/sentry-openapi-operations.json +0 -1837
  178. package/src/sentry-budget.ts +0 -171
  179. package/src/sentry-capabilities.ts +0 -1222
  180. package/src/sentry-conformance.ts +0 -110
  181. package/src/sentry-connector.ts +0 -260
  182. package/src/sentry-events.ts +0 -172
  183. package/src/sentry-ingest.ts +0 -471
  184. package/src/sentry-mirror-ui.ts +0 -162
  185. package/src/sentry-perform-harness.ts +0 -19
  186. package/src/sentry-server.ts +0 -35
  187. package/src/sentry-twin.ts +0 -1615
  188. package/test-fixtures/sentry-openapi-operations.SOURCE.md +0 -24
  189. package/test-fixtures/sentry-openapi-operations.json +0 -1837
@@ -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/dist/src/cli.js CHANGED
@@ -1,36 +1,21 @@
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.js";
8
- import { createSentryMirrorServer } from "./sentry-mirror-ui.js";
9
- import { defaultDsn } from "./sentry-ingest.js";
4
+ import { keepProcessAlive } from '@volter/world-core/lifecycle';
5
+ import { createSentryTwinServer } from "./server.js";
10
6
  const [cmd, ...rest] = process.argv.slice(2);
11
7
  const port = Number(optionValue(rest, '--port', '0')) || undefined;
12
8
  const root = optionValue(rest, '--root') || undefined;
13
- const readOnly = hasFlag(rest, '--read-only'); // a twin accepts writes/events unless read-only
14
- if (cmd === 'serve') {
15
- const s = await createSentryTwinServer({ readOnly, ...(root ? { root } : {}), ...(port ? { port } : {}) });
16
- const origin = `http://127.0.0.1:${s.port}`;
17
- process.stdout.write(`sentry twin (ingest + Web API)${readOnly ? ' [read-only]' : ''} at ${origin}\n`);
18
- process.stdout.write(` point @sentry/node at DSN: ${defaultDsn(origin)}\n`);
9
+ const readOnly = hasFlag(rest, '--read-only');
10
+ // the selected twin's private Postgres, which the runtime binds a pack declaring managedDatabase to
11
+ const database = optionValue(rest, '--database') || undefined;
12
+ // the World's scenario file, for a model vendor's turns
13
+ const scenarioPath = optionValue(rest, '--scenario') || undefined;
14
+ if (cmd === 'serve' || cmd === undefined) {
15
+ const s = await createSentryTwinServer({ readOnly, ...(root ? { root } : {}), ...(port ? { port } : {}), ...(database ? { database } : {}), ...(scenarioPath ? { scenarioPath } : {}) });
16
+ process.stdout.write(`sentry twin${readOnly ? ' [read-only]' : ''} at http://127.0.0.1:${s.port}\n`);
19
17
  await keepProcessAlive();
20
18
  }
21
- else if (cmd === 'mirror') {
22
- const s = await createSentryMirrorServer({ ...(root ? { root } : {}), ...(port ? { port } : {}) });
23
- process.stdout.write(`sentry mirror UI (dashboard) at http://127.0.0.1:${s.port}\n`);
24
- await keepProcessAlive();
25
- }
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.js");
29
- const report = await checkSentryConformance({ ...(root ? { root } : {}) });
30
- process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
31
- if (!report.ok)
32
- process.exitCode = 1;
33
- }
34
19
  else {
35
- process.stdout.write('Usage: world-sentry serve|mirror|conformance [--port N] [--root DIR] [--read-only]\n');
20
+ process.stdout.write('Usage: world-sentry serve [--port N] [--root DIR] [--read-only] [--database URL] [--scenario FILE]\n');
36
21
  }
@@ -0,0 +1,2 @@
1
+ import { type DerivedFetch, type PackFetchOptions } from '@volter/world-core';
2
+ export declare function createSentryFetch(options?: PackFetchOptions): DerivedFetch;
@@ -0,0 +1,9 @@
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 } from '@volter/world-core';
4
+ import { manifest } from "./manifest.js";
5
+ import { createApiLaneFetch, manifest as api_manifest } from "../api/src/index.js";
6
+ import { createIngestLaneFetch, manifest as ingest_manifest } from "../ingest/src/index.js";
7
+ export function createSentryFetch(options = {}) {
8
+ return createVendorFetch(manifest, { "api": { fetch: createApiLaneFetch(options), manifest: api_manifest }, "ingest": { fetch: createIngestLaneFetch(options), manifest: ingest_manifest } });
9
+ }
@@ -1,15 +1,5 @@
1
- export { handleSentryTwinRequest } from './sentry-twin.js';
2
- export type { SentryRequest, SentryResponse } from './sentry-twin.js';
3
- export { createSentryTwinFetch, createSentryTwinServer, type SentryTwinFetchOptions } from './sentry-server.js';
4
- export { defaultDsn, DEFAULT_ORG, DEFAULT_PROJECT, DEFAULT_PROJECT_ID, DEFAULT_PUBLIC_KEY, ensureDefaultProject, envelopeEvents, eventCulprit, eventTitle, fingerprintText, hashFingerprint, ingestEvent, issueIdFor, normalizeFingerprintText, parseEnvelope, publicKeyFromAuthHeader, publicKeyFromDsn, resolveProjectKey, resolvePublicKey, } from './sentry-ingest.js';
5
- export type { IngestOutcome, ParsedEnvelope, ResolvedKey, SentryEventPayload, SentryExceptionValue, SentryFrame } from './sentry-ingest.js';
6
- export { computeSentrySignature, constructSentryWebhook, emitIssueAlert, listAlertRules, registerAlertRule, SentrySignatureVerificationError, verifySentrySignature, } from './sentry-events.js';
7
- export type { AlertTrigger, SentryWebhook, SentryWebhookAction, SentryWebhookDelivery } from './sentry-events.js';
8
- export { liveSentryExecute, mapIssue, mapProject, mapRelease, pullSentryIssues, pullSentryProjects, pullSentryReleases, pushSentryAction, sentryRequestForAction, syncSentryFromReal, } from './sentry-connector.js';
9
- export type { SentryExecute, LiveSentryOptions } from './sentry-connector.js';
10
- export { SENTRY_BUDGET_CEILING, SENTRY_BUDGET_MAX_RETRY_AFTER_S, SENTRY_BUDGET_WINDOW_MS, SENTRY_CALL_WEIGHTS, SENTRY_RATE_BUDGET, SentryBudget, SentryBudgetError, sentryBudgetPath, sentryCallWeight, } from './sentry-budget.js';
11
- export type { SentryBudgetErrorKind, SentryBudgetOptions, SentryBudgetReservation, SentryBudgetSnapshot } from './sentry-budget.js';
12
- export { buildSentryMirrorClient, createSentryMirrorServer, eventTags, formatCount, latestStacktrace, levelTone, sentryMirrorHtml, statusTone, timeAgo, } from './sentry-mirror-ui.js';
13
- export type { IssueRow, StackFrame } from './sentry-mirror-ui.js';
14
- import type { TwinPack } from '@volter/world-core';
15
- export declare const pack: TwinPack;
1
+ import { manifest } from './manifest.js';
2
+ export { createSentryFetch } from './fetch.js';
3
+ export { createSentryTwinServer } from './server.js';
4
+ export { manifest };
5
+ export declare const pack: import("@volter/world-core").PackDescriptor;
package/dist/src/index.js CHANGED
@@ -1,75 +1,13 @@
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.js";
8
- export { createSentryTwinFetch, createSentryTwinServer } from "./sentry-server.js";
9
- export { defaultDsn, DEFAULT_ORG, DEFAULT_PROJECT, DEFAULT_PROJECT_ID, DEFAULT_PUBLIC_KEY, ensureDefaultProject, envelopeEvents, eventCulprit, eventTitle, fingerprintText, hashFingerprint, ingestEvent, issueIdFor, normalizeFingerprintText, parseEnvelope, publicKeyFromAuthHeader, publicKeyFromDsn, resolveProjectKey, resolvePublicKey, } from "./sentry-ingest.js";
10
- export { computeSentrySignature, constructSentryWebhook, emitIssueAlert, listAlertRules, registerAlertRule, SentrySignatureVerificationError, verifySentrySignature, } from "./sentry-events.js";
11
- export { liveSentryExecute, mapIssue, mapProject, mapRelease, pullSentryIssues, pullSentryProjects, pullSentryReleases, pushSentryAction, sentryRequestForAction, syncSentryFromReal, } from "./sentry-connector.js";
12
- // The client-side rate budget — the fail-closed backstop `liveSentryExecute` routes every live
13
- // request through. The MECHANISM is the kernel's shared, vendor-agnostic `RateBudget`; what lives
14
- // here is Sentry's DECLARATION (window/ceiling/per-endpoint weights) plus the vendor-bound
15
- // bindings. Exported so an operator can inspect spend (`snapshot`) and so a caller can catch
16
- // `SentryBudgetError` by type; there is deliberately no export that disables the guard.
17
- export { SENTRY_BUDGET_CEILING, SENTRY_BUDGET_MAX_RETRY_AFTER_S, SENTRY_BUDGET_WINDOW_MS, SENTRY_CALL_WEIGHTS, SENTRY_RATE_BUDGET, SentryBudget, SentryBudgetError, sentryBudgetPath, sentryCallWeight, } from "./sentry-budget.js";
18
- export { buildSentryMirrorClient, createSentryMirrorServer, eventTags, formatCount, latestStacktrace, levelTone, sentryMirrorHtml, statusTone, timeAgo, } from "./sentry-mirror-ui.js";
19
- import { SENTRY_RATE_BUDGET as RATE_BUDGET } from "./sentry-budget.js";
20
- import { performSentryAction, syncSentryFromRemote } from "./sentry-connector.js";
21
- export const pack = {
22
- // 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
23
- // state system. Moved 2026-09-08. TRIAGE is what crosses to Sentry — an issue resolved, assigned, muted;
24
- // everything else this twin holds is something Sentry told it.
25
- protocol: '2',
26
- refresh: { every: '2m', webhook: true, onDemand: { atMost: '30s' } },
27
- stateSystem: { perform: performSentryAction, refresh: syncSentryFromRemote },
28
- // the round trip: an organization, then a project in it — the two things a Sentry account is made of
29
- // the round trip: an organization, a team in it, then a project under that team — Sentry's own create
30
- // path for a project is /teams/:org/:team/projects/, not the organization
31
- roundTrip: [
32
- { method: 'POST', path: '/api/0/organizations/', body: { name: 'Round Trip', slug: 'round-trip' }, headers: { authorization: 'Bearer round-trip' } },
33
- { method: 'POST', path: '/api/0/organizations/round-trip/teams/', body: { name: 'Round Trip', slug: 'round-trip' }, headers: { authorization: 'Bearer round-trip' } },
34
- { method: 'POST', path: '/api/0/teams/round-trip/round-trip/projects/', body: { name: 'Round Trip', platform: 'node' }, headers: { authorization: 'Bearer round-trip' } },
35
- // a project's slug is unique inside its org, so the create above rightly refuses a second one on a
36
- // branch that already has it — the vendor's own truth. The last write is therefore the one a world
37
- // repeats freely: triage on the project's own issue stream.
38
- { method: 'PUT', path: '/api/0/projects/round-trip/round-trip/', body: { platform: 'node', digestsMinDelay: 60 }, headers: { authorization: 'Bearer round-trip' } },
39
- ],
40
- parityOrigin: 'http://twin',
41
- vendor: 'sentry',
42
- // The SAME object sentry-budget.ts declares at module load — one source of truth, so registering
43
- // the pack and importing the connector can never arm two different ceilings.
44
- rateBudget: RATE_BUDGET,
45
- transport: 'rest',
46
- archetype: 'crud',
47
- bin: 'world-sentry',
48
- 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'],
49
- specSource: 'Sentry API reference (https://docs.sentry.io/api/) — ingest store/envelope + Web API /api/0/',
50
- description: 'Sentry REST twin — SDK ingestion → grouped issues, Web API, signed alert webhooks, dashboard mirror.',
51
- // Adoption + interception, moved off the central maps unchanged (descriptor-first back-migration, adding-a-twin.md §3,
52
- // 2026-08-31). The four canonical clients plus the further first-party @sentry
53
- // framework SDKs of the same ingest surface — battery-observed: sentry was the single
54
- // most-missed vendor, 13 repos, largely via these — and the whole `@sentry/` scope so a
55
- // satellite package like `@sentry/cli` still detects.
56
- adoption: {
57
- // Sentry's official Python SDK - the one distribution behind every Python integration.
58
- pypi: ['sentry-sdk'],
59
- sdks: [
60
- '@sentry/node', '@sentry/browser', '@sentry/react', '@sentry/nextjs',
61
- '@sentry/vue', '@sentry/sveltekit', '@sentry/astro', '@sentry/remix',
62
- '@sentry/electron', '@sentry/react-native',
63
- ],
64
- scopes: ['@sentry/'],
65
- // 'APPSMITHSENTRY' — appsmith names its DSN APPSMITH_SENTRY_DSN, an app-prefixed Sentry
66
- // credential for the same ingest surface (ladder classification 2026-09-02).
67
- envStems: ['SENTRY', 'APPSMITHSENTRY'],
68
- },
69
- // sentry.io (the web/REST API) plus the per-organization DSN ingest hosts
70
- // (`o<org-id>.ingest.sentry.io`), which need the suffix form.
71
- hosts: [{ host: 'sentry.io' }, { suffix: '.ingest.sentry.io' }],
72
- // The @sentry/node SDK POSTs to <dsn-host>/api/:projectId/envelope/; the dashboard hits
73
- // /api/0/. The dev proxy forwards both prefixes to the twin and strips the sentry.io host.
74
- browserRouting: { apiPathPrefix: '/api/', loaderHost: 'https://sentry.io' },
75
- };
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, unless the manifest declares none (vendorBacked.none;
3
+ // architecture, "The real-system adapters").
4
+ import { packOf, registerPack } from '@volter/world-core';
5
+ import { manifest } from "./manifest.js";
6
+ import { manifest as apiManifest } from "../api/src/manifest.js";
7
+ import apiSurface from '../api/src/generated/surface.gen.json' with { type: 'json' };
8
+ import { manifest as ingestManifest } from "../ingest/src/manifest.js";
9
+ import ingestSurface from '../ingest/src/generated/surface.gen.json' with { type: 'json' };
10
+ export { createSentryFetch } from "./fetch.js";
11
+ export { createSentryTwinServer } from "./server.js";
12
+ export { manifest };
13
+ export const pack = registerPack(packOf(manifest, { "api": { manifest: apiManifest, surface: apiSurface }, "ingest": { manifest: ingestManifest, surface: ingestSurface } }));
@@ -0,0 +1,2 @@
1
+ import type { VendorManifest } from '@volter/world-core';
2
+ export declare const manifest: VendorManifest;
@@ -0,0 +1,35 @@
1
+ export const manifest = {
2
+ vendor: 'sentry',
3
+ discovery: {
4
+ 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',
5
+ stores: 'organizations, projects and client keys, auth tokens (by their SHA-256), events and issues, and every other envelope item; releases and artifact bundles',
6
+ },
7
+ lanes: {
8
+ routes: [
9
+ { lane: 'ingest', host: '(^|\\.)ingest(\\.[a-z]+)?\\.sentry\\.io$' },
10
+ { lane: 'api', host: '^([a-z]+\\.)?sentry\\.io$' },
11
+ ],
12
+ default: 'api',
13
+ },
14
+ descriptor: {
15
+ protocol: '3',
16
+ transport: 'rest',
17
+ archetype: 'crud',
18
+ bin: 'world-sentry',
19
+ resources: ['organization', 'project', 'project_key', 'event', 'issue', 'release', 'monitor', 'check_in'],
20
+ specSource: "Sentry's OpenAPI document (api/spec, sentry-api-schema 98ec014, patched with evidence) and its SDK developer documentation's envelope endpoint (ingest/spec)",
21
+ 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 and Rallly, account project/key setup, and core vendor-backed reads.',
22
+ 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'] },
23
+ 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' }],
24
+ 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",
25
+ // Bootstrap: account sign-up, first credential and the project/key named by this env, stable at every boot.
26
+ credentialDoor: { account: { field: 'account', tenancy: 'organization', source: 'https://docs.sentry.io/api/permissions/' },
27
+ deployment: { field: 'deployment', object: 'project and client key', source: 'https://docs.sentry.io/product/sentry-basics/environments/', organizationOutputs: ['SENTRY_ORG', 'SENTRY_ORGANIZATION'] },
28
+ path: '/_twin/app-credentials', body: {},
29
+ fill: {
30
+ 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',
31
+ SENTRY_AUTH_TOKEN: 'auth_token', SENTRY_ORG: 'org', SENTRY_ORGANIZATION: 'org', SENTRY_PROJECT: 'project',
32
+ },
33
+ },
34
+ },
35
+ };
@@ -0,0 +1,88 @@
1
+ import type { HandlerContext } from '@volter/world-core';
2
+ type Reader = Pick<HandlerContext, 'row' | 'rowsRaw' | 'own'>;
3
+ export type Row = Record<string, unknown>;
4
+ /** An organization, made the first time (sentry.io's sign-up names it). */
5
+ export declare function makeOrg(ctx: HandlerContext, slug: string, name: string, owner: string): Promise<Row | Response>;
6
+ /** A project of an organization with its default client key (the project's creation makes one). */
7
+ export declare function makeProject(ctx: HandlerContext, org: Row, slug: string, platform: string | null): Promise<Row | Response>;
8
+ export declare function makeClientKey(ctx: HandlerContext, org: Row, project: Row): Promise<Row>;
9
+ /** An organization auth token, made on Settings > Auth Tokens: its value shown once. Its scopes are the organization
10
+ * token's fixed set ("org:ci": releases and source maps, and reading the organization). */
11
+ export declare function makeOrgToken(ctx: HandlerContext, org: Row, name: string, scopes?: string[]): Promise<string>;
12
+ /** A live native auth token, reconstructed only while its stored digest still matches. */
13
+ export declare function readToken(ctx: HandlerContext, org: Row, row: Row): Promise<string | undefined>;
14
+ /** A personal token (User Settings > Personal Tokens): `sntryu_` and 64 hexadecimal digits, with the scopes chosen when it
15
+ * is made, acting on the organizations its user belongs to (here, the one named). */
16
+ export declare function makePersonalToken(ctx: HandlerContext, org: Row, name: string, scopes: string[]): Promise<string>;
17
+ /** The token a request's `Authorization: Bearer` names, if the World issued it and it is not revoked. */
18
+ export declare function bearerToken(ctx: Pick<HandlerContext, 'row' | 'crypto' | 'call'>): Row | undefined;
19
+ /** Whether a token's scopes grant one: the scope itself, one its `org:ci` implies, or the same resource's write or
20
+ * admin (a `:write` scope reads, an `:admin` one writes and reads). */
21
+ export declare function grants(token: Row, scope: string): boolean;
22
+ /** An event's time: its `timestamp` (RFC 3339 or seconds since the epoch), else when it was received. */
23
+ export declare function eventTime(payload: Row, received: string): string;
24
+ /** An event's title, culprit, location and metadata, as Sentry derives them for its kind. Where the documentation stops:
25
+ * Sentry's own derivation (its event types' `get_title` and `get_location`) is code, not a page; these follow its
26
+ * answers' forms: `<Type>: <value>` for an error, the message for a message event, the transaction's name for one. */
27
+ export declare function derive(payload: Row, type: string): {
28
+ title: string;
29
+ culprit: string;
30
+ location: string | null;
31
+ metadata: Row;
32
+ };
33
+ /** The hash an error groups by: its fingerprint when the SDK sends one of its own, else its exception's type and its
34
+ * in-app frames (or its type and value, with no stack trace), else its message. Where the documentation stops: Sentry
35
+ * groups by its grouping configuration (https://docs.sentry.io/concepts/data-management/event-grouping/), whose
36
+ * algorithm is not reproduced; this keeps its rule's shape: the stack trace first, then the exception, then the message. */
37
+ export declare function groupingHash(ctx: Pick<HandlerContext, 'crypto'>, payload: Row): string;
38
+ /** An event's tags as the API lists them: the SDK's own, and the ones Sentry derives from the event. */
39
+ export declare function tagsOf(payload: Row): Array<{
40
+ key: string;
41
+ value: string;
42
+ }>;
43
+ /** An error or message event kept, grouped into its issue (made, or counted again). */
44
+ export declare function keepEvent(ctx: HandlerContext, project: Row, payload: Row, type: string): Promise<Row>;
45
+ /** An event as a project's event list answers it (the spec's listProjectEvents item). */
46
+ export declare function simpleEvent(e: Row): Row;
47
+ /** An event in full (the spec's getProjectEvent): the simple fields, its entries (the exception with its stack
48
+ * traces, the breadcrumbs, the request, the message), its contexts, SDK, release and neighbours. */
49
+ export declare function fullEvent(ctx: Reader, raw: Row): Row;
50
+ /** An issue as the API answers it (the spec's issue schema, its common fields). */
51
+ export declare function issueView(ctx: Reader, raw: Row): Row;
52
+ /** Stored vendor fields, including the API's own _meta; private association/payload fields stay in the tree. */
53
+ export declare function wire(ctx: Reader, row: Row): Row;
54
+ export declare const ORG = "organization";
55
+ export declare const PROJECT = "project";
56
+ export declare const CLIENT_KEY = "project_key";
57
+ export declare const TOKEN = "_auth_token";
58
+ /** An id in Sentry's form: a number, as a string. Where the documentation stops: how Sentry mints its ids is not
59
+ * published; ctx.mint makes hash-derived decimal ids at the declared width, the same every run. */
60
+ export declare const orgBySlug: (ctx: Reader, ref: string) => Row | undefined;
61
+ export declare const projectOf: (ctx: Reader, org: Row, ref: string) => Row | undefined;
62
+ export declare const projectById: (ctx: Reader, id: string) => Row | undefined;
63
+ /** The host a DSN names for an organization. */
64
+ export declare const ingestHost: (org: Row) => string;
65
+ /** A project's DSN, from its client key. */
66
+ export declare const dsnOf: (org: Row, project: Row, key: Row) => string;
67
+ /** A project's active client key. */
68
+ export declare const keyOf: (ctx: Reader, project: Row) => Row | undefined;
69
+ /** The project a DSN's public key belongs to. */
70
+ export declare const projectByKey: (ctx: Reader, publicKey: string) => Row | undefined;
71
+ /** The World's next number in a sequence (a project's id, a nonce): issued from the tree over the lane's declared
72
+ * `_seq_<what>` (ctx.issue), never a row count. */
73
+ export declare const next: (ctx: Pick<HandlerContext, "issue">, what: string) => Promise<number>;
74
+ export declare const EVENT = "event";
75
+ export declare const ISSUE = "issue";
76
+ /** One user an issue's events came from (its `userCount` counts them): bookkeeping the vendor serves only as the count. */
77
+ export declare const ISSUE_USER = "_issue_user";
78
+ export declare const SESSION = "_session";
79
+ export declare const CLIENT_REPORT = "_client_report";
80
+ export declare const ATTACHMENT = "_attachment";
81
+ export declare const REPLAY = "_replay";
82
+ export declare const PROFILE = "_profile";
83
+ export declare const MONITOR = "monitor";
84
+ export declare const CHECK_IN = "check_in";
85
+ export declare const LOG = "_log";
86
+ export declare const METRIC = "_metric";
87
+ export declare const OTHER_ITEM = "_envelope_item";
88
+ export {};