@relaycast/engine 10.6.5 → 11.1.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 (138) hide show
  1. package/dist/adapters/node/database.d.ts +8 -3
  2. package/dist/adapters/node/database.d.ts.map +1 -1
  3. package/dist/adapters/node/database.js +9 -30
  4. package/dist/adapters/node/database.js.map +1 -1
  5. package/dist/adapters/node/delivery-maintenance.d.ts.map +1 -1
  6. package/dist/adapters/node/delivery-maintenance.js +5 -2
  7. package/dist/adapters/node/delivery-maintenance.js.map +1 -1
  8. package/dist/adapters/node/index.d.ts.map +1 -1
  9. package/dist/adapters/node/index.js +2 -1
  10. package/dist/adapters/node/index.js.map +1 -1
  11. package/dist/adapters/node/migration-source.d.ts +17 -0
  12. package/dist/adapters/node/migration-source.d.ts.map +1 -0
  13. package/dist/adapters/node/migration-source.js +31 -0
  14. package/dist/adapters/node/migration-source.js.map +1 -0
  15. package/dist/adapters/node/pinned-https-fetch.d.ts +16 -0
  16. package/dist/adapters/node/pinned-https-fetch.d.ts.map +1 -0
  17. package/dist/adapters/node/pinned-https-fetch.js +83 -0
  18. package/dist/adapters/node/pinned-https-fetch.js.map +1 -0
  19. package/dist/adapters/node/sqlite-driver.d.ts +27 -0
  20. package/dist/adapters/node/sqlite-driver.d.ts.map +1 -0
  21. package/dist/adapters/node/sqlite-driver.js +9 -0
  22. package/dist/adapters/node/sqlite-driver.js.map +1 -0
  23. package/dist/adapters/node/ssrf-fetch.d.ts.map +1 -1
  24. package/dist/adapters/node/ssrf-fetch.js +35 -28
  25. package/dist/adapters/node/ssrf-fetch.js.map +1 -1
  26. package/dist/bin/serve.js +9 -0
  27. package/dist/bin/serve.js.map +1 -1
  28. package/dist/bin/version.d.ts +8 -0
  29. package/dist/bin/version.d.ts.map +1 -0
  30. package/dist/bin/version.js +12 -0
  31. package/dist/bin/version.js.map +1 -0
  32. package/dist/db/migrations/0076_deliveries_agent_status_created_index.sql +17 -0
  33. package/dist/db/schema.d.ts.map +1 -1
  34. package/dist/db/schema.js +2 -0
  35. package/dist/db/schema.js.map +1 -1
  36. package/dist/engine/usage.d.ts +10 -0
  37. package/dist/engine/usage.d.ts.map +1 -1
  38. package/dist/engine/usage.js +18 -0
  39. package/dist/engine/usage.js.map +1 -1
  40. package/dist/engine.d.ts.map +1 -1
  41. package/dist/engine.js +8 -7
  42. package/dist/engine.js.map +1 -1
  43. package/dist/env.d.ts +11 -0
  44. package/dist/env.d.ts.map +1 -1
  45. package/dist/index.d.ts +2 -2
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +1 -1
  48. package/dist/index.js.map +1 -1
  49. package/dist/lib/httpError.d.ts.map +1 -1
  50. package/dist/lib/httpError.js +3 -0
  51. package/dist/lib/httpError.js.map +1 -1
  52. package/dist/lib/logger.d.ts +3 -9
  53. package/dist/lib/logger.d.ts.map +1 -1
  54. package/dist/lib/logger.js +10 -96
  55. package/dist/lib/logger.js.map +1 -1
  56. package/dist/lib/planLimitError.d.ts +26 -0
  57. package/dist/lib/planLimitError.d.ts.map +1 -0
  58. package/dist/lib/planLimitError.js +16 -0
  59. package/dist/lib/planLimitError.js.map +1 -0
  60. package/dist/lib/serverTelemetry.d.ts +6 -45
  61. package/dist/lib/serverTelemetry.d.ts.map +1 -1
  62. package/dist/lib/serverTelemetry.js +27 -125
  63. package/dist/lib/serverTelemetry.js.map +1 -1
  64. package/dist/middleware/auth.d.ts.map +1 -1
  65. package/dist/middleware/auth.js +14 -0
  66. package/dist/middleware/auth.js.map +1 -1
  67. package/dist/middleware/planLimits.d.ts +31 -0
  68. package/dist/middleware/planLimits.d.ts.map +1 -1
  69. package/dist/middleware/planLimits.js +136 -4
  70. package/dist/middleware/planLimits.js.map +1 -1
  71. package/dist/ports/entitlements.d.ts +30 -0
  72. package/dist/ports/entitlements.d.ts.map +1 -1
  73. package/dist/ports/index.d.ts +8 -12
  74. package/dist/ports/index.d.ts.map +1 -1
  75. package/dist/ports/index.js +1 -0
  76. package/dist/ports/index.js.map +1 -1
  77. package/dist/ports/logging.d.ts +10 -0
  78. package/dist/ports/logging.d.ts.map +1 -0
  79. package/dist/ports/logging.js +2 -0
  80. package/dist/ports/logging.js.map +1 -0
  81. package/dist/ports/telemetry.d.ts +95 -23
  82. package/dist/ports/telemetry.d.ts.map +1 -1
  83. package/dist/ports/telemetry.js +77 -1
  84. package/dist/ports/telemetry.js.map +1 -1
  85. package/dist/providers/noop-telemetry.d.ts +1 -7
  86. package/dist/providers/noop-telemetry.d.ts.map +1 -1
  87. package/dist/providers/noop-telemetry.js +1 -7
  88. package/dist/providers/noop-telemetry.js.map +1 -1
  89. package/dist/providers/static-entitlements.d.ts +1 -1
  90. package/dist/providers/static-entitlements.d.ts.map +1 -1
  91. package/dist/providers/static-entitlements.js +6 -1
  92. package/dist/providers/static-entitlements.js.map +1 -1
  93. package/dist/routes/action.js +3 -3
  94. package/dist/routes/action.js.map +1 -1
  95. package/dist/routes/agent.js +8 -8
  96. package/dist/routes/agent.js.map +1 -1
  97. package/dist/routes/channel.js +9 -9
  98. package/dist/routes/channel.js.map +1 -1
  99. package/dist/routes/directory.js +5 -5
  100. package/dist/routes/directory.js.map +1 -1
  101. package/dist/routes/dm.d.ts.map +1 -1
  102. package/dist/routes/dm.js +4 -2
  103. package/dist/routes/dm.js.map +1 -1
  104. package/dist/routes/eventSubscription.js +2 -2
  105. package/dist/routes/eventSubscription.js.map +1 -1
  106. package/dist/routes/file.js +2 -2
  107. package/dist/routes/file.js.map +1 -1
  108. package/dist/routes/groupDm.d.ts.map +1 -1
  109. package/dist/routes/groupDm.js +15 -11
  110. package/dist/routes/groupDm.js.map +1 -1
  111. package/dist/routes/inboundWebhook.js +5 -6
  112. package/dist/routes/inboundWebhook.js.map +1 -1
  113. package/dist/routes/message.d.ts.map +1 -1
  114. package/dist/routes/message.js +7 -3
  115. package/dist/routes/message.js.map +1 -1
  116. package/dist/routes/node.js +1 -1
  117. package/dist/routes/node.js.map +1 -1
  118. package/dist/routes/presence.js +2 -2
  119. package/dist/routes/presence.js.map +1 -1
  120. package/dist/routes/reaction.js +2 -2
  121. package/dist/routes/reaction.js.map +1 -1
  122. package/dist/routes/receipt.js +1 -1
  123. package/dist/routes/receipt.js.map +1 -1
  124. package/dist/routes/relayfileInbound.d.ts.map +1 -1
  125. package/dist/routes/relayfileInbound.js +3 -4
  126. package/dist/routes/relayfileInbound.js.map +1 -1
  127. package/dist/routes/routing.js +3 -3
  128. package/dist/routes/routing.js.map +1 -1
  129. package/dist/routes/search.js +1 -1
  130. package/dist/routes/search.js.map +1 -1
  131. package/dist/routes/systemPrompt.js +2 -2
  132. package/dist/routes/systemPrompt.js.map +1 -1
  133. package/dist/routes/thread.d.ts.map +1 -1
  134. package/dist/routes/thread.js +7 -3
  135. package/dist/routes/thread.js.map +1 -1
  136. package/dist/routes/workspace.js +5 -5
  137. package/dist/routes/workspace.js.map +1 -1
  138. package/package.json +8 -4
