@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.
- package/dist/adapters/node/database.d.ts +8 -3
- package/dist/adapters/node/database.d.ts.map +1 -1
- package/dist/adapters/node/database.js +9 -30
- package/dist/adapters/node/database.js.map +1 -1
- package/dist/adapters/node/delivery-maintenance.d.ts.map +1 -1
- package/dist/adapters/node/delivery-maintenance.js +5 -2
- package/dist/adapters/node/delivery-maintenance.js.map +1 -1
- package/dist/adapters/node/index.d.ts.map +1 -1
- package/dist/adapters/node/index.js +2 -1
- package/dist/adapters/node/index.js.map +1 -1
- package/dist/adapters/node/migration-source.d.ts +17 -0
- package/dist/adapters/node/migration-source.d.ts.map +1 -0
- package/dist/adapters/node/migration-source.js +31 -0
- package/dist/adapters/node/migration-source.js.map +1 -0
- package/dist/adapters/node/pinned-https-fetch.d.ts +16 -0
- package/dist/adapters/node/pinned-https-fetch.d.ts.map +1 -0
- package/dist/adapters/node/pinned-https-fetch.js +83 -0
- package/dist/adapters/node/pinned-https-fetch.js.map +1 -0
- package/dist/adapters/node/sqlite-driver.d.ts +27 -0
- package/dist/adapters/node/sqlite-driver.d.ts.map +1 -0
- package/dist/adapters/node/sqlite-driver.js +9 -0
- package/dist/adapters/node/sqlite-driver.js.map +1 -0
- package/dist/adapters/node/ssrf-fetch.d.ts.map +1 -1
- package/dist/adapters/node/ssrf-fetch.js +35 -28
- package/dist/adapters/node/ssrf-fetch.js.map +1 -1
- package/dist/bin/serve.js +9 -0
- package/dist/bin/serve.js.map +1 -1
- package/dist/bin/version.d.ts +8 -0
- package/dist/bin/version.d.ts.map +1 -0
- package/dist/bin/version.js +12 -0
- package/dist/bin/version.js.map +1 -0
- package/dist/db/migrations/0076_deliveries_agent_status_created_index.sql +17 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +2 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/engine/usage.d.ts +10 -0
- package/dist/engine/usage.d.ts.map +1 -1
- package/dist/engine/usage.js +18 -0
- package/dist/engine/usage.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +8 -7
- package/dist/engine.js.map +1 -1
- package/dist/env.d.ts +11 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/httpError.d.ts.map +1 -1
- package/dist/lib/httpError.js +3 -0
- package/dist/lib/httpError.js.map +1 -1
- package/dist/lib/logger.d.ts +3 -9
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +10 -96
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/planLimitError.d.ts +26 -0
- package/dist/lib/planLimitError.d.ts.map +1 -0
- package/dist/lib/planLimitError.js +16 -0
- package/dist/lib/planLimitError.js.map +1 -0
- package/dist/lib/serverTelemetry.d.ts +6 -45
- package/dist/lib/serverTelemetry.d.ts.map +1 -1
- package/dist/lib/serverTelemetry.js +27 -125
- package/dist/lib/serverTelemetry.js.map +1 -1
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +14 -0
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/planLimits.d.ts +31 -0
- package/dist/middleware/planLimits.d.ts.map +1 -1
- package/dist/middleware/planLimits.js +136 -4
- package/dist/middleware/planLimits.js.map +1 -1
- package/dist/ports/entitlements.d.ts +30 -0
- package/dist/ports/entitlements.d.ts.map +1 -1
- package/dist/ports/index.d.ts +8 -12
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +1 -0
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/logging.d.ts +10 -0
- package/dist/ports/logging.d.ts.map +1 -0
- package/dist/ports/logging.js +2 -0
- package/dist/ports/logging.js.map +1 -0
- package/dist/ports/telemetry.d.ts +95 -23
- package/dist/ports/telemetry.d.ts.map +1 -1
- package/dist/ports/telemetry.js +77 -1
- package/dist/ports/telemetry.js.map +1 -1
- package/dist/providers/noop-telemetry.d.ts +1 -7
- package/dist/providers/noop-telemetry.d.ts.map +1 -1
- package/dist/providers/noop-telemetry.js +1 -7
- package/dist/providers/noop-telemetry.js.map +1 -1
- package/dist/providers/static-entitlements.d.ts +1 -1
- package/dist/providers/static-entitlements.d.ts.map +1 -1
- package/dist/providers/static-entitlements.js +6 -1
- package/dist/providers/static-entitlements.js.map +1 -1
- package/dist/routes/action.js +3 -3
- package/dist/routes/action.js.map +1 -1
- package/dist/routes/agent.js +8 -8
- package/dist/routes/agent.js.map +1 -1
- package/dist/routes/channel.js +9 -9
- package/dist/routes/channel.js.map +1 -1
- package/dist/routes/directory.js +5 -5
- package/dist/routes/directory.js.map +1 -1
- package/dist/routes/dm.d.ts.map +1 -1
- package/dist/routes/dm.js +4 -2
- package/dist/routes/dm.js.map +1 -1
- package/dist/routes/eventSubscription.js +2 -2
- package/dist/routes/eventSubscription.js.map +1 -1
- package/dist/routes/file.js +2 -2
- package/dist/routes/file.js.map +1 -1
- package/dist/routes/groupDm.d.ts.map +1 -1
- package/dist/routes/groupDm.js +15 -11
- package/dist/routes/groupDm.js.map +1 -1
- package/dist/routes/inboundWebhook.js +5 -6
- package/dist/routes/inboundWebhook.js.map +1 -1
- package/dist/routes/message.d.ts.map +1 -1
- package/dist/routes/message.js +7 -3
- package/dist/routes/message.js.map +1 -1
- package/dist/routes/node.js +1 -1
- package/dist/routes/node.js.map +1 -1
- package/dist/routes/presence.js +2 -2
- package/dist/routes/presence.js.map +1 -1
- package/dist/routes/reaction.js +2 -2
- package/dist/routes/reaction.js.map +1 -1
- package/dist/routes/receipt.js +1 -1
- package/dist/routes/receipt.js.map +1 -1
- package/dist/routes/relayfileInbound.d.ts.map +1 -1
- package/dist/routes/relayfileInbound.js +3 -4
- package/dist/routes/relayfileInbound.js.map +1 -1
- package/dist/routes/routing.js +3 -3
- package/dist/routes/routing.js.map +1 -1
- package/dist/routes/search.js +1 -1
- package/dist/routes/search.js.map +1 -1
- package/dist/routes/systemPrompt.js +2 -2
- package/dist/routes/systemPrompt.js.map +1 -1
- package/dist/routes/thread.d.ts.map +1 -1
- package/dist/routes/thread.js +7 -3
- package/dist/routes/thread.js.map +1 -1
- package/dist/routes/workspace.js +5 -5
- package/dist/routes/workspace.js.map +1 -1
- package/package.json +8 -4
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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":"
|
|
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;
|
|
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"}
|
package/dist/middleware/auth.js
CHANGED
|
@@ -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":"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"}
|
|
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":"
|
|
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
|
|
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
|
|
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":"
|
|
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;
|
|
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"}
|
package/dist/ports/index.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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":"AAAA;;;;;;;;;;;;GAYG;AACH,YAAY,EACV,QAAQ,EACR,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC3D,YAAY,EACV,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,sBAAsB,EACtB,WAAW,EACX,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAChE,YAAY,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,SAAS,EACT,KAAK,GACN,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,oBAAoB,EACpB,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ports/index.ts"],"names":[],"mappings":"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"}
|