@agimon-ai/doompi-extension-contracts 0.0.1-alpha.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/LICENSE +21 -0
- package/README.md +34 -0
- package/dist/backgroundWork.cjs +2 -0
- package/dist/backgroundWork.cjs.map +1 -0
- package/dist/backgroundWork.d.cts +73 -0
- package/dist/backgroundWork.d.cts.map +1 -0
- package/dist/backgroundWork.d.mts +73 -0
- package/dist/backgroundWork.d.mts.map +1 -0
- package/dist/backgroundWork.mjs +2 -0
- package/dist/backgroundWork.mjs.map +1 -0
- package/dist/childProcess.cjs +2 -0
- package/dist/childProcess.cjs.map +1 -0
- package/dist/childProcess.d.cts +20 -0
- package/dist/childProcess.d.cts.map +1 -0
- package/dist/childProcess.d.mts +20 -0
- package/dist/childProcess.d.mts.map +1 -0
- package/dist/childProcess.mjs +2 -0
- package/dist/childProcess.mjs.map +1 -0
- package/dist/config.cjs +2 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +517 -0
- package/dist/config.d.cts.map +1 -0
- package/dist/config.d.mts +517 -0
- package/dist/config.d.mts.map +1 -0
- package/dist/config.mjs +2 -0
- package/dist/config.mjs.map +1 -0
- package/dist/delegation.cjs +2 -0
- package/dist/delegation.cjs.map +1 -0
- package/dist/delegation.d.cts +114 -0
- package/dist/delegation.d.cts.map +1 -0
- package/dist/delegation.d.mts +114 -0
- package/dist/delegation.d.mts.map +1 -0
- package/dist/delegation.mjs +2 -0
- package/dist/delegation.mjs.map +1 -0
- package/dist/fablePlan.cjs +2 -0
- package/dist/fablePlan.cjs.map +1 -0
- package/dist/fablePlan.d.cts +143 -0
- package/dist/fablePlan.d.cts.map +1 -0
- package/dist/fablePlan.d.mts +143 -0
- package/dist/fablePlan.d.mts.map +1 -0
- package/dist/fablePlan.mjs +2 -0
- package/dist/fablePlan.mjs.map +1 -0
- package/dist/footer.cjs +2 -0
- package/dist/footer.cjs.map +1 -0
- package/dist/footer.d.cts +141 -0
- package/dist/footer.d.cts.map +1 -0
- package/dist/footer.d.mts +141 -0
- package/dist/footer.d.mts.map +1 -0
- package/dist/footer.mjs +2 -0
- package/dist/footer.mjs.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1 -0
- package/dist/leader.cjs +2 -0
- package/dist/leader.cjs.map +1 -0
- package/dist/leader.d.cts +171 -0
- package/dist/leader.d.cts.map +1 -0
- package/dist/leader.d.mts +171 -0
- package/dist/leader.d.mts.map +1 -0
- package/dist/leader.mjs +2 -0
- package/dist/leader.mjs.map +1 -0
- package/dist/mcpStatus.cjs +2 -0
- package/dist/mcpStatus.cjs.map +1 -0
- package/dist/mcpStatus.d.cts +79 -0
- package/dist/mcpStatus.d.cts.map +1 -0
- package/dist/mcpStatus.d.mts +79 -0
- package/dist/mcpStatus.d.mts.map +1 -0
- package/dist/mcpStatus.mjs +2 -0
- package/dist/mcpStatus.mjs.map +1 -0
- package/dist/mode.cjs +2 -0
- package/dist/mode.cjs.map +1 -0
- package/dist/mode.d.cts +132 -0
- package/dist/mode.d.cts.map +1 -0
- package/dist/mode.d.mts +132 -0
- package/dist/mode.d.mts.map +1 -0
- package/dist/mode.mjs +2 -0
- package/dist/mode.mjs.map +1 -0
- package/dist/protocol.cjs +2 -0
- package/dist/protocol.cjs.map +1 -0
- package/dist/protocol.d.cts +83 -0
- package/dist/protocol.d.cts.map +1 -0
- package/dist/protocol.d.mts +83 -0
- package/dist/protocol.d.mts.map +1 -0
- package/dist/protocol.mjs +2 -0
- package/dist/protocol.mjs.map +1 -0
- package/dist/runnerPty.cjs +2 -0
- package/dist/runnerPty.cjs.map +1 -0
- package/dist/runnerPty.d.cts +39 -0
- package/dist/runnerPty.d.cts.map +1 -0
- package/dist/runnerPty.d.mts +39 -0
- package/dist/runnerPty.d.mts.map +1 -0
- package/dist/runnerPty.mjs +2 -0
- package/dist/runnerPty.mjs.map +1 -0
- package/dist/skills.cjs +2 -0
- package/dist/skills.cjs.map +1 -0
- package/dist/skills.d.cts +51 -0
- package/dist/skills.d.cts.map +1 -0
- package/dist/skills.d.mts +51 -0
- package/dist/skills.d.mts.map +1 -0
- package/dist/skills.mjs +2 -0
- package/dist/skills.mjs.map +1 -0
- package/dist/subagentPolicy.cjs +2 -0
- package/dist/subagentPolicy.cjs.map +1 -0
- package/dist/subagentPolicy.d.cts +47 -0
- package/dist/subagentPolicy.d.cts.map +1 -0
- package/dist/subagentPolicy.d.mts +47 -0
- package/dist/subagentPolicy.d.mts.map +1 -0
- package/dist/subagentPolicy.mjs +2 -0
- package/dist/subagentPolicy.mjs.map +1 -0
- package/dist/subagentTool.cjs +2 -0
- package/dist/subagentTool.cjs.map +1 -0
- package/dist/subagentTool.d.cts +78 -0
- package/dist/subagentTool.d.cts.map +1 -0
- package/dist/subagentTool.d.mts +78 -0
- package/dist/subagentTool.d.mts.map +1 -0
- package/dist/subagentTool.mjs +2 -0
- package/dist/subagentTool.mjs.map +1 -0
- package/dist/workflow.cjs +2 -0
- package/dist/workflow.cjs.map +1 -0
- package/dist/workflow.d.cts +15 -0
- package/dist/workflow.d.cts.map +1 -0
- package/dist/workflow.d.mts +15 -0
- package/dist/workflow.d.mts.map +1 -0
- package/dist/workflow.mjs +2 -0
- package/dist/workflow.mjs.map +1 -0
- package/package.json +121 -0
package/dist/mode.d.cts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { NotificationDefinition, ProtocolRuntime } from "./protocol.cjs";
|
|
2
|
+
import { DoomExtensionHost } from "./config.cjs";
|
|
3
|
+
import { Static, Type } from "typebox";
|
|
4
|
+
//#region src/mode.d.ts
|
|
5
|
+
declare const ModeTextColorSchema: Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>;
|
|
6
|
+
type ModeTextColor = Static<typeof ModeTextColorSchema>;
|
|
7
|
+
declare const ModeStatusItemSchema: Type.TObject<{
|
|
8
|
+
id: Type.TString;
|
|
9
|
+
/**
|
|
10
|
+
* The mode's name, and nothing else.
|
|
11
|
+
*
|
|
12
|
+
* Short because the line holds every enabled mode at once: `WORKFLOW`, not
|
|
13
|
+
* `WORKFLOW MODE · ON`. That a label is present at all is what says the mode
|
|
14
|
+
* is on, so an `ON` suffix spends a word restating the line's premise.
|
|
15
|
+
*/
|
|
16
|
+
label: Type.TString;
|
|
17
|
+
/** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */
|
|
18
|
+
detail: Type.TOptional<Type.TString>;
|
|
19
|
+
color: Type.TOptional<Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>>;
|
|
20
|
+
order: Type.TInteger;
|
|
21
|
+
}>;
|
|
22
|
+
type ModeStatusItem = Static<typeof ModeStatusItemSchema>;
|
|
23
|
+
declare const ModeStatusSourceSchema: Type.TObject<{
|
|
24
|
+
source: Type.TString;
|
|
25
|
+
generation: Type.TString;
|
|
26
|
+
}>;
|
|
27
|
+
declare const ModeStatusSnapshotSchema: Type.TObject<{
|
|
28
|
+
items: Type.TArray<Type.TObject<{
|
|
29
|
+
id: Type.TString;
|
|
30
|
+
/**
|
|
31
|
+
* The mode's name, and nothing else.
|
|
32
|
+
*
|
|
33
|
+
* Short because the line holds every enabled mode at once: `WORKFLOW`, not
|
|
34
|
+
* `WORKFLOW MODE · ON`. That a label is present at all is what says the mode
|
|
35
|
+
* is on, so an `ON` suffix spends a word restating the line's premise.
|
|
36
|
+
*/
|
|
37
|
+
label: Type.TString;
|
|
38
|
+
/** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */
|
|
39
|
+
detail: Type.TOptional<Type.TString>;
|
|
40
|
+
color: Type.TOptional<Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>>;
|
|
41
|
+
order: Type.TInteger;
|
|
42
|
+
}>>;
|
|
43
|
+
source: Type.TString;
|
|
44
|
+
generation: Type.TString;
|
|
45
|
+
}>;
|
|
46
|
+
type ModeStatusSnapshot = Static<typeof ModeStatusSnapshotSchema>;
|
|
47
|
+
type ModeStatusSource = Static<typeof ModeStatusSourceSchema>;
|
|
48
|
+
declare const ModeStatusDiscovery: NotificationDefinition<Type.TObject<{}>>;
|
|
49
|
+
declare const ModeStatusRegistration: NotificationDefinition<Type.TObject<{
|
|
50
|
+
items: Type.TArray<Type.TObject<{
|
|
51
|
+
id: Type.TString;
|
|
52
|
+
/**
|
|
53
|
+
* The mode's name, and nothing else.
|
|
54
|
+
*
|
|
55
|
+
* Short because the line holds every enabled mode at once: `WORKFLOW`, not
|
|
56
|
+
* `WORKFLOW MODE · ON`. That a label is present at all is what says the mode
|
|
57
|
+
* is on, so an `ON` suffix spends a word restating the line's premise.
|
|
58
|
+
*/
|
|
59
|
+
label: Type.TString;
|
|
60
|
+
/** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */
|
|
61
|
+
detail: Type.TOptional<Type.TString>;
|
|
62
|
+
color: Type.TOptional<Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>>;
|
|
63
|
+
order: Type.TInteger;
|
|
64
|
+
}>>;
|
|
65
|
+
source: Type.TString;
|
|
66
|
+
generation: Type.TString;
|
|
67
|
+
}>>;
|
|
68
|
+
declare const ModeStatusChanged: NotificationDefinition<Type.TObject<{
|
|
69
|
+
items: Type.TArray<Type.TObject<{
|
|
70
|
+
id: Type.TString;
|
|
71
|
+
/**
|
|
72
|
+
* The mode's name, and nothing else.
|
|
73
|
+
*
|
|
74
|
+
* Short because the line holds every enabled mode at once: `WORKFLOW`, not
|
|
75
|
+
* `WORKFLOW MODE · ON`. That a label is present at all is what says the mode
|
|
76
|
+
* is on, so an `ON` suffix spends a word restating the line's premise.
|
|
77
|
+
*/
|
|
78
|
+
label: Type.TString;
|
|
79
|
+
/** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */
|
|
80
|
+
detail: Type.TOptional<Type.TString>;
|
|
81
|
+
color: Type.TOptional<Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>>;
|
|
82
|
+
order: Type.TInteger;
|
|
83
|
+
}>>;
|
|
84
|
+
source: Type.TString;
|
|
85
|
+
generation: Type.TString;
|
|
86
|
+
}>>;
|
|
87
|
+
declare const ModeStatusUnregistration: NotificationDefinition<Type.TObject<{
|
|
88
|
+
source: Type.TString;
|
|
89
|
+
generation: Type.TString;
|
|
90
|
+
}>>;
|
|
91
|
+
interface ModeStatusProvider {
|
|
92
|
+
source: string;
|
|
93
|
+
listStatuses(): readonly ModeStatusItem[];
|
|
94
|
+
}
|
|
95
|
+
interface ModeStatusProviderHandle {
|
|
96
|
+
update(): void;
|
|
97
|
+
dispose(): void;
|
|
98
|
+
}
|
|
99
|
+
declare function registerModeStatusProvider(runtime: ProtocolRuntime, provider: ModeStatusProvider): ModeStatusProviderHandle;
|
|
100
|
+
interface DoomModeContributionDefinition {
|
|
101
|
+
source: string;
|
|
102
|
+
id: string;
|
|
103
|
+
order: number;
|
|
104
|
+
}
|
|
105
|
+
interface DoomModeContributionValue {
|
|
106
|
+
label: string;
|
|
107
|
+
detail?: string;
|
|
108
|
+
color?: ModeTextColor;
|
|
109
|
+
}
|
|
110
|
+
interface DoomModeContributionHandle {
|
|
111
|
+
update(value: DoomModeContributionValue | undefined): void;
|
|
112
|
+
dispose(): void;
|
|
113
|
+
}
|
|
114
|
+
interface DoomModeStatus extends ModeStatusItem {
|
|
115
|
+
source: string;
|
|
116
|
+
}
|
|
117
|
+
declare class DoomModeStatusRegistry {
|
|
118
|
+
private readonly sources;
|
|
119
|
+
private readonly listeners;
|
|
120
|
+
bind(runtime: ProtocolRuntime): () => void;
|
|
121
|
+
getStatuses(): DoomModeStatus[];
|
|
122
|
+
subscribe(listener: () => void): () => void;
|
|
123
|
+
reset(): void;
|
|
124
|
+
private register;
|
|
125
|
+
private update;
|
|
126
|
+
private unregister;
|
|
127
|
+
private notify;
|
|
128
|
+
}
|
|
129
|
+
declare function registerDoomModeContribution(pi: DoomExtensionHost, definition: DoomModeContributionDefinition): DoomModeContributionHandle;
|
|
130
|
+
//#endregion
|
|
131
|
+
export { DoomModeContributionDefinition, DoomModeContributionHandle, DoomModeContributionValue, DoomModeStatus, DoomModeStatusRegistry, ModeStatusChanged, ModeStatusDiscovery, ModeStatusItem, ModeStatusItemSchema, ModeStatusProvider, ModeStatusProviderHandle, ModeStatusRegistration, ModeStatusSnapshot, ModeStatusSource, ModeStatusUnregistration, ModeTextColor, ModeTextColorSchema, registerDoomModeContribution, registerModeStatusProvider };
|
|
132
|
+
//# sourceMappingURL=mode.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.d.cts","names":[],"sources":["../src/mode.ts"],"mappings":";;;;cAgBa,qBAAmB,KAAA,QAAA,KAAA,oBAAA,KAAA,qBAAA,KAAA,uBAAA,KAAA,mBAAA,KAAA;KAOpB,gBAAgB,cAAc;cAE7B,sBAAoB,KAAA;;;;;;;;;;;;;;;KAkBrB,iBAAiB,cAAc;cAErC,wBAAsB,KAAA;;;;cAQtB,0BAAwB,KAAA;;;;;;;;;;;;;;;;;;;KAOlB,qBAAqB,cAAc;KACnC,mBAAmB,cAAc;cAEhC,qBAAmB,uBAAA,KAAA;cAMnB,wBAAsB,uBAAA,KAAA;;;;;;;;;;;;;;;;;;;cAMtB,mBAAiB,uBAAA,KAAA;;;;;;;;;;;;;;;;;;;cAMjB,0BAAwB,uBAAA,KAAA;;;;UAMpB;EACf;EACA,yBAAyB;;UAGV;EACf;EACA;;iBAGc,2BACd,SAAS,iBACT,UAAU,qBACT;UAgCc;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA,QAAQ;;UAGO;EACf,OAAO,OAAO;EACd;;UAGe,uBAAuB;EACtC;;cAQW;mBACM;mBACA;EAEjB,KAAK,SAAS;EAed,eAAe;EASf,UAAU;EAKV;UAMQ;UAQA;UASA;UAMA;;iBAKM,6BACd,IAAI,mBACJ,YAAY,iCACX"}
|
package/dist/mode.d.mts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { NotificationDefinition, ProtocolRuntime } from "./protocol.mjs";
|
|
2
|
+
import { DoomExtensionHost } from "./config.mjs";
|
|
3
|
+
import { Static, Type } from "typebox";
|
|
4
|
+
//#region src/mode.d.ts
|
|
5
|
+
declare const ModeTextColorSchema: Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>;
|
|
6
|
+
type ModeTextColor = Static<typeof ModeTextColorSchema>;
|
|
7
|
+
declare const ModeStatusItemSchema: Type.TObject<{
|
|
8
|
+
id: Type.TString;
|
|
9
|
+
/**
|
|
10
|
+
* The mode's name, and nothing else.
|
|
11
|
+
*
|
|
12
|
+
* Short because the line holds every enabled mode at once: `WORKFLOW`, not
|
|
13
|
+
* `WORKFLOW MODE · ON`. That a label is present at all is what says the mode
|
|
14
|
+
* is on, so an `ON` suffix spends a word restating the line's premise.
|
|
15
|
+
*/
|
|
16
|
+
label: Type.TString;
|
|
17
|
+
/** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */
|
|
18
|
+
detail: Type.TOptional<Type.TString>;
|
|
19
|
+
color: Type.TOptional<Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>>;
|
|
20
|
+
order: Type.TInteger;
|
|
21
|
+
}>;
|
|
22
|
+
type ModeStatusItem = Static<typeof ModeStatusItemSchema>;
|
|
23
|
+
declare const ModeStatusSourceSchema: Type.TObject<{
|
|
24
|
+
source: Type.TString;
|
|
25
|
+
generation: Type.TString;
|
|
26
|
+
}>;
|
|
27
|
+
declare const ModeStatusSnapshotSchema: Type.TObject<{
|
|
28
|
+
items: Type.TArray<Type.TObject<{
|
|
29
|
+
id: Type.TString;
|
|
30
|
+
/**
|
|
31
|
+
* The mode's name, and nothing else.
|
|
32
|
+
*
|
|
33
|
+
* Short because the line holds every enabled mode at once: `WORKFLOW`, not
|
|
34
|
+
* `WORKFLOW MODE · ON`. That a label is present at all is what says the mode
|
|
35
|
+
* is on, so an `ON` suffix spends a word restating the line's premise.
|
|
36
|
+
*/
|
|
37
|
+
label: Type.TString;
|
|
38
|
+
/** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */
|
|
39
|
+
detail: Type.TOptional<Type.TString>;
|
|
40
|
+
color: Type.TOptional<Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>>;
|
|
41
|
+
order: Type.TInteger;
|
|
42
|
+
}>>;
|
|
43
|
+
source: Type.TString;
|
|
44
|
+
generation: Type.TString;
|
|
45
|
+
}>;
|
|
46
|
+
type ModeStatusSnapshot = Static<typeof ModeStatusSnapshotSchema>;
|
|
47
|
+
type ModeStatusSource = Static<typeof ModeStatusSourceSchema>;
|
|
48
|
+
declare const ModeStatusDiscovery: NotificationDefinition<Type.TObject<{}>>;
|
|
49
|
+
declare const ModeStatusRegistration: NotificationDefinition<Type.TObject<{
|
|
50
|
+
items: Type.TArray<Type.TObject<{
|
|
51
|
+
id: Type.TString;
|
|
52
|
+
/**
|
|
53
|
+
* The mode's name, and nothing else.
|
|
54
|
+
*
|
|
55
|
+
* Short because the line holds every enabled mode at once: `WORKFLOW`, not
|
|
56
|
+
* `WORKFLOW MODE · ON`. That a label is present at all is what says the mode
|
|
57
|
+
* is on, so an `ON` suffix spends a word restating the line's premise.
|
|
58
|
+
*/
|
|
59
|
+
label: Type.TString;
|
|
60
|
+
/** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */
|
|
61
|
+
detail: Type.TOptional<Type.TString>;
|
|
62
|
+
color: Type.TOptional<Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>>;
|
|
63
|
+
order: Type.TInteger;
|
|
64
|
+
}>>;
|
|
65
|
+
source: Type.TString;
|
|
66
|
+
generation: Type.TString;
|
|
67
|
+
}>>;
|
|
68
|
+
declare const ModeStatusChanged: NotificationDefinition<Type.TObject<{
|
|
69
|
+
items: Type.TArray<Type.TObject<{
|
|
70
|
+
id: Type.TString;
|
|
71
|
+
/**
|
|
72
|
+
* The mode's name, and nothing else.
|
|
73
|
+
*
|
|
74
|
+
* Short because the line holds every enabled mode at once: `WORKFLOW`, not
|
|
75
|
+
* `WORKFLOW MODE · ON`. That a label is present at all is what says the mode
|
|
76
|
+
* is on, so an `ON` suffix spends a word restating the line's premise.
|
|
77
|
+
*/
|
|
78
|
+
label: Type.TString;
|
|
79
|
+
/** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */
|
|
80
|
+
detail: Type.TOptional<Type.TString>;
|
|
81
|
+
color: Type.TOptional<Type.TUnion<[Type.TLiteral<"accent">, Type.TLiteral<"warning">, Type.TLiteral<"mdHeading">, Type.TLiteral<"muted">, Type.TLiteral<"dim">]>>;
|
|
82
|
+
order: Type.TInteger;
|
|
83
|
+
}>>;
|
|
84
|
+
source: Type.TString;
|
|
85
|
+
generation: Type.TString;
|
|
86
|
+
}>>;
|
|
87
|
+
declare const ModeStatusUnregistration: NotificationDefinition<Type.TObject<{
|
|
88
|
+
source: Type.TString;
|
|
89
|
+
generation: Type.TString;
|
|
90
|
+
}>>;
|
|
91
|
+
interface ModeStatusProvider {
|
|
92
|
+
source: string;
|
|
93
|
+
listStatuses(): readonly ModeStatusItem[];
|
|
94
|
+
}
|
|
95
|
+
interface ModeStatusProviderHandle {
|
|
96
|
+
update(): void;
|
|
97
|
+
dispose(): void;
|
|
98
|
+
}
|
|
99
|
+
declare function registerModeStatusProvider(runtime: ProtocolRuntime, provider: ModeStatusProvider): ModeStatusProviderHandle;
|
|
100
|
+
interface DoomModeContributionDefinition {
|
|
101
|
+
source: string;
|
|
102
|
+
id: string;
|
|
103
|
+
order: number;
|
|
104
|
+
}
|
|
105
|
+
interface DoomModeContributionValue {
|
|
106
|
+
label: string;
|
|
107
|
+
detail?: string;
|
|
108
|
+
color?: ModeTextColor;
|
|
109
|
+
}
|
|
110
|
+
interface DoomModeContributionHandle {
|
|
111
|
+
update(value: DoomModeContributionValue | undefined): void;
|
|
112
|
+
dispose(): void;
|
|
113
|
+
}
|
|
114
|
+
interface DoomModeStatus extends ModeStatusItem {
|
|
115
|
+
source: string;
|
|
116
|
+
}
|
|
117
|
+
declare class DoomModeStatusRegistry {
|
|
118
|
+
private readonly sources;
|
|
119
|
+
private readonly listeners;
|
|
120
|
+
bind(runtime: ProtocolRuntime): () => void;
|
|
121
|
+
getStatuses(): DoomModeStatus[];
|
|
122
|
+
subscribe(listener: () => void): () => void;
|
|
123
|
+
reset(): void;
|
|
124
|
+
private register;
|
|
125
|
+
private update;
|
|
126
|
+
private unregister;
|
|
127
|
+
private notify;
|
|
128
|
+
}
|
|
129
|
+
declare function registerDoomModeContribution(pi: DoomExtensionHost, definition: DoomModeContributionDefinition): DoomModeContributionHandle;
|
|
130
|
+
//#endregion
|
|
131
|
+
export { DoomModeContributionDefinition, DoomModeContributionHandle, DoomModeContributionValue, DoomModeStatus, DoomModeStatusRegistry, ModeStatusChanged, ModeStatusDiscovery, ModeStatusItem, ModeStatusItemSchema, ModeStatusProvider, ModeStatusProviderHandle, ModeStatusRegistration, ModeStatusSnapshot, ModeStatusSource, ModeStatusUnregistration, ModeTextColor, ModeTextColorSchema, registerDoomModeContribution, registerModeStatusProvider };
|
|
132
|
+
//# sourceMappingURL=mode.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.d.mts","names":[],"sources":["../src/mode.ts"],"mappings":";;;;cAgBa,qBAAmB,KAAA,QAAA,KAAA,oBAAA,KAAA,qBAAA,KAAA,uBAAA,KAAA,mBAAA,KAAA;KAOpB,gBAAgB,cAAc;cAE7B,sBAAoB,KAAA;;;;;;;;;;;;;;;KAkBrB,iBAAiB,cAAc;cAErC,wBAAsB,KAAA;;;;cAQtB,0BAAwB,KAAA;;;;;;;;;;;;;;;;;;;KAOlB,qBAAqB,cAAc;KACnC,mBAAmB,cAAc;cAEhC,qBAAmB,uBAAA,KAAA;cAMnB,wBAAsB,uBAAA,KAAA;;;;;;;;;;;;;;;;;;;cAMtB,mBAAiB,uBAAA,KAAA;;;;;;;;;;;;;;;;;;;cAMjB,0BAAwB,uBAAA,KAAA;;;;UAMpB;EACf;EACA,yBAAyB;;UAGV;EACf;EACA;;iBAGc,2BACd,SAAS,iBACT,UAAU,qBACT;UAgCc;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA,QAAQ;;UAGO;EACf,OAAO,OAAO;EACd;;UAGe,uBAAuB;EACtC;;cAQW;mBACM;mBACA;EAEjB,KAAK,SAAS;EAed,eAAe;EASf,UAAU;EAKV;UAMQ;UAQA;UASA;UAMA;;iBAKM,6BACd,IAAI,mBACJ,YAAY,iCACX"}
|
package/dist/mode.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createProtocolRuntime as e,defineNotification as t}from"./protocol.mjs";import{Type as n}from"typebox";const r=n.Union([n.Literal(`accent`),n.Literal(`warning`),n.Literal(`mdHeading`),n.Literal(`muted`),n.Literal(`dim`)]),i=n.Object({id:n.String({minLength:1,maxLength:128}),label:n.String({minLength:1,maxLength:24}),detail:n.Optional(n.String({minLength:1,maxLength:48})),color:n.Optional(r),order:n.Integer({minimum:0,maximum:1e3})},{additionalProperties:!1}),a=n.Object({source:n.String({minLength:1,maxLength:128}),generation:n.String({minLength:1})},{additionalProperties:!1}),o=n.Object({...a.properties,items:n.Array(i)},{additionalProperties:!1}),s=t({channel:`doom:ui:mode:v1:discover`,kind:`mode-status.discover`,payload:n.Object({},{additionalProperties:!1})}),c=t({channel:`doom:ui:mode:v1:register`,kind:`mode-status.register`,payload:o}),l=t({channel:`doom:ui:mode:v1:changed`,kind:`mode-status.changed`,payload:o}),u=t({channel:`doom:ui:mode:v1:unregister`,kind:`mode-status.unregister`,payload:a});function d(e,t){let n=`${t.source}:${crypto.randomUUID()}`,r=!1,i=()=>({source:t.source,generation:n,items:t.listStatuses().map(e=>({...e}))}),a=()=>{r||e.notify(c,i())},o=e.onNotification(s,a);return a(),{update(){r||e.notify(l,i())},dispose(){r||(r=!0,o(),e.notify(u,{source:t.source,generation:n}))}}}var f=class{sources=new Map;listeners=new Set;bind(e){let t=[e.onNotification(c,e=>this.register(e)),e.onNotification(l,e=>this.update(e)),e.onNotification(u,e=>this.unregister(e))];e.notify(s,{});let n=!1;return()=>{if(!n){n=!0;for(let e of t)e()}}}getStatuses(){return[...this.sources.entries()].flatMap(([e,t])=>t.items.map(t=>({source:e,...t}))).toSorted((e,t)=>e.order-t.order||e.source.localeCompare(t.source)||e.id.localeCompare(t.id))}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}reset(){this.sources.size!==0&&(this.sources.clear(),this.notify())}register(e){this.sources.set(e.source,{generation:e.generation,items:e.items.map(e=>({...e}))}),this.notify()}update(e){this.sources.get(e.source)?.generation===e.generation&&(this.sources.set(e.source,{generation:e.generation,items:e.items.map(e=>({...e}))}),this.notify())}unregister(e){this.sources.get(e.source)?.generation===e.generation&&(this.sources.delete(e.source),this.notify())}notify(){for(let e of this.listeners)e()}};function p(t,n){let r,i,a=!1,o=()=>{i?.dispose(),i=void 0};return t.on(`session_start`,(s,c)=>{a||(o(),i=d(e({bus:t.events,source:n.source,sessionId:c.sessionManager.getSessionId()}),{source:n.source,listStatuses:()=>r?[{id:n.id,label:r.label,...r.detail?{detail:r.detail}:{},...r.color?{color:r.color}:{},order:n.order}]:[]}))}),t.on(`session_shutdown`,o),{update(e){a||(r=e?{...e}:void 0,i?.update())},dispose(){a||(a=!0,r=void 0,o())}}}export{f as DoomModeStatusRegistry,l as ModeStatusChanged,s as ModeStatusDiscovery,i as ModeStatusItemSchema,c as ModeStatusRegistration,u as ModeStatusUnregistration,r as ModeTextColorSchema,p as registerDoomModeContribution,d as registerModeStatusProvider};
|
|
2
|
+
//# sourceMappingURL=mode.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.mjs","names":[],"sources":["../src/mode.ts"],"sourcesContent":["/**\n * Mode banners, contributed by every extension that owns one.\n *\n * Each mode used to paint its own below-editor widget under its own key, which\n * Pi renders on a row of its own: three modes on meant three stacked rows,\n * growing with every mode added. Publishing a label instead lets one renderer\n * put them all on a single wrapped line.\n *\n * Deliberately the same shape as the footer contract next door, since the\n * problem is the same one: several extensions sharing one strip of screen.\n */\n\nimport { type Static, Type } from 'typebox';\nimport type { DoomExtensionHost } from './config.ts';\nimport { createProtocolRuntime, defineNotification, type ProtocolRuntime } from './protocol.ts';\n\nexport const ModeTextColorSchema = Type.Union([\n Type.Literal('accent'),\n Type.Literal('warning'),\n Type.Literal('mdHeading'),\n Type.Literal('muted'),\n Type.Literal('dim'),\n]);\nexport type ModeTextColor = Static<typeof ModeTextColorSchema>;\n\nexport const ModeStatusItemSchema = Type.Object(\n {\n id: Type.String({ minLength: 1, maxLength: 128 }),\n /**\n * The mode's name, and nothing else.\n *\n * Short because the line holds every enabled mode at once: `WORKFLOW`, not\n * `WORKFLOW MODE · ON`. That a label is present at all is what says the mode\n * is on, so an `ON` suffix spends a word restating the line's premise.\n */\n label: Type.String({ minLength: 1, maxLength: 24 }),\n /** Sub-state worth reading, parenthesised by the renderer: `normal - read only`. */\n detail: Type.Optional(Type.String({ minLength: 1, maxLength: 48 })),\n color: Type.Optional(ModeTextColorSchema),\n order: Type.Integer({ minimum: 0, maximum: 1000 }),\n },\n { additionalProperties: false },\n);\nexport type ModeStatusItem = Static<typeof ModeStatusItemSchema>;\n\nconst ModeStatusSourceSchema = Type.Object(\n {\n source: Type.String({ minLength: 1, maxLength: 128 }),\n generation: Type.String({ minLength: 1 }),\n },\n { additionalProperties: false },\n);\n\nconst ModeStatusSnapshotSchema = Type.Object(\n {\n ...ModeStatusSourceSchema.properties,\n items: Type.Array(ModeStatusItemSchema),\n },\n { additionalProperties: false },\n);\nexport type ModeStatusSnapshot = Static<typeof ModeStatusSnapshotSchema>;\nexport type ModeStatusSource = Static<typeof ModeStatusSourceSchema>;\n\nexport const ModeStatusDiscovery = defineNotification({\n channel: 'doom:ui:mode:v1:discover',\n kind: 'mode-status.discover',\n payload: Type.Object({}, { additionalProperties: false }),\n});\n\nexport const ModeStatusRegistration = defineNotification({\n channel: 'doom:ui:mode:v1:register',\n kind: 'mode-status.register',\n payload: ModeStatusSnapshotSchema,\n});\n\nexport const ModeStatusChanged = defineNotification({\n channel: 'doom:ui:mode:v1:changed',\n kind: 'mode-status.changed',\n payload: ModeStatusSnapshotSchema,\n});\n\nexport const ModeStatusUnregistration = defineNotification({\n channel: 'doom:ui:mode:v1:unregister',\n kind: 'mode-status.unregister',\n payload: ModeStatusSourceSchema,\n});\n\nexport interface ModeStatusProvider {\n source: string;\n listStatuses(): readonly ModeStatusItem[];\n}\n\nexport interface ModeStatusProviderHandle {\n update(): void;\n dispose(): void;\n}\n\nexport function registerModeStatusProvider(\n runtime: ProtocolRuntime,\n provider: ModeStatusProvider,\n): ModeStatusProviderHandle {\n const generation = `${provider.source}:${crypto.randomUUID()}`;\n let disposed = false;\n const snapshot = (): ModeStatusSnapshot => ({\n source: provider.source,\n generation,\n items: provider.listStatuses().map((item) => ({ ...item })),\n });\n // A renderer that loads after a provider would otherwise never learn about it,\n // and neither side controls the order extensions load in.\n const announce = (): void => {\n if (!disposed) runtime.notify(ModeStatusRegistration, snapshot());\n };\n const disposeDiscovery = runtime.onNotification(ModeStatusDiscovery, announce);\n announce();\n\n return {\n update() {\n if (!disposed) runtime.notify(ModeStatusChanged, snapshot());\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n disposeDiscovery();\n runtime.notify(ModeStatusUnregistration, { source: provider.source, generation });\n },\n };\n}\n\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\nexport interface DoomModeContributionDefinition {\n source: string;\n id: string;\n order: number;\n}\n\nexport interface DoomModeContributionValue {\n label: string;\n detail?: string;\n color?: ModeTextColor;\n}\n\nexport interface DoomModeContributionHandle {\n update(value: DoomModeContributionValue | undefined): void;\n dispose(): void;\n}\n\nexport interface DoomModeStatus extends ModeStatusItem {\n source: string;\n}\n\ninterface ActiveModeSource {\n generation: string;\n items: ModeStatusItem[];\n}\n\nexport class DoomModeStatusRegistry {\n private readonly sources = new Map<string, ActiveModeSource>();\n private readonly listeners = new Set<() => void>();\n\n bind(runtime: ProtocolRuntime): () => void {\n const disposers = [\n runtime.onNotification(ModeStatusRegistration, (snapshot) => this.register(snapshot)),\n runtime.onNotification(ModeStatusChanged, (snapshot) => this.update(snapshot)),\n runtime.onNotification(ModeStatusUnregistration, (source) => this.unregister(source)),\n ];\n runtime.notify(ModeStatusDiscovery, {});\n let disposed = false;\n return () => {\n if (disposed) return;\n disposed = true;\n for (const dispose of disposers) dispose();\n };\n }\n\n getStatuses(): DoomModeStatus[] {\n return [...this.sources.entries()]\n .flatMap(([source, snapshot]) => snapshot.items.map((item) => ({ source, ...item })))\n .toSorted(\n (left, right) =>\n left.order - right.order || left.source.localeCompare(right.source) || left.id.localeCompare(right.id),\n );\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n reset(): void {\n if (this.sources.size === 0) return;\n this.sources.clear();\n this.notify();\n }\n\n private register(snapshot: ModeStatusSnapshot): void {\n this.sources.set(snapshot.source, {\n generation: snapshot.generation,\n items: snapshot.items.map((item) => ({ ...item })),\n });\n this.notify();\n }\n\n private update(snapshot: ModeStatusSnapshot): void {\n if (this.sources.get(snapshot.source)?.generation !== snapshot.generation) return;\n this.sources.set(snapshot.source, {\n generation: snapshot.generation,\n items: snapshot.items.map((item) => ({ ...item })),\n });\n this.notify();\n }\n\n private unregister(source: ModeStatusSource): void {\n if (this.sources.get(source.source)?.generation !== source.generation) return;\n this.sources.delete(source.source);\n this.notify();\n }\n\n private notify(): void {\n for (const listener of this.listeners) listener();\n }\n}\n\nexport function registerDoomModeContribution(\n pi: DoomExtensionHost,\n definition: DoomModeContributionDefinition,\n): DoomModeContributionHandle {\n let value: DoomModeContributionValue | undefined;\n let provider: ModeStatusProviderHandle | undefined;\n let stopped = false;\n\n const disposeProvider = (): void => {\n provider?.dispose();\n provider = undefined;\n };\n\n pi.on(SESSION_START_EVENT, (_event, ctx) => {\n if (stopped) return;\n disposeProvider();\n const runtime = createProtocolRuntime({\n bus: pi.events,\n source: definition.source,\n sessionId: ctx.sessionManager.getSessionId(),\n });\n provider = registerModeStatusProvider(runtime, {\n source: definition.source,\n listStatuses: () =>\n value\n ? [\n {\n id: definition.id,\n label: value.label,\n ...(value.detail ? { detail: value.detail } : {}),\n ...(value.color ? { color: value.color } : {}),\n order: definition.order,\n },\n ]\n : [],\n });\n });\n\n pi.on(SESSION_SHUTDOWN_EVENT, disposeProvider);\n\n return {\n update(nextValue) {\n if (stopped) return;\n value = nextValue ? { ...nextValue } : undefined;\n provider?.update();\n },\n dispose() {\n if (stopped) return;\n stopped = true;\n value = undefined;\n disposeProvider();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("typebox"),t=require("typebox/value");const n={aborted:`ABORTED`,invalidMessage:`INVALID_MESSAGE`,providerError:`PROVIDER_ERROR`,timeout:`TIMEOUT`},r=e.Type.Object({code:e.Type.String({minLength:1}),message:e.Type.String({minLength:1}),retryable:e.Type.Optional(e.Type.Boolean())},{additionalProperties:!1});var i=class extends Error{code;retryable;constructor(e){super(e.message),this.name=`DoomProtocolError`,this.code=e.code,this.retryable=e.retryable??!1}},a=class extends i{constructor(e,t){super({code:n.invalidMessage,message:`Invalid message on ${e}: ${t}`}),this.name=`DoomProtocolValidationError`}};const o=e.Type.Object({protocol:e.Type.String({minLength:1}),version:e.Type.Literal(1),kind:e.Type.String({minLength:1}),messageId:e.Type.String({minLength:1}),correlationId:e.Type.Optional(e.Type.String({minLength:1})),source:e.Type.String({minLength:1}),sessionId:e.Type.String({minLength:1})},{additionalProperties:!1});function s(t){return e.Type.Object({...o.properties,payload:t},{additionalProperties:!1})}function c(e){let t=/^(doom:[^:]+(?::[^:]+)*):v\d+:/.exec(e);if(!t)throw Error(`Invalid Doom protocol channel: ${e}`);return t[1]}function l(e,n){return(0,t.Errors)(e,n).slice(0,3).map(e=>`${e.instancePath||`/`} ${e.message}`).join(`; `)}function u(e,n,r){if(!(0,t.Check)(n,r))throw new a(e,l(n,r))}function d(e){return e instanceof i?{code:e.code,message:e.message,retryable:e.retryable}:{code:n.providerError,message:e instanceof Error?e.message:String(e)}}function f(e){return c(e.channel),e}function p(e){let t=c(e.channels.request);for(let n of[e.channels.response,e.channels.error])if(c(n)!==t)throw Error(`Request/reply channels must share one protocol`);return{requestChannel:e.channels.request,responseChannel:e.channels.response,errorChannel:e.channels.error,requestKind:e.kinds.request,responseKind:e.kinds.response,request:e.request,response:e.response}}const m=p;function h(e){let t=e.defaultTimeoutMs??5e3,a=e.duplicateWindow??256,o=e.createMessageId??(()=>`${e.source}:${crypto.randomUUID()}`),l=e=>{queueMicrotask(()=>{throw e instanceof Error?e:Error(String(e))})};function f(){let e=new Set;return t=>!e.has(t)&&(e.add(t),e.size>a&&e.delete(e.values().next().value),!0)}function p(t,n,r=o(),i){return{protocol:c(t),version:1,kind:n,messageId:r,...i?{correlationId:i}:{},source:e.source,sessionId:e.sessionId}}return{notify(t,n){u(t.channel,t.payload,n),e.bus.emit(t.channel,{...p(t.channel,t.kind),payload:n})},onNotification(t,n){let r=s(t.payload),i=f();return e.bus.on(t.channel,a=>{u(t.channel,r,a);let o=a;o.sessionId===e.sessionId&&i(o.messageId)&&Promise.resolve(n(o.payload,o)).catch(l)})},request(a,c,l={}){u(a.requestChannel,a.request,c);let d=o(),f=s(a.response),m=s(r);return new Promise((r,o)=>{let s=!1,h=[],g=e=>{if(!s){s=!0;for(let e of h.splice(0))e();e()}};h.push(e.bus.on(a.responseChannel,t=>{u(a.responseChannel,f,t);let n=t;n.sessionId===e.sessionId&&n.correlationId===d&&g(()=>r(n.payload))}),e.bus.on(a.errorChannel,t=>{u(a.errorChannel,m,t);let n=t;n.sessionId===e.sessionId&&n.correlationId===d&&g(()=>o(new i(n.payload)))}));let _=setTimeout(()=>g(()=>o(new i({code:n.timeout,message:`Timed out waiting for ${a.responseKind}`}))),l.timeoutMs??t);if(h.push(()=>clearTimeout(_)),l.signal){let e=()=>g(()=>o(new i({code:n.aborted,message:`Request aborted`})));if(l.signal.addEventListener(`abort`,e,{once:!0}),h.push(()=>l.signal?.removeEventListener(`abort`,e)),l.signal.aborted)return e()}e.bus.emit(a.requestChannel,{...p(a.requestChannel,a.requestKind,d),payload:c})})},provide(t,n){let r=s(t.request),i=f();return e.bus.on(t.requestChannel,a=>{u(t.requestChannel,r,a);let s=a;s.sessionId===e.sessionId&&i(s.messageId)&&Promise.resolve().then(()=>n(s.payload,s)).then(n=>{u(t.responseChannel,t.response,n),e.bus.emit(t.responseChannel,{...p(t.responseChannel,t.responseKind,o(),s.messageId),payload:n})},n=>{e.bus.emit(t.errorChannel,{...p(t.errorChannel,`error`,o(),s.messageId),payload:d(n)})})})}}}exports.DOOM_PROTOCOL_ERROR_CODE=n,exports.DoomProtocolError=i,exports.DoomProtocolValidationError=a,exports.ProtocolErrorSchema=r,exports.createProtocolRuntime=h,exports.defineJob=m,exports.defineNotification=f,exports.defineRequestReply=p;
|
|
2
|
+
//# sourceMappingURL=protocol.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.cjs","names":["Type","Errors","Check"],"sources":["../src/protocol.ts"],"sourcesContent":["import { type Static, type TSchema, Type } from 'typebox';\nimport { Check, Errors } from 'typebox/value';\n\nexport const DOOM_PROTOCOL_ERROR_CODE = {\n aborted: 'ABORTED',\n invalidMessage: 'INVALID_MESSAGE',\n providerError: 'PROVIDER_ERROR',\n timeout: 'TIMEOUT',\n} as const;\n\nconst DEFAULT_PROTOCOL_TIMEOUT_MS = 5_000;\nconst DEFAULT_DUPLICATE_WINDOW = 256;\n\nexport interface EventBusLike {\n emit(event: string, data: unknown): void;\n on(event: string, handler: (data: unknown) => void): () => void;\n}\n\nexport const ProtocolErrorSchema = Type.Object(\n {\n code: Type.String({ minLength: 1 }),\n message: Type.String({ minLength: 1 }),\n retryable: Type.Optional(Type.Boolean()),\n },\n { additionalProperties: false },\n);\n\nexport type ProtocolErrorPayload = Static<typeof ProtocolErrorSchema>;\n\nexport class DoomProtocolError extends Error {\n readonly code: string;\n readonly retryable: boolean;\n\n constructor(payload: ProtocolErrorPayload) {\n super(payload.message);\n this.name = 'DoomProtocolError';\n this.code = payload.code;\n this.retryable = payload.retryable ?? false;\n }\n}\n\nexport class DoomProtocolValidationError extends DoomProtocolError {\n constructor(channel: string, details: string) {\n super({ code: DOOM_PROTOCOL_ERROR_CODE.invalidMessage, message: `Invalid message on ${channel}: ${details}` });\n this.name = 'DoomProtocolValidationError';\n }\n}\n\nexport interface ProtocolIdentity {\n source: string;\n sessionId: string;\n}\n\ninterface ProtocolEnvelope<TPayload> extends ProtocolIdentity {\n protocol: string;\n version: 1;\n kind: string;\n messageId: string;\n correlationId?: string;\n payload: TPayload;\n}\n\nexport interface NotificationDefinition<TPayload extends TSchema> {\n channel: string;\n kind: string;\n payload: TPayload;\n}\n\nexport interface RequestReplyDefinition<TRequest extends TSchema, TResponse extends TSchema> {\n requestChannel: string;\n responseChannel: string;\n errorChannel: string;\n requestKind: string;\n responseKind: string;\n request: TRequest;\n response: TResponse;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n}\n\nexport interface ProtocolRuntimeOptions extends ProtocolIdentity {\n bus: EventBusLike;\n defaultTimeoutMs?: number;\n createMessageId?: () => string;\n duplicateWindow?: number;\n}\n\nexport interface ProtocolRuntime {\n notify<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, payload: Static<TPayload>): void;\n onNotification<TPayload extends TSchema>(\n definition: NotificationDefinition<TPayload>,\n handler: (payload: Static<TPayload>, identity: ProtocolIdentity) => void | Promise<void>,\n ): () => void;\n request<TRequest extends TSchema, TResponse extends TSchema>(\n definition: RequestReplyDefinition<TRequest, TResponse>,\n payload: Static<TRequest>,\n options?: RequestOptions,\n ): Promise<Static<TResponse>>;\n provide<TRequest extends TSchema, TResponse extends TSchema>(\n definition: RequestReplyDefinition<TRequest, TResponse>,\n handler: (payload: Static<TRequest>, identity: ProtocolIdentity) => Static<TResponse> | Promise<Static<TResponse>>,\n ): () => void;\n}\n\nconst EnvelopeBaseSchema = Type.Object(\n {\n protocol: Type.String({ minLength: 1 }),\n version: Type.Literal(1),\n kind: Type.String({ minLength: 1 }),\n messageId: Type.String({ minLength: 1 }),\n correlationId: Type.Optional(Type.String({ minLength: 1 })),\n source: Type.String({ minLength: 1 }),\n sessionId: Type.String({ minLength: 1 }),\n },\n { additionalProperties: false },\n);\n\nfunction envelopeSchema<TPayload extends TSchema>(payload: TPayload) {\n return Type.Object({ ...EnvelopeBaseSchema.properties, payload }, { additionalProperties: false });\n}\n\nfunction protocolName(channel: string): string {\n const match = /^(doom:[^:]+(?::[^:]+)*):v\\d+:/.exec(channel);\n if (!match) throw new Error(`Invalid Doom protocol channel: ${channel}`);\n return match[1];\n}\n\nfunction validationDetails(schema: TSchema, value: unknown): string {\n return Errors(schema, value)\n .slice(0, 3)\n .map((error) => `${error.instancePath || '/'} ${error.message}`)\n .join('; ');\n}\n\nfunction assertValid<TSchemaValue extends TSchema>(\n channel: string,\n schema: TSchemaValue,\n value: unknown,\n): asserts value is Static<TSchemaValue> {\n if (!Check(schema, value)) throw new DoomProtocolValidationError(channel, validationDetails(schema, value));\n}\n\nfunction asProtocolError(error: unknown): ProtocolErrorPayload {\n if (error instanceof DoomProtocolError) {\n return { code: error.code, message: error.message, retryable: error.retryable };\n }\n return {\n code: DOOM_PROTOCOL_ERROR_CODE.providerError,\n message: error instanceof Error ? error.message : String(error),\n };\n}\n\nexport function defineNotification<TPayload extends TSchema>(definition: {\n channel: `doom:${string}:${string}:v1:${string}`;\n kind: string;\n payload: TPayload;\n}): NotificationDefinition<TPayload> {\n protocolName(definition.channel);\n return definition;\n}\n\nexport function defineRequestReply<TRequest extends TSchema, TResponse extends TSchema>(definition: {\n channels: {\n request: `doom:${string}:${string}:v1:${string}`;\n response: `doom:${string}:${string}:v1:${string}`;\n error: `doom:${string}:${string}:v1:${string}`;\n };\n kinds: { request: string; response: string };\n request: TRequest;\n response: TResponse;\n}): RequestReplyDefinition<TRequest, TResponse> {\n const protocol = protocolName(definition.channels.request);\n for (const channel of [definition.channels.response, definition.channels.error]) {\n if (protocolName(channel) !== protocol) throw new Error('Request/reply channels must share one protocol');\n }\n return {\n requestChannel: definition.channels.request,\n responseChannel: definition.channels.response,\n errorChannel: definition.channels.error,\n requestKind: definition.kinds.request,\n responseKind: definition.kinds.response,\n request: definition.request,\n response: definition.response,\n };\n}\n\nexport const defineJob = defineRequestReply;\n\nexport function createProtocolRuntime(options: ProtocolRuntimeOptions): ProtocolRuntime {\n const timeoutDefault = options.defaultTimeoutMs ?? DEFAULT_PROTOCOL_TIMEOUT_MS;\n const duplicateWindow = options.duplicateWindow ?? DEFAULT_DUPLICATE_WINDOW;\n const createMessageId = options.createMessageId ?? (() => `${options.source}:${crypto.randomUUID()}`);\n\n const rethrowAsync = (error: unknown): void => {\n queueMicrotask(() => {\n throw error instanceof Error ? error : new Error(String(error));\n });\n };\n\n function duplicateGuard(): (messageId: string) => boolean {\n const handled = new Set<string>();\n return (messageId) => {\n if (handled.has(messageId)) return false;\n handled.add(messageId);\n if (handled.size > duplicateWindow) handled.delete(handled.values().next().value as string);\n return true;\n };\n }\n\n function base(channel: string, kind: string, messageId = createMessageId(), correlationId?: string) {\n return {\n protocol: protocolName(channel),\n version: 1 as const,\n kind,\n messageId,\n ...(correlationId ? { correlationId } : {}),\n source: options.source,\n sessionId: options.sessionId,\n };\n }\n\n return {\n notify<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, payload: Static<TPayload>) {\n assertValid(definition.channel, definition.payload, payload);\n options.bus.emit(definition.channel, { ...base(definition.channel, definition.kind), payload });\n },\n\n onNotification<TPayload extends TSchema>(\n definition: NotificationDefinition<TPayload>,\n handler: (payload: Static<TPayload>, identity: ProtocolIdentity) => void | Promise<void>,\n ) {\n const schema = envelopeSchema(definition.payload);\n const remember = duplicateGuard();\n return options.bus.on(definition.channel, (message) => {\n assertValid(definition.channel, schema, message);\n const envelope = message as unknown as ProtocolEnvelope<Static<TPayload>>;\n if (envelope.sessionId !== options.sessionId) return;\n if (!remember(envelope.messageId)) return;\n void Promise.resolve(handler(envelope.payload, envelope)).catch(rethrowAsync);\n });\n },\n\n request<TRequest extends TSchema, TResponse extends TSchema>(\n definition: RequestReplyDefinition<TRequest, TResponse>,\n payload: Static<TRequest>,\n requestOptions: RequestOptions = {},\n ) {\n assertValid(definition.requestChannel, definition.request, payload);\n const messageId = createMessageId();\n const responseSchema = envelopeSchema(definition.response);\n const errorSchema = envelopeSchema(ProtocolErrorSchema);\n return new Promise<Static<typeof definition.response>>((resolve, reject) => {\n let settled = false;\n const cleanups: Array<() => void> = [];\n const finish = (action: () => void) => {\n if (settled) return;\n settled = true;\n for (const cleanup of cleanups.splice(0)) cleanup();\n action();\n };\n cleanups.push(\n options.bus.on(definition.responseChannel, (message) => {\n assertValid(definition.responseChannel, responseSchema, message);\n const envelope = message as unknown as ProtocolEnvelope<Static<TResponse>>;\n if (envelope.sessionId !== options.sessionId) return;\n if (envelope.correlationId !== messageId) return;\n finish(() => resolve(envelope.payload));\n }),\n options.bus.on(definition.errorChannel, (message) => {\n assertValid(definition.errorChannel, errorSchema, message);\n const envelope = message as unknown as ProtocolEnvelope<ProtocolErrorPayload>;\n if (envelope.sessionId !== options.sessionId) return;\n if (envelope.correlationId !== messageId) return;\n finish(() => reject(new DoomProtocolError(envelope.payload)));\n }),\n );\n const timer = setTimeout(\n () =>\n finish(() =>\n reject(\n new DoomProtocolError({\n code: DOOM_PROTOCOL_ERROR_CODE.timeout,\n message: `Timed out waiting for ${definition.responseKind}`,\n }),\n ),\n ),\n requestOptions.timeoutMs ?? timeoutDefault,\n );\n cleanups.push(() => clearTimeout(timer));\n if (requestOptions.signal) {\n const abort = () =>\n finish(() =>\n reject(new DoomProtocolError({ code: DOOM_PROTOCOL_ERROR_CODE.aborted, message: 'Request aborted' })),\n );\n requestOptions.signal.addEventListener('abort', abort, { once: true });\n cleanups.push(() => requestOptions.signal?.removeEventListener('abort', abort));\n if (requestOptions.signal.aborted) return abort();\n }\n options.bus.emit(definition.requestChannel, {\n ...base(definition.requestChannel, definition.requestKind, messageId),\n payload,\n });\n });\n },\n\n provide<TRequest extends TSchema, TResponse extends TSchema>(\n definition: RequestReplyDefinition<TRequest, TResponse>,\n handler: (\n payload: Static<TRequest>,\n identity: ProtocolIdentity,\n ) => Static<TResponse> | Promise<Static<TResponse>>,\n ) {\n const requestSchema = envelopeSchema(definition.request);\n const remember = duplicateGuard();\n return options.bus.on(definition.requestChannel, (message) => {\n assertValid(definition.requestChannel, requestSchema, message);\n const envelope = message as unknown as ProtocolEnvelope<Static<TRequest>>;\n if (envelope.sessionId !== options.sessionId) return;\n if (!remember(envelope.messageId)) return;\n void Promise.resolve()\n .then(() => handler(envelope.payload, envelope))\n .then(\n (payload) => {\n assertValid(definition.responseChannel, definition.response, payload);\n options.bus.emit(definition.responseChannel, {\n ...base(definition.responseChannel, definition.responseKind, createMessageId(), envelope.messageId),\n payload,\n });\n },\n (error) => {\n options.bus.emit(definition.errorChannel, {\n ...base(definition.errorChannel, 'error', createMessageId(), envelope.messageId),\n payload: asProtocolError(error),\n });\n },\n );\n });\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Static, TSchema, Type } from "typebox";
|
|
2
|
+
//#region src/protocol.d.ts
|
|
3
|
+
declare const DOOM_PROTOCOL_ERROR_CODE: {
|
|
4
|
+
readonly aborted: "ABORTED";
|
|
5
|
+
readonly invalidMessage: "INVALID_MESSAGE";
|
|
6
|
+
readonly providerError: "PROVIDER_ERROR";
|
|
7
|
+
readonly timeout: "TIMEOUT";
|
|
8
|
+
};
|
|
9
|
+
interface EventBusLike {
|
|
10
|
+
emit(event: string, data: unknown): void;
|
|
11
|
+
on(event: string, handler: (data: unknown) => void): () => void;
|
|
12
|
+
}
|
|
13
|
+
declare const ProtocolErrorSchema: Type.TObject<{
|
|
14
|
+
code: Type.TString;
|
|
15
|
+
message: Type.TString;
|
|
16
|
+
retryable: Type.TOptional<Type.TBoolean>;
|
|
17
|
+
}>;
|
|
18
|
+
type ProtocolErrorPayload = Static<typeof ProtocolErrorSchema>;
|
|
19
|
+
declare class DoomProtocolError extends Error {
|
|
20
|
+
readonly code: string;
|
|
21
|
+
readonly retryable: boolean;
|
|
22
|
+
constructor(payload: ProtocolErrorPayload);
|
|
23
|
+
}
|
|
24
|
+
declare class DoomProtocolValidationError extends DoomProtocolError {
|
|
25
|
+
constructor(channel: string, details: string);
|
|
26
|
+
}
|
|
27
|
+
interface ProtocolIdentity {
|
|
28
|
+
source: string;
|
|
29
|
+
sessionId: string;
|
|
30
|
+
}
|
|
31
|
+
interface NotificationDefinition<TPayload extends TSchema> {
|
|
32
|
+
channel: string;
|
|
33
|
+
kind: string;
|
|
34
|
+
payload: TPayload;
|
|
35
|
+
}
|
|
36
|
+
interface RequestReplyDefinition<TRequest extends TSchema, TResponse extends TSchema> {
|
|
37
|
+
requestChannel: string;
|
|
38
|
+
responseChannel: string;
|
|
39
|
+
errorChannel: string;
|
|
40
|
+
requestKind: string;
|
|
41
|
+
responseKind: string;
|
|
42
|
+
request: TRequest;
|
|
43
|
+
response: TResponse;
|
|
44
|
+
}
|
|
45
|
+
interface RequestOptions {
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
}
|
|
49
|
+
interface ProtocolRuntimeOptions extends ProtocolIdentity {
|
|
50
|
+
bus: EventBusLike;
|
|
51
|
+
defaultTimeoutMs?: number;
|
|
52
|
+
createMessageId?: () => string;
|
|
53
|
+
duplicateWindow?: number;
|
|
54
|
+
}
|
|
55
|
+
interface ProtocolRuntime {
|
|
56
|
+
notify<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, payload: Static<TPayload>): void;
|
|
57
|
+
onNotification<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, handler: (payload: Static<TPayload>, identity: ProtocolIdentity) => void | Promise<void>): () => void;
|
|
58
|
+
request<TRequest extends TSchema, TResponse extends TSchema>(definition: RequestReplyDefinition<TRequest, TResponse>, payload: Static<TRequest>, options?: RequestOptions): Promise<Static<TResponse>>;
|
|
59
|
+
provide<TRequest extends TSchema, TResponse extends TSchema>(definition: RequestReplyDefinition<TRequest, TResponse>, handler: (payload: Static<TRequest>, identity: ProtocolIdentity) => Static<TResponse> | Promise<Static<TResponse>>): () => void;
|
|
60
|
+
}
|
|
61
|
+
declare function defineNotification<TPayload extends TSchema>(definition: {
|
|
62
|
+
channel: `doom:${string}:${string}:v1:${string}`;
|
|
63
|
+
kind: string;
|
|
64
|
+
payload: TPayload;
|
|
65
|
+
}): NotificationDefinition<TPayload>;
|
|
66
|
+
declare function defineRequestReply<TRequest extends TSchema, TResponse extends TSchema>(definition: {
|
|
67
|
+
channels: {
|
|
68
|
+
request: `doom:${string}:${string}:v1:${string}`;
|
|
69
|
+
response: `doom:${string}:${string}:v1:${string}`;
|
|
70
|
+
error: `doom:${string}:${string}:v1:${string}`;
|
|
71
|
+
};
|
|
72
|
+
kinds: {
|
|
73
|
+
request: string;
|
|
74
|
+
response: string;
|
|
75
|
+
};
|
|
76
|
+
request: TRequest;
|
|
77
|
+
response: TResponse;
|
|
78
|
+
}): RequestReplyDefinition<TRequest, TResponse>;
|
|
79
|
+
declare const defineJob: typeof defineRequestReply;
|
|
80
|
+
declare function createProtocolRuntime(options: ProtocolRuntimeOptions): ProtocolRuntime;
|
|
81
|
+
//#endregion
|
|
82
|
+
export { DOOM_PROTOCOL_ERROR_CODE, DoomProtocolError, DoomProtocolValidationError, EventBusLike, NotificationDefinition, ProtocolErrorPayload, ProtocolErrorSchema, ProtocolIdentity, ProtocolRuntime, ProtocolRuntimeOptions, RequestOptions, RequestReplyDefinition, createProtocolRuntime, defineJob, defineNotification, defineRequestReply };
|
|
83
|
+
//# sourceMappingURL=protocol.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.cts","names":[],"sources":["../src/protocol.ts"],"mappings":";;cAGa;;;;;;UAUI;EACf,KAAK,eAAe;EACpB,GAAG,eAAe,UAAU;;cAGjB,qBAAmB,KAAA;;;;;KASpB,uBAAuB,cAAc;cAEpC,0BAA0B;WAC5B;WACA;EAEG,YAAA,SAAS;;cAQV,oCAAoC;EACnC,YAAA,iBAAiB;;UAMd;EACf;EACA;;UAYe,uBAAuB,iBAAiB;EACvD;EACA;EACA,SAAS;;UAGM,uBAAuB,iBAAiB,SAAS,kBAAkB;EAClF;EACA;EACA;EACA;EACA;EACA,SAAS;EACT,UAAU;;UAGK;EACf,SAAS;EACT;;UAGe,+BAA+B;EAC9C,KAAK;EACL;EACA;EACA;;UAGe;EACf,OAAO,iBAAiB,SAAS,YAAY,uBAAuB,WAAW,SAAS,OAAO;EAC/F,eAAe,iBAAiB,SAC9B,YAAY,uBAAuB,WACnC,UAAU,SAAS,OAAO,WAAW,UAAU,4BAA4B;EAE7E,QAAQ,iBAAiB,SAAS,kBAAkB,SAClD,YAAY,uBAAuB,UAAU,YAC7C,SAAS,OAAO,WAChB,UAAU,iBACT,QAAQ,OAAO;EAClB,QAAQ,iBAAiB,SAAS,kBAAkB,SAClD,YAAY,uBAAuB,UAAU,YAC7C,UAAU,SAAS,OAAO,WAAW,UAAU,qBAAqB,OAAO,aAAa,QAAQ,OAAO;;iBAoD3F,mBAAmB,iBAAiB,SAAS;EAC3D;EACA;EACA,SAAS;IACP,uBAAuB;iBAKX,mBAAmB,iBAAiB,SAAS,kBAAkB,SAAS;EACtF;IACE;IACA;IACA;;EAEF;IAAS;IAAiB;;EAC1B,SAAS;EACT,UAAU;IACR,uBAAuB,UAAU;cAgBxB,kBAAS;iBAEN,sBAAsB,SAAS,yBAAyB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Static, TSchema, Type } from "typebox";
|
|
2
|
+
//#region src/protocol.d.ts
|
|
3
|
+
declare const DOOM_PROTOCOL_ERROR_CODE: {
|
|
4
|
+
readonly aborted: "ABORTED";
|
|
5
|
+
readonly invalidMessage: "INVALID_MESSAGE";
|
|
6
|
+
readonly providerError: "PROVIDER_ERROR";
|
|
7
|
+
readonly timeout: "TIMEOUT";
|
|
8
|
+
};
|
|
9
|
+
interface EventBusLike {
|
|
10
|
+
emit(event: string, data: unknown): void;
|
|
11
|
+
on(event: string, handler: (data: unknown) => void): () => void;
|
|
12
|
+
}
|
|
13
|
+
declare const ProtocolErrorSchema: Type.TObject<{
|
|
14
|
+
code: Type.TString;
|
|
15
|
+
message: Type.TString;
|
|
16
|
+
retryable: Type.TOptional<Type.TBoolean>;
|
|
17
|
+
}>;
|
|
18
|
+
type ProtocolErrorPayload = Static<typeof ProtocolErrorSchema>;
|
|
19
|
+
declare class DoomProtocolError extends Error {
|
|
20
|
+
readonly code: string;
|
|
21
|
+
readonly retryable: boolean;
|
|
22
|
+
constructor(payload: ProtocolErrorPayload);
|
|
23
|
+
}
|
|
24
|
+
declare class DoomProtocolValidationError extends DoomProtocolError {
|
|
25
|
+
constructor(channel: string, details: string);
|
|
26
|
+
}
|
|
27
|
+
interface ProtocolIdentity {
|
|
28
|
+
source: string;
|
|
29
|
+
sessionId: string;
|
|
30
|
+
}
|
|
31
|
+
interface NotificationDefinition<TPayload extends TSchema> {
|
|
32
|
+
channel: string;
|
|
33
|
+
kind: string;
|
|
34
|
+
payload: TPayload;
|
|
35
|
+
}
|
|
36
|
+
interface RequestReplyDefinition<TRequest extends TSchema, TResponse extends TSchema> {
|
|
37
|
+
requestChannel: string;
|
|
38
|
+
responseChannel: string;
|
|
39
|
+
errorChannel: string;
|
|
40
|
+
requestKind: string;
|
|
41
|
+
responseKind: string;
|
|
42
|
+
request: TRequest;
|
|
43
|
+
response: TResponse;
|
|
44
|
+
}
|
|
45
|
+
interface RequestOptions {
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
timeoutMs?: number;
|
|
48
|
+
}
|
|
49
|
+
interface ProtocolRuntimeOptions extends ProtocolIdentity {
|
|
50
|
+
bus: EventBusLike;
|
|
51
|
+
defaultTimeoutMs?: number;
|
|
52
|
+
createMessageId?: () => string;
|
|
53
|
+
duplicateWindow?: number;
|
|
54
|
+
}
|
|
55
|
+
interface ProtocolRuntime {
|
|
56
|
+
notify<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, payload: Static<TPayload>): void;
|
|
57
|
+
onNotification<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, handler: (payload: Static<TPayload>, identity: ProtocolIdentity) => void | Promise<void>): () => void;
|
|
58
|
+
request<TRequest extends TSchema, TResponse extends TSchema>(definition: RequestReplyDefinition<TRequest, TResponse>, payload: Static<TRequest>, options?: RequestOptions): Promise<Static<TResponse>>;
|
|
59
|
+
provide<TRequest extends TSchema, TResponse extends TSchema>(definition: RequestReplyDefinition<TRequest, TResponse>, handler: (payload: Static<TRequest>, identity: ProtocolIdentity) => Static<TResponse> | Promise<Static<TResponse>>): () => void;
|
|
60
|
+
}
|
|
61
|
+
declare function defineNotification<TPayload extends TSchema>(definition: {
|
|
62
|
+
channel: `doom:${string}:${string}:v1:${string}`;
|
|
63
|
+
kind: string;
|
|
64
|
+
payload: TPayload;
|
|
65
|
+
}): NotificationDefinition<TPayload>;
|
|
66
|
+
declare function defineRequestReply<TRequest extends TSchema, TResponse extends TSchema>(definition: {
|
|
67
|
+
channels: {
|
|
68
|
+
request: `doom:${string}:${string}:v1:${string}`;
|
|
69
|
+
response: `doom:${string}:${string}:v1:${string}`;
|
|
70
|
+
error: `doom:${string}:${string}:v1:${string}`;
|
|
71
|
+
};
|
|
72
|
+
kinds: {
|
|
73
|
+
request: string;
|
|
74
|
+
response: string;
|
|
75
|
+
};
|
|
76
|
+
request: TRequest;
|
|
77
|
+
response: TResponse;
|
|
78
|
+
}): RequestReplyDefinition<TRequest, TResponse>;
|
|
79
|
+
declare const defineJob: typeof defineRequestReply;
|
|
80
|
+
declare function createProtocolRuntime(options: ProtocolRuntimeOptions): ProtocolRuntime;
|
|
81
|
+
//#endregion
|
|
82
|
+
export { DOOM_PROTOCOL_ERROR_CODE, DoomProtocolError, DoomProtocolValidationError, EventBusLike, NotificationDefinition, ProtocolErrorPayload, ProtocolErrorSchema, ProtocolIdentity, ProtocolRuntime, ProtocolRuntimeOptions, RequestOptions, RequestReplyDefinition, createProtocolRuntime, defineJob, defineNotification, defineRequestReply };
|
|
83
|
+
//# sourceMappingURL=protocol.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.mts","names":[],"sources":["../src/protocol.ts"],"mappings":";;cAGa;;;;;;UAUI;EACf,KAAK,eAAe;EACpB,GAAG,eAAe,UAAU;;cAGjB,qBAAmB,KAAA;;;;;KASpB,uBAAuB,cAAc;cAEpC,0BAA0B;WAC5B;WACA;EAEG,YAAA,SAAS;;cAQV,oCAAoC;EACnC,YAAA,iBAAiB;;UAMd;EACf;EACA;;UAYe,uBAAuB,iBAAiB;EACvD;EACA;EACA,SAAS;;UAGM,uBAAuB,iBAAiB,SAAS,kBAAkB;EAClF;EACA;EACA;EACA;EACA;EACA,SAAS;EACT,UAAU;;UAGK;EACf,SAAS;EACT;;UAGe,+BAA+B;EAC9C,KAAK;EACL;EACA;EACA;;UAGe;EACf,OAAO,iBAAiB,SAAS,YAAY,uBAAuB,WAAW,SAAS,OAAO;EAC/F,eAAe,iBAAiB,SAC9B,YAAY,uBAAuB,WACnC,UAAU,SAAS,OAAO,WAAW,UAAU,4BAA4B;EAE7E,QAAQ,iBAAiB,SAAS,kBAAkB,SAClD,YAAY,uBAAuB,UAAU,YAC7C,SAAS,OAAO,WAChB,UAAU,iBACT,QAAQ,OAAO;EAClB,QAAQ,iBAAiB,SAAS,kBAAkB,SAClD,YAAY,uBAAuB,UAAU,YAC7C,UAAU,SAAS,OAAO,WAAW,UAAU,qBAAqB,OAAO,aAAa,QAAQ,OAAO;;iBAoD3F,mBAAmB,iBAAiB,SAAS;EAC3D;EACA;EACA,SAAS;IACP,uBAAuB;iBAKX,mBAAmB,iBAAiB,SAAS,kBAAkB,SAAS;EACtF;IACE;IACA;IACA;;EAEF;IAAS;IAAiB;;EAC1B,SAAS;EACT,UAAU;IACR,uBAAuB,UAAU;cAgBxB,kBAAS;iBAEN,sBAAsB,SAAS,yBAAyB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Type as e}from"typebox";import{Check as t,Errors as n}from"typebox/value";const r={aborted:`ABORTED`,invalidMessage:`INVALID_MESSAGE`,providerError:`PROVIDER_ERROR`,timeout:`TIMEOUT`},i=e.Object({code:e.String({minLength:1}),message:e.String({minLength:1}),retryable:e.Optional(e.Boolean())},{additionalProperties:!1});var a=class extends Error{code;retryable;constructor(e){super(e.message),this.name=`DoomProtocolError`,this.code=e.code,this.retryable=e.retryable??!1}},o=class extends a{constructor(e,t){super({code:r.invalidMessage,message:`Invalid message on ${e}: ${t}`}),this.name=`DoomProtocolValidationError`}};const s=e.Object({protocol:e.String({minLength:1}),version:e.Literal(1),kind:e.String({minLength:1}),messageId:e.String({minLength:1}),correlationId:e.Optional(e.String({minLength:1})),source:e.String({minLength:1}),sessionId:e.String({minLength:1})},{additionalProperties:!1});function c(t){return e.Object({...s.properties,payload:t},{additionalProperties:!1})}function l(e){let t=/^(doom:[^:]+(?::[^:]+)*):v\d+:/.exec(e);if(!t)throw Error(`Invalid Doom protocol channel: ${e}`);return t[1]}function u(e,t){return n(e,t).slice(0,3).map(e=>`${e.instancePath||`/`} ${e.message}`).join(`; `)}function d(e,n,r){if(!t(n,r))throw new o(e,u(n,r))}function f(e){return e instanceof a?{code:e.code,message:e.message,retryable:e.retryable}:{code:r.providerError,message:e instanceof Error?e.message:String(e)}}function p(e){return l(e.channel),e}function m(e){let t=l(e.channels.request);for(let n of[e.channels.response,e.channels.error])if(l(n)!==t)throw Error(`Request/reply channels must share one protocol`);return{requestChannel:e.channels.request,responseChannel:e.channels.response,errorChannel:e.channels.error,requestKind:e.kinds.request,responseKind:e.kinds.response,request:e.request,response:e.response}}const h=m;function g(e){let t=e.defaultTimeoutMs??5e3,n=e.duplicateWindow??256,o=e.createMessageId??(()=>`${e.source}:${crypto.randomUUID()}`),s=e=>{queueMicrotask(()=>{throw e instanceof Error?e:Error(String(e))})};function u(){let e=new Set;return t=>!e.has(t)&&(e.add(t),e.size>n&&e.delete(e.values().next().value),!0)}function p(t,n,r=o(),i){return{protocol:l(t),version:1,kind:n,messageId:r,...i?{correlationId:i}:{},source:e.source,sessionId:e.sessionId}}return{notify(t,n){d(t.channel,t.payload,n),e.bus.emit(t.channel,{...p(t.channel,t.kind),payload:n})},onNotification(t,n){let r=c(t.payload),i=u();return e.bus.on(t.channel,a=>{d(t.channel,r,a);let o=a;o.sessionId===e.sessionId&&i(o.messageId)&&Promise.resolve(n(o.payload,o)).catch(s)})},request(n,s,l={}){d(n.requestChannel,n.request,s);let u=o(),f=c(n.response),m=c(i);return new Promise((i,o)=>{let c=!1,h=[],g=e=>{if(!c){c=!0;for(let e of h.splice(0))e();e()}};h.push(e.bus.on(n.responseChannel,t=>{d(n.responseChannel,f,t);let r=t;r.sessionId===e.sessionId&&r.correlationId===u&&g(()=>i(r.payload))}),e.bus.on(n.errorChannel,t=>{d(n.errorChannel,m,t);let r=t;r.sessionId===e.sessionId&&r.correlationId===u&&g(()=>o(new a(r.payload)))}));let _=setTimeout(()=>g(()=>o(new a({code:r.timeout,message:`Timed out waiting for ${n.responseKind}`}))),l.timeoutMs??t);if(h.push(()=>clearTimeout(_)),l.signal){let e=()=>g(()=>o(new a({code:r.aborted,message:`Request aborted`})));if(l.signal.addEventListener(`abort`,e,{once:!0}),h.push(()=>l.signal?.removeEventListener(`abort`,e)),l.signal.aborted)return e()}e.bus.emit(n.requestChannel,{...p(n.requestChannel,n.requestKind,u),payload:s})})},provide(t,n){let r=c(t.request),i=u();return e.bus.on(t.requestChannel,a=>{d(t.requestChannel,r,a);let s=a;s.sessionId===e.sessionId&&i(s.messageId)&&Promise.resolve().then(()=>n(s.payload,s)).then(n=>{d(t.responseChannel,t.response,n),e.bus.emit(t.responseChannel,{...p(t.responseChannel,t.responseKind,o(),s.messageId),payload:n})},n=>{e.bus.emit(t.errorChannel,{...p(t.errorChannel,`error`,o(),s.messageId),payload:f(n)})})})}}}export{r as DOOM_PROTOCOL_ERROR_CODE,a as DoomProtocolError,o as DoomProtocolValidationError,i as ProtocolErrorSchema,g as createProtocolRuntime,h as defineJob,p as defineNotification,m as defineRequestReply};
|
|
2
|
+
//# sourceMappingURL=protocol.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.mjs","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["import { type Static, type TSchema, Type } from 'typebox';\nimport { Check, Errors } from 'typebox/value';\n\nexport const DOOM_PROTOCOL_ERROR_CODE = {\n aborted: 'ABORTED',\n invalidMessage: 'INVALID_MESSAGE',\n providerError: 'PROVIDER_ERROR',\n timeout: 'TIMEOUT',\n} as const;\n\nconst DEFAULT_PROTOCOL_TIMEOUT_MS = 5_000;\nconst DEFAULT_DUPLICATE_WINDOW = 256;\n\nexport interface EventBusLike {\n emit(event: string, data: unknown): void;\n on(event: string, handler: (data: unknown) => void): () => void;\n}\n\nexport const ProtocolErrorSchema = Type.Object(\n {\n code: Type.String({ minLength: 1 }),\n message: Type.String({ minLength: 1 }),\n retryable: Type.Optional(Type.Boolean()),\n },\n { additionalProperties: false },\n);\n\nexport type ProtocolErrorPayload = Static<typeof ProtocolErrorSchema>;\n\nexport class DoomProtocolError extends Error {\n readonly code: string;\n readonly retryable: boolean;\n\n constructor(payload: ProtocolErrorPayload) {\n super(payload.message);\n this.name = 'DoomProtocolError';\n this.code = payload.code;\n this.retryable = payload.retryable ?? false;\n }\n}\n\nexport class DoomProtocolValidationError extends DoomProtocolError {\n constructor(channel: string, details: string) {\n super({ code: DOOM_PROTOCOL_ERROR_CODE.invalidMessage, message: `Invalid message on ${channel}: ${details}` });\n this.name = 'DoomProtocolValidationError';\n }\n}\n\nexport interface ProtocolIdentity {\n source: string;\n sessionId: string;\n}\n\ninterface ProtocolEnvelope<TPayload> extends ProtocolIdentity {\n protocol: string;\n version: 1;\n kind: string;\n messageId: string;\n correlationId?: string;\n payload: TPayload;\n}\n\nexport interface NotificationDefinition<TPayload extends TSchema> {\n channel: string;\n kind: string;\n payload: TPayload;\n}\n\nexport interface RequestReplyDefinition<TRequest extends TSchema, TResponse extends TSchema> {\n requestChannel: string;\n responseChannel: string;\n errorChannel: string;\n requestKind: string;\n responseKind: string;\n request: TRequest;\n response: TResponse;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n}\n\nexport interface ProtocolRuntimeOptions extends ProtocolIdentity {\n bus: EventBusLike;\n defaultTimeoutMs?: number;\n createMessageId?: () => string;\n duplicateWindow?: number;\n}\n\nexport interface ProtocolRuntime {\n notify<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, payload: Static<TPayload>): void;\n onNotification<TPayload extends TSchema>(\n definition: NotificationDefinition<TPayload>,\n handler: (payload: Static<TPayload>, identity: ProtocolIdentity) => void | Promise<void>,\n ): () => void;\n request<TRequest extends TSchema, TResponse extends TSchema>(\n definition: RequestReplyDefinition<TRequest, TResponse>,\n payload: Static<TRequest>,\n options?: RequestOptions,\n ): Promise<Static<TResponse>>;\n provide<TRequest extends TSchema, TResponse extends TSchema>(\n definition: RequestReplyDefinition<TRequest, TResponse>,\n handler: (payload: Static<TRequest>, identity: ProtocolIdentity) => Static<TResponse> | Promise<Static<TResponse>>,\n ): () => void;\n}\n\nconst EnvelopeBaseSchema = Type.Object(\n {\n protocol: Type.String({ minLength: 1 }),\n version: Type.Literal(1),\n kind: Type.String({ minLength: 1 }),\n messageId: Type.String({ minLength: 1 }),\n correlationId: Type.Optional(Type.String({ minLength: 1 })),\n source: Type.String({ minLength: 1 }),\n sessionId: Type.String({ minLength: 1 }),\n },\n { additionalProperties: false },\n);\n\nfunction envelopeSchema<TPayload extends TSchema>(payload: TPayload) {\n return Type.Object({ ...EnvelopeBaseSchema.properties, payload }, { additionalProperties: false });\n}\n\nfunction protocolName(channel: string): string {\n const match = /^(doom:[^:]+(?::[^:]+)*):v\\d+:/.exec(channel);\n if (!match) throw new Error(`Invalid Doom protocol channel: ${channel}`);\n return match[1];\n}\n\nfunction validationDetails(schema: TSchema, value: unknown): string {\n return Errors(schema, value)\n .slice(0, 3)\n .map((error) => `${error.instancePath || '/'} ${error.message}`)\n .join('; ');\n}\n\nfunction assertValid<TSchemaValue extends TSchema>(\n channel: string,\n schema: TSchemaValue,\n value: unknown,\n): asserts value is Static<TSchemaValue> {\n if (!Check(schema, value)) throw new DoomProtocolValidationError(channel, validationDetails(schema, value));\n}\n\nfunction asProtocolError(error: unknown): ProtocolErrorPayload {\n if (error instanceof DoomProtocolError) {\n return { code: error.code, message: error.message, retryable: error.retryable };\n }\n return {\n code: DOOM_PROTOCOL_ERROR_CODE.providerError,\n message: error instanceof Error ? error.message : String(error),\n };\n}\n\nexport function defineNotification<TPayload extends TSchema>(definition: {\n channel: `doom:${string}:${string}:v1:${string}`;\n kind: string;\n payload: TPayload;\n}): NotificationDefinition<TPayload> {\n protocolName(definition.channel);\n return definition;\n}\n\nexport function defineRequestReply<TRequest extends TSchema, TResponse extends TSchema>(definition: {\n channels: {\n request: `doom:${string}:${string}:v1:${string}`;\n response: `doom:${string}:${string}:v1:${string}`;\n error: `doom:${string}:${string}:v1:${string}`;\n };\n kinds: { request: string; response: string };\n request: TRequest;\n response: TResponse;\n}): RequestReplyDefinition<TRequest, TResponse> {\n const protocol = protocolName(definition.channels.request);\n for (const channel of [definition.channels.response, definition.channels.error]) {\n if (protocolName(channel) !== protocol) throw new Error('Request/reply channels must share one protocol');\n }\n return {\n requestChannel: definition.channels.request,\n responseChannel: definition.channels.response,\n errorChannel: definition.channels.error,\n requestKind: definition.kinds.request,\n responseKind: definition.kinds.response,\n request: definition.request,\n response: definition.response,\n };\n}\n\nexport const defineJob = defineRequestReply;\n\nexport function createProtocolRuntime(options: ProtocolRuntimeOptions): ProtocolRuntime {\n const timeoutDefault = options.defaultTimeoutMs ?? DEFAULT_PROTOCOL_TIMEOUT_MS;\n const duplicateWindow = options.duplicateWindow ?? DEFAULT_DUPLICATE_WINDOW;\n const createMessageId = options.createMessageId ?? (() => `${options.source}:${crypto.randomUUID()}`);\n\n const rethrowAsync = (error: unknown): void => {\n queueMicrotask(() => {\n throw error instanceof Error ? error : new Error(String(error));\n });\n };\n\n function duplicateGuard(): (messageId: string) => boolean {\n const handled = new Set<string>();\n return (messageId) => {\n if (handled.has(messageId)) return false;\n handled.add(messageId);\n if (handled.size > duplicateWindow) handled.delete(handled.values().next().value as string);\n return true;\n };\n }\n\n function base(channel: string, kind: string, messageId = createMessageId(), correlationId?: string) {\n return {\n protocol: protocolName(channel),\n version: 1 as const,\n kind,\n messageId,\n ...(correlationId ? { correlationId } : {}),\n source: options.source,\n sessionId: options.sessionId,\n };\n }\n\n return {\n notify<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, payload: Static<TPayload>) {\n assertValid(definition.channel, definition.payload, payload);\n options.bus.emit(definition.channel, { ...base(definition.channel, definition.kind), payload });\n },\n\n onNotification<TPayload extends TSchema>(\n definition: NotificationDefinition<TPayload>,\n handler: (payload: Static<TPayload>, identity: ProtocolIdentity) => void | Promise<void>,\n ) {\n const schema = envelopeSchema(definition.payload);\n const remember = duplicateGuard();\n return options.bus.on(definition.channel, (message) => {\n assertValid(definition.channel, schema, message);\n const envelope = message as unknown as ProtocolEnvelope<Static<TPayload>>;\n if (envelope.sessionId !== options.sessionId) return;\n if (!remember(envelope.messageId)) return;\n void Promise.resolve(handler(envelope.payload, envelope)).catch(rethrowAsync);\n });\n },\n\n request<TRequest extends TSchema, TResponse extends TSchema>(\n definition: RequestReplyDefinition<TRequest, TResponse>,\n payload: Static<TRequest>,\n requestOptions: RequestOptions = {},\n ) {\n assertValid(definition.requestChannel, definition.request, payload);\n const messageId = createMessageId();\n const responseSchema = envelopeSchema(definition.response);\n const errorSchema = envelopeSchema(ProtocolErrorSchema);\n return new Promise<Static<typeof definition.response>>((resolve, reject) => {\n let settled = false;\n const cleanups: Array<() => void> = [];\n const finish = (action: () => void) => {\n if (settled) return;\n settled = true;\n for (const cleanup of cleanups.splice(0)) cleanup();\n action();\n };\n cleanups.push(\n options.bus.on(definition.responseChannel, (message) => {\n assertValid(definition.responseChannel, responseSchema, message);\n const envelope = message as unknown as ProtocolEnvelope<Static<TResponse>>;\n if (envelope.sessionId !== options.sessionId) return;\n if (envelope.correlationId !== messageId) return;\n finish(() => resolve(envelope.payload));\n }),\n options.bus.on(definition.errorChannel, (message) => {\n assertValid(definition.errorChannel, errorSchema, message);\n const envelope = message as unknown as ProtocolEnvelope<ProtocolErrorPayload>;\n if (envelope.sessionId !== options.sessionId) return;\n if (envelope.correlationId !== messageId) return;\n finish(() => reject(new DoomProtocolError(envelope.payload)));\n }),\n );\n const timer = setTimeout(\n () =>\n finish(() =>\n reject(\n new DoomProtocolError({\n code: DOOM_PROTOCOL_ERROR_CODE.timeout,\n message: `Timed out waiting for ${definition.responseKind}`,\n }),\n ),\n ),\n requestOptions.timeoutMs ?? timeoutDefault,\n );\n cleanups.push(() => clearTimeout(timer));\n if (requestOptions.signal) {\n const abort = () =>\n finish(() =>\n reject(new DoomProtocolError({ code: DOOM_PROTOCOL_ERROR_CODE.aborted, message: 'Request aborted' })),\n );\n requestOptions.signal.addEventListener('abort', abort, { once: true });\n cleanups.push(() => requestOptions.signal?.removeEventListener('abort', abort));\n if (requestOptions.signal.aborted) return abort();\n }\n options.bus.emit(definition.requestChannel, {\n ...base(definition.requestChannel, definition.requestKind, messageId),\n payload,\n });\n });\n },\n\n provide<TRequest extends TSchema, TResponse extends TSchema>(\n definition: RequestReplyDefinition<TRequest, TResponse>,\n handler: (\n payload: Static<TRequest>,\n identity: ProtocolIdentity,\n ) => Static<TResponse> | Promise<Static<TResponse>>,\n ) {\n const requestSchema = envelopeSchema(definition.request);\n const remember = duplicateGuard();\n return options.bus.on(definition.requestChannel, (message) => {\n assertValid(definition.requestChannel, requestSchema, message);\n const envelope = message as unknown as ProtocolEnvelope<Static<TRequest>>;\n if (envelope.sessionId !== options.sessionId) return;\n if (!remember(envelope.messageId)) return;\n void Promise.resolve()\n .then(() => handler(envelope.payload, envelope))\n .then(\n (payload) => {\n assertValid(definition.responseChannel, definition.response, payload);\n options.bus.emit(definition.responseChannel, {\n ...base(definition.responseChannel, definition.responseKind, createMessageId(), envelope.messageId),\n payload,\n });\n },\n (error) => {\n options.bus.emit(definition.errorChannel, {\n ...base(definition.errorChannel, 'error', createMessageId(), envelope.messageId),\n payload: asProtocolError(error),\n });\n },\n );\n });\n },\n };\n}\n"],"mappings":"iFAGA,MAAa,EAA2B,CACtC,QAAS,UACT,eAAgB,kBAChB,cAAe,iBACf,QAAS,SACX,EAUa,EAAsB,EAAK,OACtC,CACE,KAAM,EAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EAClC,QAAS,EAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EACrC,UAAW,EAAK,SAAS,EAAK,QAAQ,CAAC,CACzC,EACA,CAAE,qBAAsB,EAAM,CAChC,EAIA,IAAa,EAAb,cAAuC,KAAM,CAC3C,KACA,UAEA,YAAY,EAA+B,CACzC,MAAM,EAAQ,OAAO,EACrB,KAAK,KAAO,oBACZ,KAAK,KAAO,EAAQ,KACpB,KAAK,UAAY,EAAQ,WAAa,EACxC,CACF,EAEa,EAAb,cAAiD,CAAkB,CACjE,YAAY,EAAiB,EAAiB,CAC5C,MAAM,CAAE,KAAM,EAAyB,eAAgB,QAAS,sBAAsB,EAAQ,IAAI,GAAU,CAAC,EAC7G,KAAK,KAAO,6BACd,CACF,EA6DA,MAAM,EAAqB,EAAK,OAC9B,CACE,SAAU,EAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EACtC,QAAS,EAAK,QAAQ,CAAC,EACvB,KAAM,EAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EAClC,UAAW,EAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EACvC,cAAe,EAAK,SAAS,EAAK,OAAO,CAAE,UAAW,CAAE,CAAC,CAAC,EAC1D,OAAQ,EAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EACpC,UAAW,EAAK,OAAO,CAAE,UAAW,CAAE,CAAC,CACzC,EACA,CAAE,qBAAsB,EAAM,CAChC,EAEA,SAAS,EAAyC,EAAmB,CACnE,OAAO,EAAK,OAAO,CAAE,GAAG,EAAmB,WAAY,SAAQ,EAAG,CAAE,qBAAsB,EAAM,CAAC,CACnG,CAEA,SAAS,EAAa,EAAyB,CAC7C,IAAM,EAAQ,iCAAiC,KAAK,CAAO,EAC3D,GAAI,CAAC,EAAO,MAAU,MAAM,kCAAkC,GAAS,EACvE,OAAO,EAAM,EACf,CAEA,SAAS,EAAkB,EAAiB,EAAwB,CAClE,OAAO,EAAO,EAAQ,CAAK,CAAC,CACzB,MAAM,EAAG,CAAC,CAAC,CACX,IAAK,GAAU,GAAG,EAAM,cAAgB,IAAI,GAAG,EAAM,SAAS,CAAC,CAC/D,KAAK,IAAI,CACd,CAEA,SAAS,EACP,EACA,EACA,EACuC,CACvC,GAAI,CAAC,EAAM,EAAQ,CAAK,EAAG,MAAM,IAAI,EAA4B,EAAS,EAAkB,EAAQ,CAAK,CAAC,CAC5G,CAEA,SAAS,EAAgB,EAAsC,CAI7D,OAHI,aAAiB,EACZ,CAAE,KAAM,EAAM,KAAM,QAAS,EAAM,QAAS,UAAW,EAAM,SAAU,EAEzE,CACL,KAAM,EAAyB,cAC/B,QAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAChE,CACF,CAEA,SAAgB,EAA6C,EAIxB,CAEnC,OADA,EAAa,EAAW,OAAO,EACxB,CACT,CAEA,SAAgB,EAAwE,EASxC,CAC9C,IAAM,EAAW,EAAa,EAAW,SAAS,OAAO,EACzD,IAAK,IAAM,IAAW,CAAC,EAAW,SAAS,SAAU,EAAW,SAAS,KAAK,EAC5E,GAAI,EAAa,CAAO,IAAM,EAAU,MAAU,MAAM,gDAAgD,EAE1G,MAAO,CACL,eAAgB,EAAW,SAAS,QACpC,gBAAiB,EAAW,SAAS,SACrC,aAAc,EAAW,SAAS,MAClC,YAAa,EAAW,MAAM,QAC9B,aAAc,EAAW,MAAM,SAC/B,QAAS,EAAW,QACpB,SAAU,EAAW,QACvB,CACF,CAEA,MAAa,EAAY,EAEzB,SAAgB,EAAsB,EAAkD,CACtF,IAAM,EAAiB,EAAQ,kBAAoB,IAC7C,EAAkB,EAAQ,iBAAmB,IAC7C,EAAkB,EAAQ,sBAA0B,GAAG,EAAQ,OAAO,GAAG,OAAO,WAAW,KAE3F,EAAgB,GAAyB,CAC7C,mBAAqB,CACnB,MAAM,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,CAChE,CAAC,CACH,EAEA,SAAS,GAAiD,CACxD,IAAM,EAAU,IAAI,IACpB,MAAQ,IACN,CAAI,EAAQ,IAAI,CAAS,IACzB,EAAQ,IAAI,CAAS,EACjB,EAAQ,KAAO,GAAiB,EAAQ,OAAO,EAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAe,EACnF,GAEX,CAEA,SAAS,EAAK,EAAiB,EAAc,EAAY,EAAgB,EAAG,EAAwB,CAClG,MAAO,CACL,SAAU,EAAa,CAAO,EAC9B,QAAS,EACT,OACA,YACA,GAAI,EAAgB,CAAE,eAAc,EAAI,CAAC,EACzC,OAAQ,EAAQ,OAChB,UAAW,EAAQ,SACrB,CACF,CAEA,MAAO,CACL,OAAiC,EAA8C,EAA2B,CACxG,EAAY,EAAW,QAAS,EAAW,QAAS,CAAO,EAC3D,EAAQ,IAAI,KAAK,EAAW,QAAS,CAAE,GAAG,EAAK,EAAW,QAAS,EAAW,IAAI,EAAG,SAAQ,CAAC,CAChG,EAEA,eACE,EACA,EACA,CACA,IAAM,EAAS,EAAe,EAAW,OAAO,EAC1C,EAAW,EAAe,EAChC,OAAO,EAAQ,IAAI,GAAG,EAAW,QAAU,GAAY,CACrD,EAAY,EAAW,QAAS,EAAQ,CAAO,EAC/C,IAAM,EAAW,EACb,EAAS,YAAc,EAAQ,WAC9B,EAAS,EAAS,SAAS,GAChC,QAAa,QAAQ,EAAQ,EAAS,QAAS,CAAQ,CAAC,CAAC,CAAC,MAAM,CAAY,CAC9E,CAAC,CACH,EAEA,QACE,EACA,EACA,EAAiC,CAAC,EAClC,CACA,EAAY,EAAW,eAAgB,EAAW,QAAS,CAAO,EAClE,IAAM,EAAY,EAAgB,EAC5B,EAAiB,EAAe,EAAW,QAAQ,EACnD,EAAc,EAAe,CAAmB,EACtD,OAAO,IAAI,SAA6C,EAAS,IAAW,CAC1E,IAAI,EAAU,GACR,EAA8B,CAAC,EAC/B,EAAU,GAAuB,CACjC,MACJ,GAAU,GACV,IAAK,IAAM,KAAW,EAAS,OAAO,CAAC,EAAG,EAAQ,EAClD,EAAO,CAFG,CAGZ,EACA,EAAS,KACP,EAAQ,IAAI,GAAG,EAAW,gBAAkB,GAAY,CACtD,EAAY,EAAW,gBAAiB,EAAgB,CAAO,EAC/D,IAAM,EAAW,EACb,EAAS,YAAc,EAAQ,WAC/B,EAAS,gBAAkB,GAC/B,MAAa,EAAQ,EAAS,OAAO,CAAC,CACxC,CAAC,EACD,EAAQ,IAAI,GAAG,EAAW,aAAe,GAAY,CACnD,EAAY,EAAW,aAAc,EAAa,CAAO,EACzD,IAAM,EAAW,EACb,EAAS,YAAc,EAAQ,WAC/B,EAAS,gBAAkB,GAC/B,MAAa,EAAO,IAAI,EAAkB,EAAS,OAAO,CAAC,CAAC,CAC9D,CAAC,CACH,EACA,IAAM,EAAQ,eAEV,MACE,EACE,IAAI,EAAkB,CACpB,KAAM,EAAyB,QAC/B,QAAS,yBAAyB,EAAW,cAC/C,CAAC,CACH,CACF,EACF,EAAe,WAAa,CAC9B,EAEA,GADA,EAAS,SAAW,aAAa,CAAK,CAAC,EACnC,EAAe,OAAQ,CACzB,IAAM,MACJ,MACE,EAAO,IAAI,EAAkB,CAAE,KAAM,EAAyB,QAAS,QAAS,iBAAkB,CAAC,CAAC,CACtG,EAGF,GAFA,EAAe,OAAO,iBAAiB,QAAS,EAAO,CAAE,KAAM,EAAK,CAAC,EACrE,EAAS,SAAW,EAAe,QAAQ,oBAAoB,QAAS,CAAK,CAAC,EAC1E,EAAe,OAAO,QAAS,OAAO,EAAM,CAClD,CACA,EAAQ,IAAI,KAAK,EAAW,eAAgB,CAC1C,GAAG,EAAK,EAAW,eAAgB,EAAW,YAAa,CAAS,EACpE,SACF,CAAC,CACH,CAAC,CACH,EAEA,QACE,EACA,EAIA,CACA,IAAM,EAAgB,EAAe,EAAW,OAAO,EACjD,EAAW,EAAe,EAChC,OAAO,EAAQ,IAAI,GAAG,EAAW,eAAiB,GAAY,CAC5D,EAAY,EAAW,eAAgB,EAAe,CAAO,EAC7D,IAAM,EAAW,EACb,EAAS,YAAc,EAAQ,WAC9B,EAAS,EAAS,SAAS,GAChC,QAAa,QAAQ,CAAC,CACnB,SAAW,EAAQ,EAAS,QAAS,CAAQ,CAAC,CAAC,CAC/C,KACE,GAAY,CACX,EAAY,EAAW,gBAAiB,EAAW,SAAU,CAAO,EACpE,EAAQ,IAAI,KAAK,EAAW,gBAAiB,CAC3C,GAAG,EAAK,EAAW,gBAAiB,EAAW,aAAc,EAAgB,EAAG,EAAS,SAAS,EAClG,SACF,CAAC,CACH,EACC,GAAU,CACT,EAAQ,IAAI,KAAK,EAAW,aAAc,CACxC,GAAG,EAAK,EAAW,aAAc,QAAS,EAAgB,EAAG,EAAS,SAAS,EAC/E,QAAS,EAAgB,CAAK,CAChC,CAAC,CACH,CACF,CACJ,CAAC,CACH,CACF,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./protocol.cjs");let t=require("typebox");const n=t.Type.String({minLength:1,maxLength:128,pattern:`^[A-Za-z0-9][A-Za-z0-9._:-]*$`}),r=e.defineRequestReply({channels:{request:`doom:runner:pty:v1:launch`,response:`doom:runner:pty:v1:launched`,error:`doom:runner:pty:v1:error`},kinds:{request:`runner-pty.launch`,response:`runner-pty.launched`},request:t.Type.Object({id:n,name:t.Type.String({minLength:1,maxLength:64}),command:t.Type.String({minLength:1,maxLength:4096}),cwd:t.Type.String({minLength:1,maxLength:4096}),cols:t.Type.Optional(t.Type.Integer({minimum:20,maximum:500})),rows:t.Type.Optional(t.Type.Integer({minimum:5,maximum:200}))},{additionalProperties:!1}),response:t.Type.Object({launched:t.Type.Boolean(),reason:t.Type.Optional(t.Type.String({minLength:1,maxLength:240}))},{additionalProperties:!1})}),i=e.defineNotification({channel:`doom:runner:pty:v1:data`,kind:`runner-pty.data`,payload:t.Type.Object({id:n,chunk:t.Type.String({maxLength:65536})},{additionalProperties:!1})}),a=e.defineNotification({channel:`doom:runner:pty:v1:exit`,kind:`runner-pty.exit`,payload:t.Type.Object({id:n,code:t.Type.Optional(t.Type.Integer({minimum:-1,maximum:255})),signal:t.Type.Optional(t.Type.String({minLength:1,maxLength:32}))},{additionalProperties:!1})}),o=e.defineNotification({channel:`doom:runner:pty:v1:input`,kind:`runner-pty.input`,payload:t.Type.Object({id:n,text:t.Type.String({maxLength:4096})},{additionalProperties:!1})}),s=e.defineNotification({channel:`doom:runner:pty:v1:stop`,kind:`runner-pty.stop`,payload:t.Type.Object({id:n},{additionalProperties:!1})});exports.RunnerPtyData=i,exports.RunnerPtyExit=a,exports.RunnerPtyInput=o,exports.RunnerPtyLaunchProtocol=r,exports.RunnerPtyStop=s;
|
|
2
|
+
//# sourceMappingURL=runnerPty.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runnerPty.cjs","names":["Type","defineRequestReply","defineNotification"],"sources":["../src/runnerPty.ts"],"sourcesContent":["/**\n * Borrowing a pseudo terminal from doom-runner.\n *\n * Some extensions need to run a command the user has to watch and answer:\n * a package install that asks to proceed, a tool that wants a sudo password.\n * Buffered `spawn` cannot do that, and every extension growing its own pty would\n * mean every extension carrying a native module for it.\n *\n * doom-runner already owns that machinery, so this hands the job to it: the\n * caller asks for a command, receives the terminal's output as it arrives, and\n * can type back into it. The terminal lives and dies with the runner's session,\n * which is what stops an install outliving the window it was started from.\n *\n * The command runs through a login shell, so PATH matches what the user gets in\n * their own terminal. That is the point for installers: `brew` is frequently\n * only on PATH through a profile script.\n */\n\nimport { type Static, Type } from 'typebox';\nimport { defineNotification, defineRequestReply } from './protocol.ts';\n\n/** Caller-chosen and unique to the caller, since the host keys every message by it. */\nconst RunIdSchema = Type.String({ minLength: 1, maxLength: 128, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]*$' });\n\nexport const RunnerPtyLaunchProtocol = defineRequestReply({\n channels: {\n request: 'doom:runner:pty:v1:launch',\n response: 'doom:runner:pty:v1:launched',\n error: 'doom:runner:pty:v1:error',\n },\n kinds: { request: 'runner-pty.launch', response: 'runner-pty.launched' },\n request: Type.Object(\n {\n id: RunIdSchema,\n /** Shown in the runner list, so it should read as a task rather than a command. */\n name: Type.String({ minLength: 1, maxLength: 64 }),\n command: Type.String({ minLength: 1, maxLength: 4096 }),\n cwd: Type.String({ minLength: 1, maxLength: 4096 }),\n cols: Type.Optional(Type.Integer({ minimum: 20, maximum: 500 })),\n rows: Type.Optional(Type.Integer({ minimum: 5, maximum: 200 })),\n },\n { additionalProperties: false },\n ),\n response: Type.Object(\n {\n launched: Type.Boolean(),\n /** Why not, when the host has no pty available. */\n reason: Type.Optional(Type.String({ minLength: 1, maxLength: 240 })),\n },\n { additionalProperties: false },\n ),\n});\n\n/** Terminal output as it arrives. Chunks are raw, so they may split mid-line. */\nexport const RunnerPtyData = defineNotification({\n channel: 'doom:runner:pty:v1:data',\n kind: 'runner-pty.data',\n payload: Type.Object({ id: RunIdSchema, chunk: Type.String({ maxLength: 65_536 }) }, { additionalProperties: false }),\n});\n\nexport const RunnerPtyExit = defineNotification({\n channel: 'doom:runner:pty:v1:exit',\n kind: 'runner-pty.exit',\n payload: Type.Object(\n {\n id: RunIdSchema,\n code: Type.Optional(Type.Integer({ minimum: -1, maximum: 255 })),\n signal: Type.Optional(Type.String({ minLength: 1, maxLength: 32 })),\n },\n { additionalProperties: false },\n ),\n});\n\n/** Types into the terminal. The host appends the newline. */\nexport const RunnerPtyInput = defineNotification({\n channel: 'doom:runner:pty:v1:input',\n kind: 'runner-pty.input',\n payload: Type.Object({ id: RunIdSchema, text: Type.String({ maxLength: 4096 }) }, { additionalProperties: false }),\n});\n\nexport const RunnerPtyStop = defineNotification({\n channel: 'doom:runner:pty:v1:stop',\n kind: 'runner-pty.stop',\n payload: Type.Object({ id: RunIdSchema }, { additionalProperties: false }),\n});\n\nexport type RunnerPtyLaunchRequest = Static<typeof RunnerPtyLaunchProtocol.request>;\nexport type RunnerPtyLaunchResponse = Static<typeof RunnerPtyLaunchProtocol.response>;\n"],"mappings":"8HAsBA,MAAM,EAAcA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAG,UAAW,IAAK,QAAS,+BAAgC,CAAC,EAE7F,EAA0BC,EAAAA,mBAAmB,CACxD,SAAU,CACR,QAAS,4BACT,SAAU,8BACV,MAAO,0BACT,EACA,MAAO,CAAE,QAAS,oBAAqB,SAAU,qBAAsB,EACvE,QAASD,EAAAA,KAAK,OACZ,CACE,GAAI,EAEJ,KAAMA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAG,UAAW,EAAG,CAAC,EACjD,QAASA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAG,UAAW,IAAK,CAAC,EACtD,IAAKA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAG,UAAW,IAAK,CAAC,EAClD,KAAMA,EAAAA,KAAK,SAASA,EAAAA,KAAK,QAAQ,CAAE,QAAS,GAAI,QAAS,GAAI,CAAC,CAAC,EAC/D,KAAMA,EAAAA,KAAK,SAASA,EAAAA,KAAK,QAAQ,CAAE,QAAS,EAAG,QAAS,GAAI,CAAC,CAAC,CAChE,EACA,CAAE,qBAAsB,EAAM,CAChC,EACA,SAAUA,EAAAA,KAAK,OACb,CACE,SAAUA,EAAAA,KAAK,QAAQ,EAEvB,OAAQA,EAAAA,KAAK,SAASA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAG,UAAW,GAAI,CAAC,CAAC,CACrE,EACA,CAAE,qBAAsB,EAAM,CAChC,CACF,CAAC,EAGY,EAAgBE,EAAAA,mBAAmB,CAC9C,QAAS,0BACT,KAAM,kBACN,QAASF,EAAAA,KAAK,OAAO,CAAE,GAAI,EAAa,MAAOA,EAAAA,KAAK,OAAO,CAAE,UAAW,KAAO,CAAC,CAAE,EAAG,CAAE,qBAAsB,EAAM,CAAC,CACtH,CAAC,EAEY,EAAgBE,EAAAA,mBAAmB,CAC9C,QAAS,0BACT,KAAM,kBACN,QAASF,EAAAA,KAAK,OACZ,CACE,GAAI,EACJ,KAAMA,EAAAA,KAAK,SAASA,EAAAA,KAAK,QAAQ,CAAE,QAAS,GAAI,QAAS,GAAI,CAAC,CAAC,EAC/D,OAAQA,EAAAA,KAAK,SAASA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAG,UAAW,EAAG,CAAC,CAAC,CACpE,EACA,CAAE,qBAAsB,EAAM,CAChC,CACF,CAAC,EAGY,EAAiBE,EAAAA,mBAAmB,CAC/C,QAAS,2BACT,KAAM,mBACN,QAASF,EAAAA,KAAK,OAAO,CAAE,GAAI,EAAa,KAAMA,EAAAA,KAAK,OAAO,CAAE,UAAW,IAAK,CAAC,CAAE,EAAG,CAAE,qBAAsB,EAAM,CAAC,CACnH,CAAC,EAEY,EAAgBE,EAAAA,mBAAmB,CAC9C,QAAS,0BACT,KAAM,kBACN,QAASF,EAAAA,KAAK,OAAO,CAAE,GAAI,CAAY,EAAG,CAAE,qBAAsB,EAAM,CAAC,CAC3E,CAAC"}
|