@@ -1,7 +1,4 @@
1
- import { TELEMETRY_CLOUD_ID_MAX_LENGTH, } from "@relaycast/types";
2
- import { eq } from "drizzle-orm";
3
- import { workspaces } from "../db/schema.js";
4
- import { extractActorIdentity, extractAgentRelayDistinctId, extractOriginActor, requiredOriginInfo, UNKNOWN_ORIGIN_ACTOR, } from "./origin.js";
1
+ import { extractOriginActor, requiredOriginInfo, UNKNOWN_ORIGIN_ACTOR, } from "./origin.js";
5
2
  export function normalizeRoutePathForTelemetry(value) {
6
3
  const withoutQuery = value.split(/[?#]/)[0] ?? value;
7
4
  const compact = withoutQuery.replace(/\/+/g, "/").trim();
@@ -20,48 +17,6 @@ export function normalizeRoutePathForTelemetry(value) {
20
17
  });
21
18
  return `/${segments.join("/")}`;
22
19
  }
23
- /**
24
- * Load the workspace fields that carry its PostHog groups, for emitters that
25
- * run without an authenticated workspace in context (external webhooks, node
26
- * sockets). Groups are optional, so a failed lookup yields none rather than
27
- * dropping the event.
28
- */
29
- export async function loadTelemetryWorkspace(db, workspaceId) {
30
- try {
31
- const [workspace] = await db
32
- .select({ id: workspaces.id, metadata: workspaces.metadata })
33
- .from(workspaces)
34
- .where(eq(workspaces.id, workspaceId));
35
- return workspace;
36
- }
37
- catch (error) {
38
- console.warn('[telemetry] workspace lookup failed; event sent without groups', {
39
- workspace_id: workspaceId,
40
- error: error instanceof Error ? error.message : String(error),
41
- });
42
- return undefined;
43
- }
44
- }
45
- /** Sends whose first occurrence is stamped on the person via `$set_once`. */
46
- const SEND_EVENTS = new Set([
47
- "relaycast_server_message_created",
48
- "relaycast_server_thread_reply_created",
49
- "relaycast_server_dm_sent",
50
- "relaycast_server_group_dm_message_sent",
51
- ]);
52
- /** Distinct id for events with no person; a workspace is never a person. */
53
- export function workspaceTelemetryDistinctId(workspaceId) {
54
- return `relaycast-ws:${workspaceId}`;
55
- }
56
- function cloudId(metadata, key) {
57
- const value = metadata?.[key];
58
- if (typeof value !== "string")
59
- return undefined;
60
- const trimmed = value.trim();
61
- if (!trimmed || trimmed.length > TELEMETRY_CLOUD_ID_MAX_LENGTH)
62
- return undefined;
63
- return trimmed;
64
- }
65
20
  function senderType(type) {
66
21
  if (type === "human")
67
22
  return "human";
@@ -69,45 +24,6 @@ function senderType(type) {
69
24
  return "system";
70
25
  return "agent";
71
26
  }
72
- function senderProperties(actor, cloudUserId) {
73
- const type = senderType(actor.type);
74
- return {
75
- sender_type: type,
76
- agent_id: actor.id,
77
- agent_name: actor.name,
78
- ...(type !== "human" && cloudUserId ? { agent_owner_user_id: cloudUserId } : {}),
79
- };
80
- }
81
- function workspaceGroups(workspace) {
82
- const organization = cloudId(workspace?.metadata, "cloud_org_id");
83
- const cloudWorkspace = cloudId(workspace?.metadata, "cloud_workspace_id");
84
- if (!organization && !cloudWorkspace)
85
- return undefined;
86
- return {
87
- ...(organization ? { organization } : {}),
88
- ...(cloudWorkspace ? { workspace: cloudWorkspace } : {}),
89
- };
90
- }
91
- function firstSendSetOnce(sender) {
92
- const now = new Date().toISOString();
93
- if (sender.sender_type === "human")
94
- return { first_human_message_at: now };
95
- // An agent send counts toward a person only when an owner is known; system
96
- // actors are not the person's agents.
97
- return sender.sender_type === "agent" && sender.agent_owner_user_id
98
- ? { first_agent_message_at: now }
99
- : {};
100
- }
101
- /**
102
- * Emit a server-side product-telemetry event through the injected
103
- * {@link TelemetrySink}. Self-host's default sink is a no-op; cloud injects
104
- * PostHog. The sink owns batching/background-flush, so this returns immediately.
105
- *
106
- * The person is the acting agent's `metadata.cloud_user_id` (a human, or the
107
- * owner of an agent), else the caller-declared user/client id, else the
108
- * workspace with person processing off. The workspace's cloud org and
109
- * workspace ids become PostHog groups.
110
- */
111
27
  export function emitServerEvent(c, workspaceId, event, properties, attribution = {}) {
112
28
  const normalizedProperties = { ...properties };
113
29
  // The `workspaceId` argument is authoritative; a caller value must not
@@ -120,50 +36,36 @@ export function emitServerEvent(c, workspaceId, event, properties, attribution =
120
36
  // header directly so emitters that bypass middleware still get a sane value.
121
37
  const originActor = c.get("originActor") ?? extractOriginActor(c.req.raw) ?? UNKNOWN_ORIGIN_ACTOR;
122
38
  const origin = requiredOriginInfo(c.req.raw);
123
- const clientDistinctId = extractAgentRelayDistinctId(c.req.raw);
124
- // Caller-declared user/org. Analytics dimensions only — never authorization.
125
- const actor = extractActorIdentity(c.req.raw);
126
39
  // Context rows belong to the authenticated token; an event about another
127
40
  // workspace (e.g. one just created) must not inherit them.
128
41
  const contextAgent = c.get("agent");
129
- const contextWorkspace = c.get("workspace");
130
42
  const actingAgent = attribution.actor ??
131
43
  (contextAgent?.workspaceId === workspaceId ? contextAgent : undefined);
132
- const workspace = attribution.workspace ??
133
- (contextWorkspace?.id === workspaceId ? contextWorkspace : undefined);
134
- const cloudUserId = actingAgent
135
- ? cloudId(actingAgent.metadata, "cloud_user_id")
136
- : undefined;
137
- const sender = actingAgent
138
- ? senderProperties(actingAgent, cloudUserId)
139
- : undefined;
140
- // `client_distinct_id` is already the user id when the CLI is signed in; the
141
- // explicit user header covers callers that send only one of the two.
142
- const personId = cloudUserId ?? actor.actor_user_id ?? clientDistinctId;
143
- const groups = workspaceGroups(workspace);
144
- const setOnce = personId && sender && SEND_EVENTS.has(event)
145
- ? firstSendSetOnce(sender)
146
- : {};
147
- c.get("engine").telemetry.capture({
148
- name: event,
149
- distinctId: personId ?? workspaceTelemetryDistinctId(workspaceId),
150
- ...(personId ? {} : { processPersonProfile: false }),
151
- ...(groups ? { groups } : {}),
152
- ...(Object.keys(setOnce).length > 0 ? { setOnce } : {}),
153
- properties: {
154
- app: "relaycast-server",
155
- surface: "cloud",
156
- // Early, so the sink's 64-property cap can never truncate it away.
157
- workspace_id: workspaceId,
158
- ...(clientDistinctId ? { client_distinct_id: clientDistinctId } : {}),
159
- is_authenticated: Boolean(actor.actor_user_id),
160
- ...actor,
161
- ...sender,
162
- origin_actor: originActor,
163
- origin_client: origin.origin_client,
164
- origin_version: origin.origin_version,
165
- ...normalizedProperties,
166
- },
167
- });
44
+ const sender = actingAgent ? { id: actingAgent.id, name: actingAgent.name, type: senderType(actingAgent.type) } : undefined;
45
+ // Only the credential-authenticated agent can establish ownership. A node
46
+ // may name any workspace agent as `from`; loading that sender's row proves
47
+ // neither possession of its token nor any external ownership.
48
+ const scopedActor = contextAgent?.workspaceId === workspaceId ? contextAgent : undefined;
49
+ // Neither synchronous throws nor asynchronous rejections may change a domain outcome.
50
+ try {
51
+ const pending = c.get("engine").telemetry.capture({
52
+ kind: event,
53
+ occurredAt: new Date().toISOString(),
54
+ workspaceId,
55
+ ...(scopedActor ? { authenticatedActor: {
56
+ agentId: scopedActor.id,
57
+ credentialHash: c.get('agentCredentialHash'),
58
+ type: senderType(scopedActor.type),
59
+ } } : {}),
60
+ ...(sender ? { sender } : {}),
61
+ origin: { actor: originActor, client: origin.origin_client, version: origin.origin_version },
62
+ facts: normalizedProperties,
63
+ });
64
+ if (pending)
65
+ void Promise.resolve(pending).catch(() => { });
66
+ }
67
+ catch {
68
+ // Host observation is best effort.
69
+ }
168
70
  }
169
71
  //# sourceMappingURL=serverTelemetry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"serverTelemetry.js","sourceRoot":"","sources":["../../src/lib/serverTelemetry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serverTelemetry.js","sourceRoot":"","sources":["../../src/lib/serverTelemetry.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAKxC,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAyC7C,UAAU,oBAAoB;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAMD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,aAAa,GAAG,aAAa,EAAE,EACvC,OAAO,GAAE,oBAAyB,kEAuDnC;AAED,gDAAgD;AAChD,eAAO,MAAM,mBAAmB,gEAAkC,CAAC;AAEnE,wDAAwD;AACxD,eAAO,MAAM,WAAW,gEAA4B,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,aAAa,gEAA+B,CAAC;AAE1D,+CAA+C;AAC/C,eAAO,MAAM,iBAAiB,gEAA8B,CAAC;AAE7D,6CAA6C;AAC7C,eAAO,MAAM,gBAAgB,gEAA6B,CAAC"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAMxC,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAgD7C,UAAU,oBAAoB;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAMD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,aAAa,GAAG,aAAa,EAAE,EACvC,OAAO,GAAE,oBAAyB,kEAyDnC;AAED,gDAAgD;AAChD,eAAO,MAAM,mBAAmB,gEAAkC,CAAC;AAEnE,wDAAwD;AACxD,eAAO,MAAM,WAAW,gEAA4B,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,aAAa,gEAA+B,CAAC;AAE1D,+CAA+C;AAC/C,eAAO,MAAM,iBAAiB,gEAA8B,CAAC;AAE7D,6CAA6C;AAC7C,eAAO,MAAM,gBAAgB,gEAA6B,CAAC"}
@@ -3,6 +3,7 @@ import { touchLastSeen } from '../engine/agent.js';
3
3
  import { getAuthTokenKind } from '../auth/tokenKind.js';
4
4
  import { authenticateUnexpired } from '../auth/workspaceExpiry.js';
5
5
  import { jsonError } from '../lib/httpResponse.js';
6
+ import { sha256Hex } from '../lib/crypto.js';
6
7
  import { hasAnyObserverScope, } from '../engine/observerToken.js';
7
8
  // Re-exported for the WS upgrade, which looks tokens up
8
9
  // directly. The active provider's `hashToken` is preferred at those call sites.
@@ -13,6 +14,16 @@ function extractToken(authHeader) {
13
14
  return null;
14
15
  return authHeader.slice(7);
15
16
  }
17
+ async function presentedCredentialHash(token) {
18
+ // AuthProvider.hashToken describes storage, and may return a raw token.
19
+ // Telemetry provenance always uses its own irreversible SHA-256 digest.
20
+ try {
21
+ return await sha256Hex(token);
22
+ }
23
+ catch {
24
+ return undefined;
25
+ }
26
+ }
16
27
  function makeAuthMiddleware(require) {
17
28
  return createMiddleware(async (c, next) => {
18
29
  const token = extractToken(c.req.header('Authorization'));
@@ -25,6 +36,7 @@ function makeAuthMiddleware(require) {
25
36
  return jsonError(c, result.code, result.message, result.status);
26
37
  }
27
38
  c.set('workspace', result.workspace);
39
+ c.set('agentCredentialHash', result.agent ? await presentedCredentialHash(token) : undefined);
28
40
  if (result.agent) {
29
41
  c.set('agent', result.agent);
30
42
  // Touch lastSeen (debounced, fire-and-forget)
@@ -69,6 +81,7 @@ export function requireWorkspaceRead(scopes, options = {}) {
69
81
  }
70
82
  c.set('workspace', result.workspace);
71
83
  c.set('agent', undefined);
84
+ c.set('agentCredentialHash', undefined);
72
85
  c.set('node', undefined);
73
86
  c.set('observerToken', result.observerToken);
74
87
  await next();
@@ -81,6 +94,7 @@ export function requireWorkspaceRead(scopes, options = {}) {
81
94
  return jsonError(c, 'forbidden', 'Node token cannot access this resource', 403);
82
95
  }
83
96
  c.set('workspace', result.workspace);
97
+ c.set('agentCredentialHash', result.agent ? await presentedCredentialHash(token) : undefined);
84
98
  if (result.agent) {
85
99
  c.set('agent', result.agent);
86
100
  if (Date.now() - result.agent.lastSeen.getTime() > LAST_SEEN_DEBOUNCE_MS) {
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,mBAAmB,GAEpB,MAAM,4BAA4B,CAAC;AAEpC,wDAAwD;AACxD,gFAAgF;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,qBAAqB,GAAG,MAAM,CAAC,CAAC,aAAa;AAEnD,SAAS,YAAY,CAAC,UAA8B;IAClD,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAoB;IAC9C,OAAO,gBAAgB,CAAS,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QAChD,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,SAAS,CAAC,CAAC,EAAE,cAAc,EAAE,yCAAyC,EAAE,GAAG,CAAC,CAAC;QACtF,CAAC;QAED,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACzF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAA8B,CAAC,CAAC;QAC1F,CAAC;QAED,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7B,8CAA8C;YAC9C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,qBAAqB,EAAE,CAAC;gBACzE,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACzB,CAAC,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAOD,SAAS,WAAW,CAAC,MAAuC;IAC1D,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,MAAuC,EACvC,UAAgC,EAAE;IAElC,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;IAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;IAE5C,OAAO,gBAAgB,CAAS,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QAChD,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,SAAS,CAAC,CAAC,EAAE,cAAc,EAAE,yCAAyC,EAAE,GAAG,CAAC,CAAC;QACtF,CAAC;QAED,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,OAAO,GAAgB,gBAAgB,CAAC,KAAK,CAAC,KAAK,UAAU;YACjE,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,UAAU,IAAI,SAAS;gBACvB,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,WAAW,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACzF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAA8B,CAAC,CAAC;QAC1F,CAAC;QAED,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACzB,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,aAAa,EAAE,cAAc,CAAC,EAAE,CAAC;gBAC/D,OAAO,SAAS,CAAC,CAAC,EAAE,oBAAoB,EAAE,yCAAyC,EAAE,GAAG,CAAC,CAAC;YAC5F,CAAC;YACD,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;YACrC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;YAC1B,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACzB,CAAC,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;YAC7C,MAAM,IAAI,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC,CAAC,EAAE,WAAW,EAAE,yCAAyC,EAAE,GAAG,CAAC,CAAC;QACnF,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC9B,OAAO,SAAS,CAAC,CAAC,EAAE,WAAW,EAAE,wCAAwC,EAAE,GAAG,CAAC,CAAC;QAClF,CAAC;QAED,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,qBAAqB,EAAE,CAAC;gBACzE,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;AAEnE,wDAAwD;AACxD,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;AAErD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AAE1D,+CAA+C;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAE7D,6CAA6C;AAC7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,36 @@
1
+ import type { Context } from 'hono';
1
2
  import type { AppEnv } from '../env.js';
2
3
  import type { UsageMetric } from '../ports/entitlements.js';
3
4
  export { PLAN_LIMITS } from '../providers/static-entitlements.js';
4
5
  export declare function checkPlanLimit(metric: UsageMetric): import("hono").MiddlewareHandler<AppEnv, string, {}, Response>;
6
+ /**
7
+ * Enforce a plan's one-time `lifetime_messages` allowance on message sends.
8
+ *
9
+ * Mounted after `rateLimit` on the routes that create a message (channel post,
10
+ * DM, group DM, thread reply). Plans without a finite allowance — every tier
11
+ * except a hosted anonymous trial, and always `selfhost` — skip it without
12
+ * touching the counter. The allowance never resets, so the 429 carries no
13
+ * `Retry-After`: retrying cannot clear it; signing in or upgrading does.
14
+ *
15
+ * Idempotency is preserved. Only a fresh send that succeeds (2xx without
16
+ * `Idempotency-Replayed`) is counted, so retries never spend the allowance.
17
+ * Once the allowance is spent, a request without an `Idempotency-Key` is
18
+ * refused here; a keyed request reaches the route so a replay of an earlier
19
+ * successful send still returns its stored receipt, and the route refuses only
20
+ * a fresh send ({@link assertMessageAllowance}, called inside the idempotent
21
+ * operation).
22
+ *
23
+ * The count is kept alive past the response with `runInBackground`
24
+ * (`waitUntil` on Workers). Check-then-count is not atomic: concurrent sends at
25
+ * the boundary can overshoot by the number in flight, which a soft trial
26
+ * allowance tolerates. Fails open on entitlement or counter errors, matching
27
+ * `checkPlanLimit`.
28
+ */
29
+ export declare const checkMessageAllowance: import("hono").MiddlewareHandler<AppEnv, string, {}, Response>;
30
+ /**
31
+ * Refuse a fresh send when `checkMessageAllowance` found the allowance spent.
32
+ * Call it first inside a message route's idempotent `operation`, which runs
33
+ * only for a new send — never for a replay of a stored receipt.
34
+ */
35
+ export declare function assertMessageAllowance(c: Context<AppEnv>): void;
5
36
  //# sourceMappingURL=planLimits.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"planLimits.d.ts","sourceRoot":"","sources":["../../src/middleware/planLimits.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAwB,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAMlF,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAmBlE,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,kEA+BjD"}
1
+ {"version":3,"file":"planLimits.d.ts","sourceRoot":"","sources":["../../src/middleware/planLimits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAyC,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAQnG,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAwElE,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,kEAuCjD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,qBAAqB,gEA0ChC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAG/D"}
@@ -1,7 +1,8 @@
1
1
  import { createMiddleware } from 'hono/factory';
2
- import { usagePeriodResetAt } from '../engine/usage.js';
3
- import { jsonError } from '../lib/httpResponse.js';
2
+ import { getLifetimeUsageMetric, incrementLifetimeUsage, usagePeriodResetAt } from '../engine/usage.js';
4
3
  import { setRetryContract } from '../lib/throttle.js';
4
+ import { PlanLimitExceededError } from '../lib/planLimitError.js';
5
+ import { runInBackground } from '../routes/background.js';
5
6
  // Re-exported for back-compat with callers/tests that imported the table here.
6
7
  export { PLAN_LIMITS } from '../providers/static-entitlements.js';
7
8
  /**
@@ -18,6 +19,49 @@ async function resolveUsageResetAt(entitlements, workspaceId, metric) {
18
19
  catch { /* fall through to the engine period */ }
19
20
  return usagePeriodResetAt();
20
21
  }
22
+ /**
23
+ * Where the caller can lift the limit. Advisory only: an absent or failing hook,
24
+ * or a non-absolute URL, omits the guidance and never changes the decision.
25
+ */
26
+ async function resolveUpgradeGuidance(entitlements, workspace, metric) {
27
+ try {
28
+ const guidance = await entitlements.getUpgradeGuidance?.(workspace, metric);
29
+ if (!guidance || typeof guidance.url !== 'string')
30
+ return null;
31
+ const url = new URL(guidance.url);
32
+ if (url.protocol !== 'https:' && url.protocol !== 'http:')
33
+ return null;
34
+ return guidance;
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ /**
41
+ * The `plan_limit_exceeded` body. The envelope stays `{ ok, error: { code,
42
+ * message } }`; `metric`, `limit`, `usage`, `plan` and — when the host knows
43
+ * one — `upgrade_url` / `upgrade_action` are additive fields on `error` so a
44
+ * client can render "sign in" or "upgrade" without parsing the message.
45
+ */
46
+ function planLimitExceededBody(input) {
47
+ const { guidance } = input;
48
+ const nextStep = guidance
49
+ ? `${guidance.hint ?? (guidance.action === 'sign_in' ? 'Sign in to keep going:' : 'Upgrade your plan to increase limits:')} ${guidance.url}`
50
+ : 'Upgrade your plan to increase limits.';
51
+ return {
52
+ ok: false,
53
+ error: {
54
+ code: 'plan_limit_exceeded',
55
+ message: `${input.message} ${nextStep}`,
56
+ metric: input.metric,
57
+ plan: input.plan,
58
+ limit: input.limit,
59
+ usage: input.usage,
60
+ upgrade_url: guidance?.url ?? null,
61
+ upgrade_action: guidance?.action ?? null,
62
+ },
63
+ };
64
+ }
21
65
  export function checkPlanLimit(metric) {
22
66
  return createMiddleware(async (c, next) => {
23
67
  const workspace = c.get('workspace');
@@ -42,17 +86,105 @@ export function checkPlanLimit(metric) {
42
86
  try {
43
87
  const current = await entitlements.getUsage(workspace.id, metric);
44
88
  if (current >= limit) {
45
- const plan = workspace.plan || 'free';
89
+ const guidance = await resolveUpgradeGuidance(entitlements, workspace, metric);
90
+ const plan = guidance?.plan ?? (workspace.plan || 'free');
46
91
  // Quota clears on the billing period, not on a backoff. Advertising the
47
92
  // real reset lets a caller with a bounded retry budget fail fast instead
48
93
  // of spending it on a condition retrying cannot fix.
49
94
  const resetAt = await resolveUsageResetAt(entitlements, workspace.id, metric);
50
95
  setRetryContract(c, resetAt);
51
- return jsonError(c, 'plan_limit_exceeded', `Plan limit exceeded for ${metric}. Current plan: ${plan}. Limit: ${limit} per usage period. Current usage: ${current}. Quota resets at ${new Date(resetAt).toISOString()}. Upgrade your plan to increase limits.`, 429);
96
+ return c.json(planLimitExceededBody({
97
+ metric,
98
+ plan,
99
+ limit,
100
+ usage: current,
101
+ message: `Plan limit exceeded for ${metric}. Current plan: ${plan}. Limit: ${limit} per usage period. Current usage: ${current}. Quota resets at ${new Date(resetAt).toISOString()}.`,
102
+ guidance,
103
+ }), 429);
52
104
  }
53
105
  }
54
106
  catch { /* fail open */ }
55
107
  await next();
56
108
  });
57
109
  }
110
+ /**
111
+ * Enforce a plan's one-time `lifetime_messages` allowance on message sends.
112
+ *
113
+ * Mounted after `rateLimit` on the routes that create a message (channel post,
114
+ * DM, group DM, thread reply). Plans without a finite allowance — every tier
115
+ * except a hosted anonymous trial, and always `selfhost` — skip it without
116
+ * touching the counter. The allowance never resets, so the 429 carries no
117
+ * `Retry-After`: retrying cannot clear it; signing in or upgrading does.
118
+ *
119
+ * Idempotency is preserved. Only a fresh send that succeeds (2xx without
120
+ * `Idempotency-Replayed`) is counted, so retries never spend the allowance.
121
+ * Once the allowance is spent, a request without an `Idempotency-Key` is
122
+ * refused here; a keyed request reaches the route so a replay of an earlier
123
+ * successful send still returns its stored receipt, and the route refuses only
124
+ * a fresh send ({@link assertMessageAllowance}, called inside the idempotent
125
+ * operation).
126
+ *
127
+ * The count is kept alive past the response with `runInBackground`
128
+ * (`waitUntil` on Workers). Check-then-count is not atomic: concurrent sends at
129
+ * the boundary can overshoot by the number in flight, which a soft trial
130
+ * allowance tolerates. Fails open on entitlement or counter errors, matching
131
+ * `checkPlanLimit`.
132
+ */
133
+ export const checkMessageAllowance = createMiddleware(async (c, next) => {
134
+ const workspace = c.get('workspace');
135
+ if (!workspace) {
136
+ await next();
137
+ return;
138
+ }
139
+ const { entitlements, kv } = c.get('engine');
140
+ let allowance;
141
+ try {
142
+ allowance = (await entitlements.getLimits(workspace)).lifetime_messages;
143
+ }
144
+ catch {
145
+ await next();
146
+ return;
147
+ }
148
+ if (typeof allowance !== 'number' || !Number.isFinite(allowance)) {
149
+ await next();
150
+ return;
151
+ }
152
+ let used;
153
+ try {
154
+ used = await getLifetimeUsageMetric(kv, workspace.id, 'messages');
155
+ }
156
+ catch {
157
+ await next();
158
+ return;
159
+ }
160
+ if (used >= allowance) {
161
+ const guidance = await resolveUpgradeGuidance(entitlements, workspace, 'messages');
162
+ const plan = guidance?.plan ?? (workspace.plan || 'free');
163
+ const body = planLimitExceededBody({
164
+ metric: 'messages',
165
+ plan,
166
+ limit: allowance,
167
+ usage: used,
168
+ message: `Message allowance used up: this workspace has sent ${used} of its ${allowance} messages (current plan: ${plan}). The allowance does not reset.`,
169
+ guidance,
170
+ });
171
+ if (!c.req.header('Idempotency-Key'))
172
+ return c.json(body, 429);
173
+ c.set('messageAllowanceDenial', body);
174
+ }
175
+ await next();
176
+ if (c.res.status >= 200 && c.res.status < 300 && c.res.headers.get('Idempotency-Replayed') !== 'true') {
177
+ runInBackground(c, incrementLifetimeUsage(kv, workspace.id, 'messages'), 'lifetime message usage increment');
178
+ }
179
+ });
180
+ /**
181
+ * Refuse a fresh send when `checkMessageAllowance` found the allowance spent.
182
+ * Call it first inside a message route's idempotent `operation`, which runs
183
+ * only for a new send — never for a replay of a stored receipt.
184
+ */
185
+ export function assertMessageAllowance(c) {
186
+ const denial = c.get('messageAllowanceDenial');
187
+ if (denial)
188
+ throw new PlanLimitExceededError(denial);
189
+ }
58
190
  //# sourceMappingURL=planLimits.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"planLimits.js","sourceRoot":"","sources":["../../src/middleware/planLimits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,+EAA+E;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAElE;;;;GAIG;AACH,KAAK,UAAU,mBAAmB,CAChC,YAAkC,EAClC,WAAmB,EACnB,MAAmB;IAEnB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC3E,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,OAAO,QAAQ,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC,CAAC,uCAAuC,CAAC,CAAC;IACnD,OAAO,kBAAkB,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAmB;IAChD,OAAO,gBAAgB,CAAS,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;QAChD,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,CAAC,SAAS,EAAE,CAAC;YAAC,MAAM,IAAI,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAEzC,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YAAC,MAAM,IAAI,EAAE,CAAC;YAAC,OAAO;QAAC,CAAC;QAE9E,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAClE,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;gBACrB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,IAAI,MAAM,CAAC;gBACtC,wEAAwE;gBACxE,yEAAyE;gBACzE,qDAAqD;gBACrD,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBAC9E,gBAAgB,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBAC7B,OAAO,SAAS,CAAC,CAAC,EAAE,qBAAqB,EAAE,2BAA2B,MAAM,mBAAmB,IAAI,YAAY,KAAK,qCAAqC,OAAO,qBAAqB,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,yCAAyC,EAAE,GAAG,CAAC,CAAC;YACtQ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC;QAE3B,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"planLimits.js","sourceRoot":"","sources":["../../src/middleware/planLimits.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,29 @@ export interface PlanLimits {
8
8
  api_calls: number;
9
9
  /** Global requests-per-minute ceiling, fed into the rate limiter. */
10
10
  rate_per_min: number;
11
+ /**
12
+ * One-time message allowance that never resets. When set to a finite number,
13
+ * message sends (channel posts, DMs, group DMs, thread replies) are refused
14
+ * with `plan_limit_exceeded` once the workspace has sent this many messages
15
+ * over its whole lifetime. Unset (or `Infinity`) means no lifetime cap — the
16
+ * case for every tier except a hosted anonymous trial.
17
+ */
18
+ lifetime_messages?: number;
19
+ }
20
+ /**
21
+ * Where a workspace that hit a limit should go next. Returned by
22
+ * {@link EntitlementsProvider.getUpgradeGuidance} and surfaced on the
23
+ * `plan_limit_exceeded` error body as `upgrade_url` / `upgrade_action`.
24
+ */
25
+ export interface UpgradeGuidance {
26
+ /** An absolute URL the caller can open to lift the limit. */
27
+ url: string;
28
+ /** `sign_in` when signing in (free) lifts the limit, `upgrade` when a paid plan does. */
29
+ action: 'sign_in' | 'upgrade';
30
+ /** Effective plan name to report, when it differs from the stored `workspace.plan`. */
31
+ plan?: string;
32
+ /** One sentence appended to the error message, e.g. how to sign in. */
33
+ hint?: string;
11
34
  }
12
35
  /**
13
36
  * Pluggable plan limits / usage — the billing seam.
@@ -31,5 +54,12 @@ export interface EntitlementsProvider {
31
54
  * UTC-month period.
32
55
  */
33
56
  getUsageResetAt?(workspaceId: string, metric: UsageMetric): Promise<number>;
57
+ /**
58
+ * Where a workspace that hit `metric`'s limit can lift it (sign in, upgrade).
59
+ * Optional: self-host deployments have no upgrade path, and an absent or
60
+ * failing hook only omits `upgrade_url` from the error — it never changes
61
+ * the limit decision.
62
+ */
63
+ getUpgradeGuidance?(workspace: Workspace, metric: UsageMetric): Promise<UpgradeGuidance | null>;
34
64
  }
35
65
  //# sourceMappingURL=entitlements.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entitlements.d.ts","sourceRoot":"","sources":["../../src/ports/entitlements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,GAAG,WAAW,CAAC;AAE7E,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAErD,wFAAwF;IACxF,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEpE;;;;;;OAMG;IACH,eAAe,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC7E"}
1
+ {"version":3,"file":"entitlements.d.ts","sourceRoot":"","sources":["../../src/ports/entitlements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,GAAG,WAAW,CAAC;AAE7E,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,yFAAyF;IACzF,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC;IAC9B,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAErD,wFAAwF;IACxF,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEpE;;;;;;OAMG;IACH,eAAe,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE5E;;;;;OAKG;IACH,kBAAkB,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;CACjG"}
@@ -21,8 +21,10 @@ export type { FileStorage } from './files.js';
21
21
  export type { KeyValueStore } from './kv.js';
22
22
  export type { EventQueue, QueuedEvent } from './event-queue.js';
23
23
  export type { AuthProvider, AuthResult, AuthRequire, Workspace, Agent, } from './auth.js';
24
- export type { EntitlementsProvider, PlanLimits, UsageMetric, } from './entitlements.js';
25
- export type { TelemetrySink, TelemetryEvent } from './telemetry.js';
24
+ export type { EntitlementsProvider, PlanLimits, UpgradeGuidance, UsageMetric, } from './entitlements.js';
25
+ export { ENGINE_OBSERVATION_FACTS } from './telemetry.js';
26
+ export type { TelemetrySink, TelemetryEvent, EngineObservation, EngineObservationKind, EngineObservationFacts } from './telemetry.js';
27
+ export type { EngineLogRecord, EngineLogExport } from './logging.js';
26
28
  import type { EngineDb } from './database.js';
27
29
  import type { RealtimeBus, ConnectionRegistry, NodeConnectionRegistry } from './realtime.js';
28
30
  import type { PresenceTracker } from './presence.js';
@@ -33,6 +35,7 @@ import type { EventQueue } from './event-queue.js';
33
35
  import type { AuthProvider } from './auth.js';
34
36
  import type { EntitlementsProvider } from './entitlements.js';
35
37
  import type { TelemetrySink } from './telemetry.js';
38
+ import type { EngineLogExport } from './logging.js';
36
39
  /** Infrastructure ports the engine reads off the request context. */
37
40
  export interface EnginePorts {
38
41
  db: EngineDb;
@@ -49,7 +52,7 @@ export interface EnginePorts {
49
52
  export interface EngineProviders {
50
53
  auth: AuthProvider;
51
54
  entitlements: EntitlementsProvider;
52
- telemetry: TelemetrySink;
55
+ telemetry?: TelemetrySink;
53
56
  }
54
57
  /** Everything `createEngine` needs. */
55
58
  export interface EngineDeps extends EnginePorts, EngineProviders {
@@ -124,15 +127,8 @@ export interface EngineConfig {
124
127
  url?: string;
125
128
  secret?: string;
126
129
  };
127
- /**
128
- * When set, the structured logger exports prod logs to a PostHog OTLP endpoint
129
- * via plain fetch (no posthog-node dependency). Self-host leaves this unset and
130
- * logs to the console only; cloud wires it from its secrets.
131
- */
132
- logExport?: {
133
- posthogApiKey?: string;
134
- posthogHost?: string;
135
- };
130
+ /** Optional host-owned log transport. Console output remains enabled. */
131
+ logExport?: EngineLogExport;
136
132
  /**
137
133
  * Bounded durable mailbox tuning. Hosted adapters may provide workspace
138
134
  * overrides; self-host defaults to one hour TTL and 1000 in-flight deliveries
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"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"}