@superblocksteam/gateway 2.0.161 → 2.0.162-next.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.
- package/README.md +135 -39
- package/dist/agents/resolve-orchestrator-url.d.ts +18 -0
- package/dist/agents/resolve-orchestrator-url.js +64 -1
- package/dist/agents/resolve-orchestrator-url.js.map +1 -1
- package/dist/capabilities/lifecycle.d.ts +46 -29
- package/dist/capabilities/lifecycle.js +1731 -843
- package/dist/capabilities/lifecycle.js.map +1 -1
- package/dist/capabilities/query-integration.d.ts +14 -0
- package/dist/capabilities/query-integration.js +172 -0
- package/dist/capabilities/query-integration.js.map +1 -0
- package/dist/capabilities/source-files-archive.d.ts +11 -0
- package/dist/capabilities/source-files-archive.js +54 -0
- package/dist/capabilities/source-files-archive.js.map +1 -0
- package/dist/capabilities/types.d.ts +197 -119
- package/dist/capabilities/types.js +45 -6
- package/dist/capabilities/types.js.map +1 -1
- package/dist/capture/browser-contract.d.ts +15 -5
- package/dist/capture/browser-contract.js +13 -3
- package/dist/capture/browser-contract.js.map +1 -1
- package/dist/capture/browser-instructions.d.ts +3 -2
- package/dist/capture/browser-instructions.js +3 -2
- package/dist/capture/browser-instructions.js.map +1 -1
- package/dist/capture/mode.d.ts +8 -1
- package/dist/capture/mode.js +22 -2
- package/dist/capture/mode.js.map +1 -1
- package/dist/config.d.ts +22 -23
- package/dist/config.js +13 -12
- package/dist/config.js.map +1 -1
- package/dist/deps.d.ts +7 -7
- package/dist/index.d.ts +2 -4
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/dist/integrations/read-only-postgres-query.d.ts +2 -0
- package/dist/integrations/read-only-postgres-query.js +164 -0
- package/dist/integrations/read-only-postgres-query.js.map +1 -0
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/playwright/ensure-chromium.d.ts +5 -7
- package/dist/playwright/ensure-chromium.js +13 -13
- package/dist/playwright/ensure-chromium.js.map +1 -1
- package/dist/preview/capture-screenshot.d.ts +30 -4
- package/dist/preview/capture-screenshot.js +67 -17
- package/dist/preview/capture-screenshot.js.map +1 -1
- package/dist/preview/viewer-url.js +3 -1
- package/dist/preview/viewer-url.js.map +1 -1
- package/dist/process/fault-barrier.js +1 -1
- package/dist/process/fault-barrier.js.map +1 -1
- package/dist/sabs/agent-facing-text.d.ts +2 -0
- package/dist/sabs/agent-facing-text.js +56 -2
- package/dist/sabs/agent-facing-text.js.map +1 -1
- package/dist/sabs/app-state.d.ts +126 -0
- package/dist/sabs/app-state.js +332 -0
- package/dist/sabs/app-state.js.map +1 -0
- package/dist/sabs/awaited-decision.d.ts +49 -0
- package/dist/sabs/awaited-decision.js +129 -0
- package/dist/sabs/awaited-decision.js.map +1 -0
- package/dist/sabs/editor-client-methods.d.ts +23 -5
- package/dist/sabs/editor-client-methods.js +45 -4
- package/dist/sabs/editor-client-methods.js.map +1 -1
- package/dist/sabs/editor-socket.d.ts +85 -0
- package/dist/sabs/editor-socket.js +67 -0
- package/dist/sabs/editor-socket.js.map +1 -0
- package/dist/sabs/session-peer.d.ts +119 -82
- package/dist/sabs/session-peer.js +10 -1
- package/dist/sabs/session-peer.js.map +1 -1
- package/dist/sabs/streamed-reply.d.ts +45 -0
- package/dist/sabs/streamed-reply.js +125 -0
- package/dist/sabs/streamed-reply.js.map +1 -0
- package/dist/sabs/turn-collector.d.ts +50 -35
- package/dist/sabs/turn-collector.js +110 -176
- package/dist/sabs/turn-collector.js.map +1 -1
- package/dist/sabs/websocket-session-peer.d.ts +104 -69
- package/dist/sabs/websocket-session-peer.js +1333 -477
- package/dist/sabs/websocket-session-peer.js.map +1 -1
- package/dist/server/client.d.ts +41 -9
- package/dist/server/client.js +126 -21
- package/dist/server/client.js.map +1 -1
- package/dist/start.d.ts +1 -1
- package/dist/start.js +30 -8
- package/dist/start.js.map +1 -1
- package/dist/stores/memory.d.ts +46 -0
- package/dist/stores/memory.js +163 -0
- package/dist/stores/memory.js.map +1 -0
- package/dist/stores/types.d.ts +92 -0
- package/dist/stores/types.js +11 -0
- package/dist/stores/types.js.map +1 -0
- package/dist/telemetry/mcp-client.d.ts +6 -1
- package/dist/telemetry/mcp-client.js +100 -4
- package/dist/telemetry/mcp-client.js.map +1 -1
- package/dist/telemetry/metrics.d.ts +12 -3
- package/dist/telemetry/metrics.js +60 -14
- package/dist/telemetry/metrics.js.map +1 -1
- package/dist/telemetry/runtime.js +4 -6
- package/dist/telemetry/runtime.js.map +1 -1
- package/dist/transports/mcp/admin-tools.d.ts +8 -0
- package/dist/transports/mcp/admin-tools.js +115 -4
- package/dist/transports/mcp/admin-tools.js.map +1 -1
- package/dist/transports/mcp/app-status-html.d.ts +4 -8
- package/dist/transports/mcp/app-status-html.js +336 -128
- package/dist/transports/mcp/app-status-html.js.map +1 -1
- package/dist/transports/mcp/client-presentation.d.ts +16 -0
- package/dist/transports/mcp/client-presentation.js +13 -0
- package/dist/transports/mcp/client-presentation.js.map +1 -0
- package/dist/transports/mcp/cowork-editor-url.d.ts +6 -0
- package/dist/transports/mcp/cowork-editor-url.js +10 -0
- package/dist/transports/mcp/cowork-editor-url.js.map +1 -0
- package/dist/transports/mcp/decision-card-html.d.ts +26 -0
- package/dist/transports/mcp/decision-card-html.js +876 -0
- package/dist/transports/mcp/decision-card-html.js.map +1 -0
- package/dist/transports/mcp/decision-elicitation.d.ts +42 -0
- package/dist/transports/mcp/decision-elicitation.js +59 -0
- package/dist/transports/mcp/decision-elicitation.js.map +1 -1
- package/dist/transports/mcp/editor-document-probe.d.ts +4 -0
- package/dist/transports/mcp/editor-document-probe.js +35 -0
- package/dist/transports/mcp/editor-document-probe.js.map +1 -0
- package/dist/transports/mcp/editor-integration-setup-url.d.ts +14 -0
- package/dist/transports/mcp/editor-integration-setup-url.js +29 -0
- package/dist/transports/mcp/editor-integration-setup-url.js.map +1 -0
- package/dist/transports/mcp/format-tool-content.d.ts +13 -18
- package/dist/transports/mcp/format-tool-content.js +172 -13
- package/dist/transports/mcp/format-tool-content.js.map +1 -1
- package/dist/transports/mcp/instructions/index.d.ts +23 -0
- package/dist/transports/mcp/instructions/index.js +81 -0
- package/dist/transports/mcp/instructions/index.js.map +1 -0
- package/dist/transports/mcp/instructions/result.d.ts +18 -0
- package/dist/transports/mcp/instructions/result.js +58 -0
- package/dist/transports/mcp/instructions/result.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/ask-user.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/ask-user.js +20 -0
- package/dist/transports/mcp/instructions/tools/ask-user.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/build-app.d.ts +4 -0
- package/dist/transports/mcp/instructions/tools/build-app.js +54 -0
- package/dist/transports/mcp/instructions/tools/build-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/check-app-progress.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/check-app-progress.js +79 -0
- package/dist/transports/mcp/instructions/tools/check-app-progress.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/check-publish-progress.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/check-publish-progress.js +23 -0
- package/dist/transports/mcp/instructions/tools/check-publish-progress.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/copy.d.ts +18 -0
- package/dist/transports/mcp/instructions/tools/copy.js +49 -0
- package/dist/transports/mcp/instructions/tools/copy.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/create-integration.d.ts +4 -0
- package/dist/transports/mcp/instructions/tools/create-integration.js +41 -0
- package/dist/transports/mcp/instructions/tools/create-integration.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/edit-app.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/edit-app.js +18 -0
- package/dist/transports/mcp/instructions/tools/edit-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/get-app.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/get-app.js +49 -0
- package/dist/transports/mcp/instructions/tools/get-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/get-integration-metadata.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/get-integration-metadata.js +13 -0
- package/dist/transports/mcp/instructions/tools/get-integration-metadata.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/index.d.ts +7 -0
- package/dist/transports/mcp/instructions/tools/index.js +31 -0
- package/dist/transports/mcp/instructions/tools/index.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/publish-app.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/publish-app.js +23 -0
- package/dist/transports/mcp/instructions/tools/publish-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/start-app.d.ts +3 -0
- package/dist/transports/mcp/instructions/tools/start-app.js +22 -0
- package/dist/transports/mcp/instructions/tools/start-app.js.map +1 -0
- package/dist/transports/mcp/instructions/tools/upload-artifact.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/upload-artifact.js +13 -0
- package/dist/transports/mcp/instructions/tools/upload-artifact.js.map +1 -0
- package/dist/transports/mcp/mcp-app-brand-css.d.ts +1 -0
- package/dist/transports/mcp/mcp-app-brand-css.js +180 -0
- package/dist/transports/mcp/mcp-app-brand-css.js.map +1 -0
- package/dist/transports/mcp/mount.d.ts +14 -1
- package/dist/transports/mcp/mount.js +729 -172
- package/dist/transports/mcp/mount.js.map +1 -1
- package/dist/transports/mcp/native-browser-presence.d.ts +45 -0
- package/dist/transports/mcp/native-browser-presence.js +158 -0
- package/dist/transports/mcp/native-browser-presence.js.map +1 -0
- package/dist/transports/mcp/plan-approval.d.ts +44 -0
- package/dist/transports/mcp/plan-approval.js +179 -0
- package/dist/transports/mcp/plan-approval.js.map +1 -0
- package/dist/transports/mcp/session-directory.d.ts +7 -0
- package/dist/transports/mcp/session-directory.js +18 -0
- package/dist/transports/mcp/session-directory.js.map +1 -0
- package/dist/transports/mcp/tool-names.d.ts +2 -0
- package/dist/transports/mcp/tool-names.js +2 -0
- package/dist/transports/mcp/tool-names.js.map +1 -0
- package/package.json +16 -7
- package/skills/superblocks-build/SKILL.md +59 -0
- package/skills/superblocks-import/SKILL.md +125 -0
- package/dist/capabilities/import-prompt.d.ts +0 -11
- package/dist/capabilities/import-prompt.js +0 -96
- package/dist/capabilities/import-prompt.js.map +0 -1
- package/dist/capabilities/persisted-progress.d.ts +0 -46
- package/dist/capabilities/persisted-progress.js +0 -246
- package/dist/capabilities/persisted-progress.js.map +0 -1
- package/dist/events/cursor.d.ts +0 -43
- package/dist/events/cursor.js +0 -78
- package/dist/events/cursor.js.map +0 -1
- package/dist/events/memory-event-store.d.ts +0 -34
- package/dist/events/memory-event-store.js +0 -110
- package/dist/events/memory-event-store.js.map +0 -1
- package/dist/events/merge.d.ts +0 -23
- package/dist/events/merge.js +0 -97
- package/dist/events/merge.js.map +0 -1
- package/dist/events/normalized-collector.d.ts +0 -62
- package/dist/events/normalized-collector.js +0 -156
- package/dist/events/normalized-collector.js.map +0 -1
- package/dist/events/schema.d.ts +0 -9
- package/dist/events/schema.js +0 -93
- package/dist/events/schema.js.map +0 -1
- package/dist/events/snapshot.d.ts +0 -32
- package/dist/events/snapshot.js +0 -57
- package/dist/events/snapshot.js.map +0 -1
- package/dist/events/stream-key.d.ts +0 -2
- package/dist/events/stream-key.js +0 -31
- package/dist/events/stream-key.js.map +0 -1
- package/dist/events/types.d.ts +0 -179
- package/dist/events/types.js +0 -66
- package/dist/events/types.js.map +0 -1
- package/dist/resume/memory-progress-store.d.ts +0 -39
- package/dist/resume/memory-progress-store.js +0 -82
- package/dist/resume/memory-progress-store.js.map +0 -1
- package/dist/resume/memory-recent-app-store.d.ts +0 -14
- package/dist/resume/memory-recent-app-store.js +0 -27
- package/dist/resume/memory-recent-app-store.js.map +0 -1
- package/dist/resume/memory-turn-store.d.ts +0 -18
- package/dist/resume/memory-turn-store.js +0 -73
- package/dist/resume/memory-turn-store.js.map +0 -1
- package/dist/resume/progress-key.d.ts +0 -21
- package/dist/resume/progress-key.js +0 -58
- package/dist/resume/progress-key.js.map +0 -1
- package/dist/resume/stores.d.ts +0 -14
- package/dist/resume/stores.js +0 -18
- package/dist/resume/stores.js.map +0 -1
- package/dist/resume/types.d.ts +0 -124
- package/dist/resume/types.js +0 -13
- package/dist/resume/types.js.map +0 -1
package/dist/events/schema.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { CHAT_ROLES, EVENT_CONTRACT_VERSION, EVENT_PRODUCERS, GENERATION_STATES, MAX_IDENTIFIER_LENGTH, MAX_LABEL_LENGTH, MAX_SEQUENCE, MAX_TEXT_LENGTH, SESSION_STATUSES, } from "./types.js";
|
|
3
|
-
const identifier = z.string().min(1).max(MAX_IDENTIFIER_LENGTH);
|
|
4
|
-
/**
|
|
5
|
-
* Payloads are strict objects: an unrecognized key fails the parse rather than
|
|
6
|
-
* being dropped. A field nobody declared is a field nobody bounded, and this
|
|
7
|
-
* body arrives from outside the process.
|
|
8
|
-
*/
|
|
9
|
-
const payloadByKind = {
|
|
10
|
-
auth_required: z
|
|
11
|
-
.object({ reason: z.string().max(MAX_LABEL_LENGTH).optional() })
|
|
12
|
-
.strict(),
|
|
13
|
-
chat_message: z
|
|
14
|
-
.object({
|
|
15
|
-
messageId: z.string().max(MAX_IDENTIFIER_LENGTH).optional(),
|
|
16
|
-
messageType: z.string().max(MAX_IDENTIFIER_LENGTH).optional(),
|
|
17
|
-
role: z.enum(CHAT_ROLES),
|
|
18
|
-
text: z.string().min(1).max(MAX_TEXT_LENGTH),
|
|
19
|
-
})
|
|
20
|
-
.strict(),
|
|
21
|
-
generation_state: z
|
|
22
|
-
.object({
|
|
23
|
-
hasError: z.boolean().optional(),
|
|
24
|
-
hasSuggestions: z.boolean().optional(),
|
|
25
|
-
state: z.enum(GENERATION_STATES),
|
|
26
|
-
})
|
|
27
|
-
.strict(),
|
|
28
|
-
progress: z
|
|
29
|
-
.object({ label: z.string().min(1).max(MAX_LABEL_LENGTH) })
|
|
30
|
-
.strict(),
|
|
31
|
-
session: z.object({ status: z.enum(SESSION_STATUSES) }).strict(),
|
|
32
|
-
};
|
|
33
|
-
const envelope = z
|
|
34
|
-
.object({
|
|
35
|
-
applicationId: identifier,
|
|
36
|
-
eventId: identifier,
|
|
37
|
-
gatewayTurnId: z.string().max(MAX_IDENTIFIER_LENGTH).optional(),
|
|
38
|
-
kind: z.enum(Object.keys(payloadByKind)),
|
|
39
|
-
liveEditId: identifier,
|
|
40
|
-
occurredAt: z.string().min(1),
|
|
41
|
-
organizationId: identifier,
|
|
42
|
-
payload: z.unknown(),
|
|
43
|
-
producer: z.enum(EVENT_PRODUCERS),
|
|
44
|
-
sequence: z.number().int().positive().max(MAX_SEQUENCE),
|
|
45
|
-
version: z.number().int(),
|
|
46
|
-
})
|
|
47
|
-
.strict();
|
|
48
|
-
/**
|
|
49
|
-
* Validates one inbound event against the contract.
|
|
50
|
-
*
|
|
51
|
-
* SABS validates the same shape before pushing it, which is not a reason to
|
|
52
|
-
* skip it here: a validated producer is not a trusted one, and this is the
|
|
53
|
-
* process boundary where the bytes become Gateway's problem.
|
|
54
|
-
*/
|
|
55
|
-
export function parseLiveEditEvent(input) {
|
|
56
|
-
const parsed = envelope.safeParse(input);
|
|
57
|
-
if (!parsed.success) {
|
|
58
|
-
return { ok: false, reason: "malformed_event" };
|
|
59
|
-
}
|
|
60
|
-
// Version is checked before the payload so an event from a future contract
|
|
61
|
-
// is reported as such rather than as a malformed body.
|
|
62
|
-
if (parsed.data.version !== EVENT_CONTRACT_VERSION) {
|
|
63
|
-
return { ok: false, reason: "unsupported_version" };
|
|
64
|
-
}
|
|
65
|
-
const occurredAtMs = Date.parse(parsed.data.occurredAt);
|
|
66
|
-
if (Number.isNaN(occurredAtMs)) {
|
|
67
|
-
return { ok: false, reason: "malformed_event" };
|
|
68
|
-
}
|
|
69
|
-
const payload = payloadByKind[parsed.data.kind].safeParse(parsed.data.payload);
|
|
70
|
-
if (!payload.success) {
|
|
71
|
-
return { ok: false, reason: "malformed_event" };
|
|
72
|
-
}
|
|
73
|
-
const event = {
|
|
74
|
-
applicationId: parsed.data.applicationId,
|
|
75
|
-
eventId: parsed.data.eventId,
|
|
76
|
-
...(parsed.data.gatewayTurnId
|
|
77
|
-
? { gatewayTurnId: parsed.data.gatewayTurnId }
|
|
78
|
-
: {}),
|
|
79
|
-
kind: parsed.data.kind,
|
|
80
|
-
liveEditId: parsed.data.liveEditId,
|
|
81
|
-
occurredAtMs,
|
|
82
|
-
organizationId: parsed.data.organizationId,
|
|
83
|
-
payload: {
|
|
84
|
-
kind: parsed.data.kind,
|
|
85
|
-
...payload.data,
|
|
86
|
-
},
|
|
87
|
-
producer: parsed.data.producer,
|
|
88
|
-
sequence: parsed.data.sequence,
|
|
89
|
-
version: EVENT_CONTRACT_VERSION,
|
|
90
|
-
};
|
|
91
|
-
return { ok: true, event };
|
|
92
|
-
}
|
|
93
|
-
//# sourceMappingURL=schema.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/events/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { type EventCursor } from "./cursor.js";
|
|
2
|
-
import type { EventProducer, EventSnapshot, LiveEditEvent } from "./types.js";
|
|
3
|
-
export type SnapshotReads = {
|
|
4
|
-
/**
|
|
5
|
-
* Lowest sequence this producer's stream still holds, or undefined when the
|
|
6
|
-
* stream is empty. This is the retention boundary a stale cursor fell off.
|
|
7
|
-
*/
|
|
8
|
-
firstRetainedSequence(producer: EventProducer): Promise<number | undefined>;
|
|
9
|
-
/** Strictly-after-sequence read, done by the store rather than by filtering. */
|
|
10
|
-
readAfter(input: {
|
|
11
|
-
afterSequence: number;
|
|
12
|
-
limit?: number;
|
|
13
|
-
producer: EventProducer;
|
|
14
|
-
}): Promise<LiveEditEvent[]>;
|
|
15
|
-
/** Newest `count` events of one producer's stream, oldest first. */
|
|
16
|
-
readTail(input: {
|
|
17
|
-
count: number;
|
|
18
|
-
producer: EventProducer;
|
|
19
|
-
}): Promise<LiveEditEvent[]>;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Assembles a snapshot from a store's three reads.
|
|
23
|
-
*
|
|
24
|
-
* Shared rather than written twice so the memory and Redis stores cannot drift
|
|
25
|
-
* into disagreeing about what resuming means — the same reason both build
|
|
26
|
-
* their keys from one builder. Each store supplies only the reads; the cursor
|
|
27
|
-
* arithmetic and the staleness rule live here.
|
|
28
|
-
*/
|
|
29
|
-
export declare function buildSnapshot(input: {
|
|
30
|
-
cursor?: EventCursor;
|
|
31
|
-
limit?: number;
|
|
32
|
-
}, reads: SnapshotReads): Promise<EventSnapshot>;
|
package/dist/events/snapshot.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { advanceEventCursor, cursorPosition, } from "./cursor.js";
|
|
2
|
-
import { PRODUCERS_IN_ORDER, sortEvents } from "./merge.js";
|
|
3
|
-
import { EVENT_SNAPSHOT_TAIL } from "./types.js";
|
|
4
|
-
/**
|
|
5
|
-
* Assembles a snapshot from a store's three reads.
|
|
6
|
-
*
|
|
7
|
-
* Shared rather than written twice so the memory and Redis stores cannot drift
|
|
8
|
-
* into disagreeing about what resuming means — the same reason both build
|
|
9
|
-
* their keys from one builder. Each store supplies only the reads; the cursor
|
|
10
|
-
* arithmetic and the staleness rule live here.
|
|
11
|
-
*/
|
|
12
|
-
export async function buildSnapshot(input, reads) {
|
|
13
|
-
const collected = [];
|
|
14
|
-
const tail = [];
|
|
15
|
-
const lost = [];
|
|
16
|
-
for (const producer of PRODUCERS_IN_ORDER) {
|
|
17
|
-
const resumedAfterSequence = cursorPosition(input.cursor, producer);
|
|
18
|
-
const afterEvents = await reads.readAfter({
|
|
19
|
-
afterSequence: resumedAfterSequence,
|
|
20
|
-
...(input.limit === undefined ? {} : { limit: input.limit }),
|
|
21
|
-
producer,
|
|
22
|
-
});
|
|
23
|
-
collected.push(...afterEvents);
|
|
24
|
-
tail.push(...(await reads.readTail({ count: EVENT_SNAPSHOT_TAIL, producer })));
|
|
25
|
-
const firstRetainedSequence = await reads.firstRetainedSequence(producer);
|
|
26
|
-
// readAfter and firstRetainedSequence are two separate reads, not one
|
|
27
|
-
// atomic one, so retention can advance between them: firstRetainedSequence
|
|
28
|
-
// can then report a boundary past events readAfter had already captured
|
|
29
|
-
// moments earlier. A delivered sequence below that boundary proves the
|
|
30
|
-
// read beat the eviction, so what looks like a gap here never actually
|
|
31
|
-
// reached the caller as one.
|
|
32
|
-
const minDelivered = afterEvents.length > 0
|
|
33
|
-
? Math.min(...afterEvents.map((event) => event.sequence))
|
|
34
|
-
: undefined;
|
|
35
|
-
const provenByDelivery = firstRetainedSequence !== undefined &&
|
|
36
|
-
minDelivered !== undefined &&
|
|
37
|
-
minDelivered < firstRetainedSequence;
|
|
38
|
-
// A gap only exists when the stream starts *past* the next sequence the
|
|
39
|
-
// cursor expects. An empty stream is not a gap: nothing was produced yet.
|
|
40
|
-
if (firstRetainedSequence !== undefined &&
|
|
41
|
-
firstRetainedSequence > resumedAfterSequence + 1 &&
|
|
42
|
-
!provenByDelivery) {
|
|
43
|
-
lost.push({ firstRetainedSequence, producer, resumedAfterSequence });
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const events = sortEvents(collected);
|
|
47
|
-
const limited = input.limit === undefined ? events : events.slice(0, input.limit);
|
|
48
|
-
return {
|
|
49
|
-
// Advanced past what is actually being handed over, never past what was
|
|
50
|
-
// read and then cut by the limit — otherwise the remainder is skipped.
|
|
51
|
-
cursor: advanceEventCursor(input.cursor, limited),
|
|
52
|
-
events: limited,
|
|
53
|
-
lost,
|
|
54
|
-
tail: sortEvents(tail),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
//# sourceMappingURL=snapshot.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/events/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,cAAc,GAEf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,mBAAmB,EAAuB,MAAM,YAAY,CAAC;AAqBtE;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA+C,EAC/C,KAAoB;IAEpB,MAAM,SAAS,GAAoB,EAAE,CAAC;IACtC,MAAM,IAAI,GAAoB,EAAE,CAAC;IACjC,MAAM,IAAI,GAAqB,EAAE,CAAC;IAElC,KAAK,MAAM,QAAQ,IAAI,kBAAkB,EAAE,CAAC;QAC1C,MAAM,oBAAoB,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpE,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC;YACxC,aAAa,EAAE,oBAAoB;YACnC,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5D,QAAQ;SACT,CAAC,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,CACP,GAAG,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,CAAC,CAAC,CACpE,CAAC;QAEF,MAAM,qBAAqB,GAAG,MAAM,KAAK,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAC1E,sEAAsE;QACtE,2EAA2E;QAC3E,wEAAwE;QACxE,uEAAuE;QACvE,uEAAuE;QACvE,6BAA6B;QAC7B,MAAM,YAAY,GAChB,WAAW,CAAC,MAAM,GAAG,CAAC;YACpB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACzD,CAAC,CAAC,SAAS,CAAC;QAChB,MAAM,gBAAgB,GACpB,qBAAqB,KAAK,SAAS;YACnC,YAAY,KAAK,SAAS;YAC1B,YAAY,GAAG,qBAAqB,CAAC;QAEvC,wEAAwE;QACxE,0EAA0E;QAC1E,IACE,qBAAqB,KAAK,SAAS;YACnC,qBAAqB,GAAG,oBAAoB,GAAG,CAAC;YAChD,CAAC,gBAAgB,EACjB,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,EAAE,qBAAqB,EAAE,QAAQ,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACrC,MAAM,OAAO,GACX,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACpE,OAAO;QACL,wEAAwE;QACxE,uEAAuE;QACvE,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;QACjD,MAAM,EAAE,OAAO;QACf,IAAI;QACJ,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC;KACvB,CAAC;AACJ,CAAC"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
/**
|
|
3
|
-
* Builds the stream address shared by every event store, so the two
|
|
4
|
-
* implementations cannot drift into addressing streams differently.
|
|
5
|
-
*
|
|
6
|
-
* Tenant identifiers (organization, application, live edit) are length-
|
|
7
|
-
* prefixed and SHA-256-digested before they reach Redis. Length-prefixing
|
|
8
|
-
* keeps `a:b`+`c` and `a`+`b:c` from colliding; digesting keeps the
|
|
9
|
-
* identifiers themselves out of key listings — ProgressStore already does
|
|
10
|
-
* the same for caller/org/app. The producer stays in the clear: it is a
|
|
11
|
-
* closed enum (`dev_server` | `sabs`), cannot identify a tenant, and naming
|
|
12
|
-
* the stream at a glance is worth more than the nothing it discloses.
|
|
13
|
-
*
|
|
14
|
-
* v0 has not shipped this key format, so there is no dual-read. Existing
|
|
15
|
-
* local Redis event keys from earlier builds are orphaned after deploy.
|
|
16
|
-
*/
|
|
17
|
-
function digest(parts) {
|
|
18
|
-
const hash = createHash("sha256");
|
|
19
|
-
for (const part of parts) {
|
|
20
|
-
hash.update(`${part.length}:${part}`);
|
|
21
|
-
}
|
|
22
|
-
return hash.digest("hex");
|
|
23
|
-
}
|
|
24
|
-
export function streamSuffix(scope, producer) {
|
|
25
|
-
return `${digest([
|
|
26
|
-
scope.organizationId,
|
|
27
|
-
scope.applicationId,
|
|
28
|
-
scope.liveEditId,
|
|
29
|
-
])}:${producer}`;
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=stream-key.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stream-key.js","sourceRoot":"","sources":["../../src/events/stream-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC;;;;;;;;;;;;;;GAcG;AACH,SAAS,MAAM,CAAC,KAAwB;IACtC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,KAAiB,EACjB,QAAuB;IAEvB,OAAO,GAAG,MAAM,CAAC;QACf,KAAK,CAAC,cAAc;QACpB,KAAK,CAAC,aAAa;QACnB,KAAK,CAAC,UAAU;KACjB,CAAC,IAAI,QAAQ,EAAE,CAAC;AACnB,CAAC"}
|
package/dist/events/types.d.ts
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import type { EventCursor } from "./cursor.js";
|
|
2
|
-
/**
|
|
3
|
-
* The versioned event contract SABS pushes over the direct authenticated
|
|
4
|
-
* callback. This mirrors `sabs/internal/gateway/event.go`; the two are kept in
|
|
5
|
-
* step by hand because the channel is deliberately not proto, and the bounds
|
|
6
|
-
* below are the only thing standing between a producer bug and unbounded
|
|
7
|
-
* Redis growth.
|
|
8
|
-
*/
|
|
9
|
-
export declare const EVENT_CONTRACT_VERSION = 1;
|
|
10
|
-
export declare const MAX_IDENTIFIER_LENGTH = 128;
|
|
11
|
-
export declare const MAX_LABEL_LENGTH = 512;
|
|
12
|
-
export declare const MAX_TEXT_LENGTH = 8192;
|
|
13
|
-
/**
|
|
14
|
-
* Ceiling on an inbound sequence number. Every consumer of `sequence`
|
|
15
|
-
* (cursor comparisons, gap detection) does so with ordinary JS number
|
|
16
|
-
* arithmetic, which stops being exact past this point; a producer sequence
|
|
17
|
-
* that reached it would silently corrupt ordering rather than fail loudly.
|
|
18
|
-
*/
|
|
19
|
-
export declare const MAX_SEQUENCE: number;
|
|
20
|
-
/** Kinds of fact a live-edit session reports. */
|
|
21
|
-
export declare const EVENT_KINDS: readonly ["auth_required", "chat_message", "generation_state", "progress", "session"];
|
|
22
|
-
export type LiveEditEventKind = (typeof EVENT_KINDS)[number];
|
|
23
|
-
/**
|
|
24
|
-
* Which stream a sequence number belongs to. The SABS control plane and the
|
|
25
|
-
* dev server both push about the same live edit and neither can see the
|
|
26
|
-
* other's counter, so ordering is defined per producer and Gateway keeps the
|
|
27
|
-
* two streams apart.
|
|
28
|
-
*/
|
|
29
|
-
export declare const EVENT_PRODUCERS: readonly ["dev_server", "sabs"];
|
|
30
|
-
export type EventProducer = (typeof EVENT_PRODUCERS)[number];
|
|
31
|
-
export declare const GENERATION_STATES: readonly ["awaiting_user_input", "cancelled", "completed", "debugging", "generating", "idle", "summarizing"];
|
|
32
|
-
export declare const CHAT_ROLES: readonly ["assistant", "user"];
|
|
33
|
-
export declare const SESSION_STATUSES: readonly ["created", "terminated"];
|
|
34
|
-
export type LiveEditEventPayload = {
|
|
35
|
-
kind: "auth_required";
|
|
36
|
-
reason?: string;
|
|
37
|
-
} | {
|
|
38
|
-
kind: "chat_message";
|
|
39
|
-
messageId?: string;
|
|
40
|
-
messageType?: string;
|
|
41
|
-
role: (typeof CHAT_ROLES)[number];
|
|
42
|
-
text: string;
|
|
43
|
-
} | {
|
|
44
|
-
kind: "generation_state";
|
|
45
|
-
hasError?: boolean;
|
|
46
|
-
hasSuggestions?: boolean;
|
|
47
|
-
state: (typeof GENERATION_STATES)[number];
|
|
48
|
-
} | {
|
|
49
|
-
kind: "progress";
|
|
50
|
-
label: string;
|
|
51
|
-
} | {
|
|
52
|
-
kind: "session";
|
|
53
|
-
status: (typeof SESSION_STATUSES)[number];
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* One accepted event. `occurredAtMs` replaces the wire's ISO string so
|
|
57
|
-
* ordering never depends on re-parsing, and `payload` is narrowed by `kind`.
|
|
58
|
-
*/
|
|
59
|
-
export type LiveEditEvent = {
|
|
60
|
-
applicationId: string;
|
|
61
|
-
eventId: string;
|
|
62
|
-
gatewayTurnId?: string;
|
|
63
|
-
kind: LiveEditEventKind;
|
|
64
|
-
liveEditId: string;
|
|
65
|
-
occurredAtMs: number;
|
|
66
|
-
organizationId: string;
|
|
67
|
-
payload: LiveEditEventPayload;
|
|
68
|
-
producer: EventProducer;
|
|
69
|
-
sequence: number;
|
|
70
|
-
version: typeof EVENT_CONTRACT_VERSION;
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* Why an event was refused. These values reach a metric label, so the set is
|
|
74
|
-
* closed and carries nothing derived from the event's content.
|
|
75
|
-
*/
|
|
76
|
-
export type EventRejectionReason = "malformed_event" | "unsupported_version";
|
|
77
|
-
export type ParseResult = {
|
|
78
|
-
ok: true;
|
|
79
|
-
event: LiveEditEvent;
|
|
80
|
-
} | {
|
|
81
|
-
ok: false;
|
|
82
|
-
reason: EventRejectionReason;
|
|
83
|
-
};
|
|
84
|
-
/** Outcome of persisting one event. */
|
|
85
|
-
export type AppendOutcome = "accepted" | "duplicate";
|
|
86
|
-
/**
|
|
87
|
-
* The whole tenant path to one live-edit stream.
|
|
88
|
-
*
|
|
89
|
-
* A live-edit id alone would be enough to address a stream, and that is
|
|
90
|
-
* exactly the problem: it makes the store's isolation depend entirely on
|
|
91
|
-
* every caller having validated ownership first. Carrying the tenant in the
|
|
92
|
-
* key means a read cannot reach another tenant's history even if something
|
|
93
|
-
* upstream let the wrong id through.
|
|
94
|
-
*/
|
|
95
|
-
export type EventScope = {
|
|
96
|
-
applicationId: string;
|
|
97
|
-
liveEditId: string;
|
|
98
|
-
organizationId: string;
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* A producer whose retention boundary overtook a caller's cursor.
|
|
102
|
-
*
|
|
103
|
-
* Reported rather than hidden: the caller asked to continue from a position
|
|
104
|
-
* that no longer exists, and answering with only the events that survived
|
|
105
|
-
* would present a stream with a hole in it as a complete one. Naming the
|
|
106
|
-
* producer and both boundaries lets a caller say exactly what it lost.
|
|
107
|
-
*/
|
|
108
|
-
export type LostEventRange = {
|
|
109
|
-
/** Lowest sequence this producer's stream still holds. */
|
|
110
|
-
firstRetainedSequence: number;
|
|
111
|
-
producer: EventProducer;
|
|
112
|
-
/** Last sequence the caller's cursor had consumed. */
|
|
113
|
-
resumedAfterSequence: number;
|
|
114
|
-
};
|
|
115
|
-
/**
|
|
116
|
-
* How many events at the end of each producer's stream a snapshot carries.
|
|
117
|
-
*
|
|
118
|
-
* Current state has to be read from the stream's end rather than from the
|
|
119
|
-
* window after the cursor: a caller that already consumed the terminal event
|
|
120
|
-
* would otherwise be told nothing is known and would poll a build that ended.
|
|
121
|
-
* A tail bounds that read so it does not grow with the length of the session.
|
|
122
|
-
*/
|
|
123
|
-
export declare const EVENT_SNAPSHOT_TAIL = 64;
|
|
124
|
-
/**
|
|
125
|
-
* What one caller sees when it resumes reading a live edit.
|
|
126
|
-
*
|
|
127
|
-
* `events` is what is new for this caller and `tail` is where the session
|
|
128
|
-
* currently stands; the two overlap freely and a reader is expected to take
|
|
129
|
-
* activity from the first and state from the second.
|
|
130
|
-
*/
|
|
131
|
-
export type EventSnapshot = {
|
|
132
|
-
/** Advanced past every event in {@link EventSnapshot.events}. */
|
|
133
|
-
cursor: EventCursor;
|
|
134
|
-
/** Strictly after the incoming cursor, ordered deterministically. */
|
|
135
|
-
events: LiveEditEvent[];
|
|
136
|
-
/** Empty when the cursor was still inside every stream's retention. */
|
|
137
|
-
lost: LostEventRange[];
|
|
138
|
-
/** Newest {@link EVENT_SNAPSHOT_TAIL} events per producer, cursor aside. */
|
|
139
|
-
tail: LiveEditEvent[];
|
|
140
|
-
};
|
|
141
|
-
/**
|
|
142
|
-
* Durable, bounded record of what happened in a live-edit session.
|
|
143
|
-
*
|
|
144
|
-
* Retention is bounded twice over: a stream holds at most
|
|
145
|
-
* {@link MAX_EVENTS_PER_STREAM} events and expires after
|
|
146
|
-
* {@link EVENT_STREAM_TTL_MS} of silence. This is the source a resumed caller
|
|
147
|
-
* reads. Live turns hear Clark over the editor websocket.
|
|
148
|
-
*/
|
|
149
|
-
export type EventStore = {
|
|
150
|
-
/** The event carries its own scope, so an append cannot be misfiled. */
|
|
151
|
-
append(event: LiveEditEvent): Promise<AppendOutcome>;
|
|
152
|
-
/** Events for a live edit, ordered deterministically across producers. */
|
|
153
|
-
list(input: EventScope & {
|
|
154
|
-
afterSequence?: number;
|
|
155
|
-
limit?: number;
|
|
156
|
-
producer?: EventProducer;
|
|
157
|
-
}): Promise<LiveEditEvent[]>;
|
|
158
|
-
/**
|
|
159
|
-
* Everything one caller needs to continue from where it left off, read
|
|
160
|
-
* without consuming anything: two callers resuming the same live edit each
|
|
161
|
-
* get their own view of it.
|
|
162
|
-
*/
|
|
163
|
-
snapshot(input: EventScope & {
|
|
164
|
-
cursor?: EventCursor;
|
|
165
|
-
limit?: number;
|
|
166
|
-
}): Promise<EventSnapshot>;
|
|
167
|
-
};
|
|
168
|
-
/**
|
|
169
|
-
* Per-(live edit, producer) retention bound. A runaway producer overwrites its
|
|
170
|
-
* own oldest events rather than growing Redis without limit. The trade-off is
|
|
171
|
-
* explicit: an event evicted by count loses its de-duplication record, so a
|
|
172
|
-
* redelivery arriving after eviction is accepted again. Bounded memory is
|
|
173
|
-
* worth more than perfect de-duplication of an event nobody can still read.
|
|
174
|
-
*/
|
|
175
|
-
export declare const MAX_EVENTS_PER_STREAM = 500;
|
|
176
|
-
/** How long a silent stream is kept before Redis reclaims it. */
|
|
177
|
-
export declare const EVENT_STREAM_TTL_MS = 3600000;
|
|
178
|
-
/** Cap on one inbound batch, matching the SABS publish bound. */
|
|
179
|
-
export declare const MAX_EVENTS_PER_REQUEST = 64;
|
package/dist/events/types.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The versioned event contract SABS pushes over the direct authenticated
|
|
3
|
-
* callback. This mirrors `sabs/internal/gateway/event.go`; the two are kept in
|
|
4
|
-
* step by hand because the channel is deliberately not proto, and the bounds
|
|
5
|
-
* below are the only thing standing between a producer bug and unbounded
|
|
6
|
-
* Redis growth.
|
|
7
|
-
*/
|
|
8
|
-
export const EVENT_CONTRACT_VERSION = 1;
|
|
9
|
-
export const MAX_IDENTIFIER_LENGTH = 128;
|
|
10
|
-
export const MAX_LABEL_LENGTH = 512;
|
|
11
|
-
export const MAX_TEXT_LENGTH = 8192;
|
|
12
|
-
/**
|
|
13
|
-
* Ceiling on an inbound sequence number. Every consumer of `sequence`
|
|
14
|
-
* (cursor comparisons, gap detection) does so with ordinary JS number
|
|
15
|
-
* arithmetic, which stops being exact past this point; a producer sequence
|
|
16
|
-
* that reached it would silently corrupt ordering rather than fail loudly.
|
|
17
|
-
*/
|
|
18
|
-
export const MAX_SEQUENCE = Number.MAX_SAFE_INTEGER;
|
|
19
|
-
/** Kinds of fact a live-edit session reports. */
|
|
20
|
-
export const EVENT_KINDS = [
|
|
21
|
-
"auth_required",
|
|
22
|
-
"chat_message",
|
|
23
|
-
"generation_state",
|
|
24
|
-
"progress",
|
|
25
|
-
"session",
|
|
26
|
-
];
|
|
27
|
-
/**
|
|
28
|
-
* Which stream a sequence number belongs to. The SABS control plane and the
|
|
29
|
-
* dev server both push about the same live edit and neither can see the
|
|
30
|
-
* other's counter, so ordering is defined per producer and Gateway keeps the
|
|
31
|
-
* two streams apart.
|
|
32
|
-
*/
|
|
33
|
-
export const EVENT_PRODUCERS = ["dev_server", "sabs"];
|
|
34
|
-
export const GENERATION_STATES = [
|
|
35
|
-
"awaiting_user_input",
|
|
36
|
-
"cancelled",
|
|
37
|
-
"completed",
|
|
38
|
-
"debugging",
|
|
39
|
-
"generating",
|
|
40
|
-
"idle",
|
|
41
|
-
"summarizing",
|
|
42
|
-
];
|
|
43
|
-
export const CHAT_ROLES = ["assistant", "user"];
|
|
44
|
-
export const SESSION_STATUSES = ["created", "terminated"];
|
|
45
|
-
/**
|
|
46
|
-
* How many events at the end of each producer's stream a snapshot carries.
|
|
47
|
-
*
|
|
48
|
-
* Current state has to be read from the stream's end rather than from the
|
|
49
|
-
* window after the cursor: a caller that already consumed the terminal event
|
|
50
|
-
* would otherwise be told nothing is known and would poll a build that ended.
|
|
51
|
-
* A tail bounds that read so it does not grow with the length of the session.
|
|
52
|
-
*/
|
|
53
|
-
export const EVENT_SNAPSHOT_TAIL = 64;
|
|
54
|
-
/**
|
|
55
|
-
* Per-(live edit, producer) retention bound. A runaway producer overwrites its
|
|
56
|
-
* own oldest events rather than growing Redis without limit. The trade-off is
|
|
57
|
-
* explicit: an event evicted by count loses its de-duplication record, so a
|
|
58
|
-
* redelivery arriving after eviction is accepted again. Bounded memory is
|
|
59
|
-
* worth more than perfect de-duplication of an event nobody can still read.
|
|
60
|
-
*/
|
|
61
|
-
export const MAX_EVENTS_PER_STREAM = 500;
|
|
62
|
-
/** How long a silent stream is kept before Redis reclaims it. */
|
|
63
|
-
export const EVENT_STREAM_TTL_MS = 3_600_000;
|
|
64
|
-
/** Cap on one inbound batch, matching the SABS publish bound. */
|
|
65
|
-
export const MAX_EVENTS_PER_REQUEST = 64;
|
|
66
|
-
//# sourceMappingURL=types.js.map
|
package/dist/events/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/events/types.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAEpC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAEpD,iDAAiD;AACjD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,eAAe;IACf,cAAc;IACd,kBAAkB;IAClB,UAAU;IACV,SAAS;CACD,CAAC;AAGX;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,MAAM,CAAU,CAAC;AAG/D,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,qBAAqB;IACrB,WAAW;IACX,WAAW;IACX,WAAW;IACX,YAAY;IACZ,MAAM;IACN,aAAa;CACL,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,WAAW,EAAE,MAAM,CAAU,CAAC;AAEzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,YAAY,CAAU,CAAC;AAkFnE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAiDtC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC,iEAAiE;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAE7C,iEAAiE;AACjE,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC"}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { type AppScopeKey, type ProgressCursorKey, type ProgressCursorRecord, type ProgressStore } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Cap on how many cursors and pointers a single process will hold.
|
|
4
|
-
*
|
|
5
|
-
* Redis expires keys on its own; a plain Map does not, and a gateway that ran
|
|
6
|
-
* for a week would hold one entry per (caller, application) it had ever
|
|
7
|
-
* served. Insertion order is iteration order for a Map, so the oldest write
|
|
8
|
-
* is the one dropped — a caller evicted this way re-reads the retained
|
|
9
|
-
* history rather than losing anything, which is the same outcome as its
|
|
10
|
-
* cursor having expired.
|
|
11
|
-
*/
|
|
12
|
-
export declare const MAX_MEMORY_PROGRESS_ENTRIES = 2048;
|
|
13
|
-
/**
|
|
14
|
-
* Local-only fallback, matching the other in-memory stores.
|
|
15
|
-
*
|
|
16
|
-
* Not a second source of truth: two replicas with private maps would hand the
|
|
17
|
-
* same caller two different positions in the same stream, which is exactly
|
|
18
|
-
* the divergence Redis is required outside local to prevent.
|
|
19
|
-
*/
|
|
20
|
-
export declare class MemoryProgressStore implements ProgressStore {
|
|
21
|
-
private readonly cursors;
|
|
22
|
-
private readonly lastActivity;
|
|
23
|
-
private readonly liveEdits;
|
|
24
|
-
getCursor(key: ProgressCursorKey): Promise<ProgressCursorRecord | undefined>;
|
|
25
|
-
getLastActivityAtMs(key: AppScopeKey): Promise<number | undefined>;
|
|
26
|
-
getLiveEditId(key: AppScopeKey): Promise<string | undefined>;
|
|
27
|
-
setCursor(input: ProgressCursorKey & {
|
|
28
|
-
record: ProgressCursorRecord;
|
|
29
|
-
ttlMs?: number;
|
|
30
|
-
}): Promise<void>;
|
|
31
|
-
setLastActivityAtMs(input: AppScopeKey & {
|
|
32
|
-
atMs: number;
|
|
33
|
-
ttlMs?: number;
|
|
34
|
-
}): Promise<void>;
|
|
35
|
-
setLiveEditId(input: AppScopeKey & {
|
|
36
|
-
liveEditId: string;
|
|
37
|
-
ttlMs?: number;
|
|
38
|
-
}): Promise<void>;
|
|
39
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { cursorKey, lastActivityKey, liveEditKey } from "./progress-key.js";
|
|
2
|
-
import { DEFAULT_LIVE_EDIT_POINTER_TTL_MS, DEFAULT_PROGRESS_CURSOR_TTL_MS, } from "./types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Cap on how many cursors and pointers a single process will hold.
|
|
5
|
-
*
|
|
6
|
-
* Redis expires keys on its own; a plain Map does not, and a gateway that ran
|
|
7
|
-
* for a week would hold one entry per (caller, application) it had ever
|
|
8
|
-
* served. Insertion order is iteration order for a Map, so the oldest write
|
|
9
|
-
* is the one dropped — a caller evicted this way re-reads the retained
|
|
10
|
-
* history rather than losing anything, which is the same outcome as its
|
|
11
|
-
* cursor having expired.
|
|
12
|
-
*/
|
|
13
|
-
export const MAX_MEMORY_PROGRESS_ENTRIES = 2_048;
|
|
14
|
-
/**
|
|
15
|
-
* Local-only fallback, matching the other in-memory stores.
|
|
16
|
-
*
|
|
17
|
-
* Not a second source of truth: two replicas with private maps would hand the
|
|
18
|
-
* same caller two different positions in the same stream, which is exactly
|
|
19
|
-
* the divergence Redis is required outside local to prevent.
|
|
20
|
-
*/
|
|
21
|
-
export class MemoryProgressStore {
|
|
22
|
-
cursors = new Map();
|
|
23
|
-
lastActivity = new Map();
|
|
24
|
-
liveEdits = new Map();
|
|
25
|
-
async getCursor(key) {
|
|
26
|
-
return read(this.cursors, cursorKey(key));
|
|
27
|
-
}
|
|
28
|
-
async getLastActivityAtMs(key) {
|
|
29
|
-
return read(this.lastActivity, lastActivityKey(key));
|
|
30
|
-
}
|
|
31
|
-
async getLiveEditId(key) {
|
|
32
|
-
return read(this.liveEdits, liveEditKey(key));
|
|
33
|
-
}
|
|
34
|
-
async setCursor(input) {
|
|
35
|
-
write(this.cursors, cursorKey(input), input.record, {
|
|
36
|
-
ttlMs: input.ttlMs ?? DEFAULT_PROGRESS_CURSOR_TTL_MS,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
async setLastActivityAtMs(input) {
|
|
40
|
-
// Same retention as a cursor: past that, there is no history left to
|
|
41
|
-
// measure a quiet spell against anyway.
|
|
42
|
-
write(this.lastActivity, lastActivityKey(input), input.atMs, {
|
|
43
|
-
ttlMs: input.ttlMs ?? DEFAULT_PROGRESS_CURSOR_TTL_MS,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
async setLiveEditId(input) {
|
|
47
|
-
write(this.liveEdits, liveEditKey(input), input.liveEditId, {
|
|
48
|
-
ttlMs: input.ttlMs ?? DEFAULT_LIVE_EDIT_POINTER_TTL_MS,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
function read(entries, key) {
|
|
53
|
-
const entry = entries.get(key);
|
|
54
|
-
if (!entry) {
|
|
55
|
-
return undefined;
|
|
56
|
-
}
|
|
57
|
-
if (entry.expiresAtMs <= Date.now()) {
|
|
58
|
-
entries.delete(key);
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
return entry.value;
|
|
62
|
-
}
|
|
63
|
-
function write(entries, key, value, options) {
|
|
64
|
-
const now = Date.now();
|
|
65
|
-
for (const [candidate, entry] of entries) {
|
|
66
|
-
if (entry.expiresAtMs <= now) {
|
|
67
|
-
entries.delete(candidate);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// Re-inserting moves the key to the end, so a cursor being written is never
|
|
71
|
-
// the next one evicted.
|
|
72
|
-
entries.delete(key);
|
|
73
|
-
entries.set(key, { expiresAtMs: now + options.ttlMs, value });
|
|
74
|
-
while (entries.size > MAX_MEMORY_PROGRESS_ENTRIES) {
|
|
75
|
-
const oldest = entries.keys().next();
|
|
76
|
-
if (oldest.done) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
entries.delete(oldest.value);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
//# sourceMappingURL=memory-progress-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"memory-progress-store.js","sourceRoot":"","sources":["../../src/resume/memory-progress-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type RecentApp, type RecentAppStore } from "./types.js";
|
|
2
|
-
export declare class MemoryRecentAppStore implements RecentAppStore {
|
|
3
|
-
private readonly byPrincipal;
|
|
4
|
-
get(input: {
|
|
5
|
-
organizationId: string;
|
|
6
|
-
userId: string;
|
|
7
|
-
}): Promise<RecentApp | undefined>;
|
|
8
|
-
set(input: {
|
|
9
|
-
applicationId: string;
|
|
10
|
-
organizationId: string;
|
|
11
|
-
ttlMs?: number;
|
|
12
|
-
userId: string;
|
|
13
|
-
}): Promise<void>;
|
|
14
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_RECENT_APP_TTL_MS, } from "./types.js";
|
|
2
|
-
function principalKey(organizationId, userId) {
|
|
3
|
-
return `${organizationId}:${userId}`;
|
|
4
|
-
}
|
|
5
|
-
export class MemoryRecentAppStore {
|
|
6
|
-
byPrincipal = new Map();
|
|
7
|
-
async get(input) {
|
|
8
|
-
const key = principalKey(input.organizationId, input.userId);
|
|
9
|
-
const entry = this.byPrincipal.get(key);
|
|
10
|
-
if (!entry) {
|
|
11
|
-
return undefined;
|
|
12
|
-
}
|
|
13
|
-
if (entry.expiresAtMs <= Date.now()) {
|
|
14
|
-
this.byPrincipal.delete(key);
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
return { applicationId: entry.applicationId };
|
|
18
|
-
}
|
|
19
|
-
async set(input) {
|
|
20
|
-
const ttlMs = input.ttlMs ?? DEFAULT_RECENT_APP_TTL_MS;
|
|
21
|
-
this.byPrincipal.set(principalKey(input.organizationId, input.userId), {
|
|
22
|
-
applicationId: input.applicationId,
|
|
23
|
-
expiresAtMs: Date.now() + ttlMs,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=memory-recent-app-store.js.map
|