@pellux/goodvibes-sdk 0.33.5 → 0.33.7

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 CHANGED
@@ -32,6 +32,8 @@ Entry points:
32
32
  - `@pellux/goodvibes-sdk/peer`
33
33
  - `@pellux/goodvibes-sdk/contracts`
34
34
  - `@pellux/goodvibes-sdk/browser`
35
+ - `@pellux/goodvibes-sdk/browser/knowledge`
36
+ - `@pellux/goodvibes-sdk/browser/homeassistant`
35
37
  - `@pellux/goodvibes-sdk/web`
36
38
  - `@pellux/goodvibes-sdk/workers`
37
39
  - `@pellux/goodvibes-sdk/react-native`
@@ -0,0 +1,118 @@
1
+ import type { OperatorMethodInput, OperatorMethodOutput, OperatorTypedMethodId } from '@pellux/goodvibes-contracts/generated/foundation-client-types';
2
+ import { forScopedBrowserSession, type ScopedBrowserSdk, type ScopedBrowserSdkOptions, type SharedBrowserMethodId } from './browser-scoped.js';
3
+ declare const HOME_ASSISTANT_BROWSER_ROUTES: {
4
+ readonly 'homeassistant.homeGraph.askHomeGraph': {
5
+ readonly method: "POST";
6
+ readonly path: "/api/homeassistant/home-graph/ask";
7
+ };
8
+ readonly 'homeassistant.homeGraph.browse': {
9
+ readonly method: "GET";
10
+ readonly path: "/api/homeassistant/home-graph/browse";
11
+ };
12
+ readonly 'homeassistant.homeGraph.export': {
13
+ readonly method: "POST";
14
+ readonly path: "/api/homeassistant/home-graph/export";
15
+ };
16
+ readonly 'homeassistant.homeGraph.generateHomeGraphPacket': {
17
+ readonly method: "POST";
18
+ readonly path: "/api/homeassistant/home-graph/packet";
19
+ };
20
+ readonly 'homeassistant.homeGraph.generateRoomPage': {
21
+ readonly method: "POST";
22
+ readonly path: "/api/homeassistant/home-graph/room-page";
23
+ };
24
+ readonly 'homeassistant.homeGraph.import': {
25
+ readonly method: "POST";
26
+ readonly path: "/api/homeassistant/home-graph/import";
27
+ };
28
+ readonly 'homeassistant.homeGraph.ingestHomeGraphArtifact': {
29
+ readonly method: "POST";
30
+ readonly path: "/api/homeassistant/home-graph/ingest/artifact";
31
+ };
32
+ readonly 'homeassistant.homeGraph.ingestHomeGraphNote': {
33
+ readonly method: "POST";
34
+ readonly path: "/api/homeassistant/home-graph/ingest/note";
35
+ };
36
+ readonly 'homeassistant.homeGraph.ingestHomeGraphUrl': {
37
+ readonly method: "POST";
38
+ readonly path: "/api/homeassistant/home-graph/ingest/url";
39
+ };
40
+ readonly 'homeassistant.homeGraph.linkHomeGraphKnowledge': {
41
+ readonly method: "POST";
42
+ readonly path: "/api/homeassistant/home-graph/link";
43
+ };
44
+ readonly 'homeassistant.homeGraph.listHomeGraphIssues': {
45
+ readonly method: "GET";
46
+ readonly path: "/api/homeassistant/home-graph/issues";
47
+ };
48
+ readonly 'homeassistant.homeGraph.map': {
49
+ readonly method: "POST";
50
+ readonly path: "/api/homeassistant/home-graph/map";
51
+ };
52
+ readonly 'homeassistant.homeGraph.pages.list': {
53
+ readonly method: "GET";
54
+ readonly path: "/api/homeassistant/home-graph/pages";
55
+ };
56
+ readonly 'homeassistant.homeGraph.refinement.run': {
57
+ readonly method: "POST";
58
+ readonly path: "/api/homeassistant/home-graph/refinement/run";
59
+ };
60
+ readonly 'homeassistant.homeGraph.refinement.task.cancel': {
61
+ readonly method: "POST";
62
+ readonly path: "/api/homeassistant/home-graph/refinement/tasks/{id}/cancel";
63
+ };
64
+ readonly 'homeassistant.homeGraph.refinement.task.get': {
65
+ readonly method: "GET";
66
+ readonly path: "/api/homeassistant/home-graph/refinement/tasks/{id}";
67
+ };
68
+ readonly 'homeassistant.homeGraph.refinement.tasks.list': {
69
+ readonly method: "GET";
70
+ readonly path: "/api/homeassistant/home-graph/refinement/tasks";
71
+ };
72
+ readonly 'homeassistant.homeGraph.refreshDevicePassport': {
73
+ readonly method: "POST";
74
+ readonly path: "/api/homeassistant/home-graph/device-passport";
75
+ };
76
+ readonly 'homeassistant.homeGraph.reindex': {
77
+ readonly method: "POST";
78
+ readonly path: "/api/homeassistant/home-graph/reindex";
79
+ };
80
+ readonly 'homeassistant.homeGraph.reset': {
81
+ readonly method: "POST";
82
+ readonly path: "/api/homeassistant/home-graph/reset";
83
+ };
84
+ readonly 'homeassistant.homeGraph.reviewHomeGraphFact': {
85
+ readonly method: "POST";
86
+ readonly path: "/api/homeassistant/home-graph/facts/review";
87
+ };
88
+ readonly 'homeassistant.homeGraph.sources.list': {
89
+ readonly method: "GET";
90
+ readonly path: "/api/homeassistant/home-graph/sources";
91
+ };
92
+ readonly 'homeassistant.homeGraph.status': {
93
+ readonly method: "GET";
94
+ readonly path: "/api/homeassistant/home-graph/status";
95
+ };
96
+ readonly 'homeassistant.homeGraph.syncHomeGraph': {
97
+ readonly method: "POST";
98
+ readonly path: "/api/homeassistant/home-graph/sync";
99
+ };
100
+ readonly 'homeassistant.homeGraph.unlinkHomeGraphKnowledge': {
101
+ readonly method: "POST";
102
+ readonly path: "/api/homeassistant/home-graph/unlink";
103
+ };
104
+ };
105
+ declare const HOME_ASSISTANT_BROWSER_DOMAINS: readonly ["session", "turn", "tasks", "providers", "surfaces", "routes", "knowledge", "control-plane"];
106
+ export type BrowserHomeAssistantMethodId = SharedBrowserMethodId | Extract<keyof typeof HOME_ASSISTANT_BROWSER_ROUTES, OperatorTypedMethodId>;
107
+ export type BrowserHomeAssistantDomain = typeof HOME_ASSISTANT_BROWSER_DOMAINS[number];
108
+ export interface BrowserHomeAssistantSdk extends ScopedBrowserSdk<BrowserHomeAssistantMethodId, BrowserHomeAssistantDomain> {
109
+ readonly homeGraph: {
110
+ status(input?: OperatorMethodInput<'homeassistant.homeGraph.status'>): Promise<OperatorMethodOutput<'homeassistant.homeGraph.status'>>;
111
+ ask(input: OperatorMethodInput<'homeassistant.homeGraph.askHomeGraph'>): Promise<OperatorMethodOutput<'homeassistant.homeGraph.askHomeGraph'>>;
112
+ map(input?: OperatorMethodInput<'homeassistant.homeGraph.map'>): Promise<OperatorMethodOutput<'homeassistant.homeGraph.map'>>;
113
+ pages(input?: OperatorMethodInput<'homeassistant.homeGraph.pages.list'>): Promise<OperatorMethodOutput<'homeassistant.homeGraph.pages.list'>>;
114
+ };
115
+ }
116
+ export declare function createBrowserHomeAssistantSdk(options?: ScopedBrowserSdkOptions): BrowserHomeAssistantSdk;
117
+ export { forScopedBrowserSession as forSession };
118
+ //# sourceMappingURL=browser-homeassistant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-homeassistant.d.ts","sourceRoot":"","sources":["../src/browser-homeassistant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,+DAA+D,CAAC;AACvE,OAAO,EAEL,uBAAuB,EAGvB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BsD,CAAC;AAE1F,QAAA,MAAM,8BAA8B,wGAS1B,CAAC;AAEX,MAAM,MAAM,4BAA4B,GACpC,qBAAqB,GACrB,OAAO,CAAC,MAAM,OAAO,6BAA6B,EAAE,qBAAqB,CAAC,CAAC;AAE/E,MAAM,MAAM,0BAA0B,GAAG,OAAO,8BAA8B,CAAC,MAAM,CAAC,CAAC;AAEvF,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB,CAAC,4BAA4B,EAAE,0BAA0B,CAAC;IACzH,QAAQ,CAAC,SAAS,EAAE;QAClB,MAAM,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,gCAAgC,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,gCAAgC,CAAC,CAAC,CAAC;QACvI,GAAG,CAAC,KAAK,EAAE,mBAAmB,CAAC,sCAAsC,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAC/I,GAAG,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,6BAA6B,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,6BAA6B,CAAC,CAAC,CAAC;QAC9H,KAAK,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,oCAAoC,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,oCAAoC,CAAC,CAAC,CAAC;KAC/I,CAAC;CACH;AAED,wBAAgB,6BAA6B,CAAC,OAAO,GAAE,uBAA4B,GAAG,uBAAuB,CAkB5G;AAED,OAAO,EAAE,uBAAuB,IAAI,UAAU,EAAE,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { createScopedBrowserSdk, forScopedBrowserSession, SHARED_BROWSER_ROUTES, } from './browser-scoped.js';
2
+ const HOME_ASSISTANT_BROWSER_ROUTES = {
3
+ 'homeassistant.homeGraph.askHomeGraph': { method: 'POST', path: '/api/homeassistant/home-graph/ask' },
4
+ 'homeassistant.homeGraph.browse': { method: 'GET', path: '/api/homeassistant/home-graph/browse' },
5
+ 'homeassistant.homeGraph.export': { method: 'POST', path: '/api/homeassistant/home-graph/export' },
6
+ 'homeassistant.homeGraph.generateHomeGraphPacket': { method: 'POST', path: '/api/homeassistant/home-graph/packet' },
7
+ 'homeassistant.homeGraph.generateRoomPage': { method: 'POST', path: '/api/homeassistant/home-graph/room-page' },
8
+ 'homeassistant.homeGraph.import': { method: 'POST', path: '/api/homeassistant/home-graph/import' },
9
+ 'homeassistant.homeGraph.ingestHomeGraphArtifact': { method: 'POST', path: '/api/homeassistant/home-graph/ingest/artifact' },
10
+ 'homeassistant.homeGraph.ingestHomeGraphNote': { method: 'POST', path: '/api/homeassistant/home-graph/ingest/note' },
11
+ 'homeassistant.homeGraph.ingestHomeGraphUrl': { method: 'POST', path: '/api/homeassistant/home-graph/ingest/url' },
12
+ 'homeassistant.homeGraph.linkHomeGraphKnowledge': { method: 'POST', path: '/api/homeassistant/home-graph/link' },
13
+ 'homeassistant.homeGraph.listHomeGraphIssues': { method: 'GET', path: '/api/homeassistant/home-graph/issues' },
14
+ 'homeassistant.homeGraph.map': { method: 'POST', path: '/api/homeassistant/home-graph/map' },
15
+ 'homeassistant.homeGraph.pages.list': { method: 'GET', path: '/api/homeassistant/home-graph/pages' },
16
+ 'homeassistant.homeGraph.refinement.run': { method: 'POST', path: '/api/homeassistant/home-graph/refinement/run' },
17
+ 'homeassistant.homeGraph.refinement.task.cancel': { method: 'POST', path: '/api/homeassistant/home-graph/refinement/tasks/{id}/cancel' },
18
+ 'homeassistant.homeGraph.refinement.task.get': { method: 'GET', path: '/api/homeassistant/home-graph/refinement/tasks/{id}' },
19
+ 'homeassistant.homeGraph.refinement.tasks.list': { method: 'GET', path: '/api/homeassistant/home-graph/refinement/tasks' },
20
+ 'homeassistant.homeGraph.refreshDevicePassport': { method: 'POST', path: '/api/homeassistant/home-graph/device-passport' },
21
+ 'homeassistant.homeGraph.reindex': { method: 'POST', path: '/api/homeassistant/home-graph/reindex' },
22
+ 'homeassistant.homeGraph.reset': { method: 'POST', path: '/api/homeassistant/home-graph/reset' },
23
+ 'homeassistant.homeGraph.reviewHomeGraphFact': { method: 'POST', path: '/api/homeassistant/home-graph/facts/review' },
24
+ 'homeassistant.homeGraph.sources.list': { method: 'GET', path: '/api/homeassistant/home-graph/sources' },
25
+ 'homeassistant.homeGraph.status': { method: 'GET', path: '/api/homeassistant/home-graph/status' },
26
+ 'homeassistant.homeGraph.syncHomeGraph': { method: 'POST', path: '/api/homeassistant/home-graph/sync' },
27
+ 'homeassistant.homeGraph.unlinkHomeGraphKnowledge': { method: 'POST', path: '/api/homeassistant/home-graph/unlink' },
28
+ };
29
+ const HOME_ASSISTANT_BROWSER_DOMAINS = [
30
+ 'session',
31
+ 'turn',
32
+ 'tasks',
33
+ 'providers',
34
+ 'surfaces',
35
+ 'routes',
36
+ 'knowledge',
37
+ 'control-plane',
38
+ ];
39
+ export function createBrowserHomeAssistantSdk(options = {}) {
40
+ const sdk = createScopedBrowserSdk({
41
+ ...SHARED_BROWSER_ROUTES,
42
+ ...HOME_ASSISTANT_BROWSER_ROUTES,
43
+ }, HOME_ASSISTANT_BROWSER_DOMAINS, options);
44
+ return {
45
+ ...sdk,
46
+ homeGraph: {
47
+ status: (input = {}) => sdk.operator.invoke('homeassistant.homeGraph.status', input),
48
+ ask: (input) => sdk.operator.invoke('homeassistant.homeGraph.askHomeGraph', input),
49
+ map: (input = {}) => sdk.operator.invoke('homeassistant.homeGraph.map', input),
50
+ pages: (input = {}) => sdk.operator.invoke('homeassistant.homeGraph.pages.list', input),
51
+ },
52
+ };
53
+ }
54
+ export { forScopedBrowserSession as forSession };
@@ -0,0 +1,210 @@
1
+ import type { OperatorMethodInput, OperatorMethodOutput, OperatorTypedMethodId } from '@pellux/goodvibes-contracts/generated/foundation-client-types';
2
+ import { forScopedBrowserSession, type ScopedBrowserSdk, type ScopedBrowserSdkOptions, type SharedBrowserMethodId } from './browser-scoped.js';
3
+ declare const KNOWLEDGE_BROWSER_ROUTES: {
4
+ readonly 'knowledge.ask': {
5
+ readonly method: "POST";
6
+ readonly path: "/api/knowledge/ask";
7
+ };
8
+ readonly 'knowledge.candidate.decide': {
9
+ readonly method: "POST";
10
+ readonly path: "/api/knowledge/candidates/{id}/decide";
11
+ };
12
+ readonly 'knowledge.candidate.get': {
13
+ readonly method: "GET";
14
+ readonly path: "/api/knowledge/candidates/{id}";
15
+ };
16
+ readonly 'knowledge.candidates.list': {
17
+ readonly method: "GET";
18
+ readonly path: "/api/knowledge/candidates";
19
+ };
20
+ readonly 'knowledge.connector.doctor': {
21
+ readonly method: "GET";
22
+ readonly path: "/api/knowledge/connectors/{id}/doctor";
23
+ };
24
+ readonly 'knowledge.connector.get': {
25
+ readonly method: "GET";
26
+ readonly path: "/api/knowledge/connectors/{id}";
27
+ };
28
+ readonly 'knowledge.connectors.list': {
29
+ readonly method: "GET";
30
+ readonly path: "/api/knowledge/connectors";
31
+ };
32
+ readonly 'knowledge.extraction.get': {
33
+ readonly method: "GET";
34
+ readonly path: "/api/knowledge/extractions/{id}";
35
+ };
36
+ readonly 'knowledge.extractions.list': {
37
+ readonly method: "GET";
38
+ readonly path: "/api/knowledge/extractions";
39
+ };
40
+ readonly 'knowledge.graphql.execute': {
41
+ readonly method: "POST";
42
+ readonly path: "/api/knowledge/graphql";
43
+ };
44
+ readonly 'knowledge.graphql.schema': {
45
+ readonly method: "GET";
46
+ readonly path: "/api/knowledge/graphql/schema";
47
+ };
48
+ readonly 'knowledge.ingest.artifact': {
49
+ readonly method: "POST";
50
+ readonly path: "/api/knowledge/ingest/artifact";
51
+ };
52
+ readonly 'knowledge.ingest.bookmarks': {
53
+ readonly method: "POST";
54
+ readonly path: "/api/knowledge/ingest/bookmarks";
55
+ };
56
+ readonly 'knowledge.ingest.browserHistory': {
57
+ readonly method: "POST";
58
+ readonly path: "/api/knowledge/ingest/browser-history";
59
+ };
60
+ readonly 'knowledge.ingest.connector': {
61
+ readonly method: "POST";
62
+ readonly path: "/api/knowledge/ingest/connector";
63
+ };
64
+ readonly 'knowledge.ingest.url': {
65
+ readonly method: "POST";
66
+ readonly path: "/api/knowledge/ingest/url";
67
+ };
68
+ readonly 'knowledge.ingest.urls': {
69
+ readonly method: "POST";
70
+ readonly path: "/api/knowledge/ingest/urls";
71
+ };
72
+ readonly 'knowledge.issue.review': {
73
+ readonly method: "POST";
74
+ readonly path: "/api/knowledge/issues/{id}/review";
75
+ };
76
+ readonly 'knowledge.issues.list': {
77
+ readonly method: "GET";
78
+ readonly path: "/api/knowledge/issues";
79
+ };
80
+ readonly 'knowledge.item.get': {
81
+ readonly method: "GET";
82
+ readonly path: "/api/knowledge/items/{id}";
83
+ };
84
+ readonly 'knowledge.job-runs.list': {
85
+ readonly method: "GET";
86
+ readonly path: "/api/knowledge/job-runs";
87
+ };
88
+ readonly 'knowledge.job.get': {
89
+ readonly method: "GET";
90
+ readonly path: "/api/knowledge/jobs/{jobId}";
91
+ };
92
+ readonly 'knowledge.job.run': {
93
+ readonly method: "POST";
94
+ readonly path: "/api/knowledge/jobs/{jobId}/run";
95
+ };
96
+ readonly 'knowledge.jobs.list': {
97
+ readonly method: "GET";
98
+ readonly path: "/api/knowledge/jobs";
99
+ };
100
+ readonly 'knowledge.lint': {
101
+ readonly method: "POST";
102
+ readonly path: "/api/knowledge/lint";
103
+ };
104
+ readonly 'knowledge.map': {
105
+ readonly method: "GET";
106
+ readonly path: "/api/knowledge/map";
107
+ };
108
+ readonly 'knowledge.nodes.list': {
109
+ readonly method: "GET";
110
+ readonly path: "/api/knowledge/nodes";
111
+ };
112
+ readonly 'knowledge.packet': {
113
+ readonly method: "POST";
114
+ readonly path: "/api/knowledge/packet";
115
+ };
116
+ readonly 'knowledge.projection.materialize': {
117
+ readonly method: "POST";
118
+ readonly path: "/api/knowledge/projections/materialize";
119
+ };
120
+ readonly 'knowledge.projection.render': {
121
+ readonly method: "POST";
122
+ readonly path: "/api/knowledge/projections/render";
123
+ };
124
+ readonly 'knowledge.projections.list': {
125
+ readonly method: "GET";
126
+ readonly path: "/api/knowledge/projections";
127
+ };
128
+ readonly 'knowledge.refinement.run': {
129
+ readonly method: "POST";
130
+ readonly path: "/api/knowledge/refinement/run";
131
+ };
132
+ readonly 'knowledge.refinement.task.cancel': {
133
+ readonly method: "POST";
134
+ readonly path: "/api/knowledge/refinement/tasks/{id}/cancel";
135
+ };
136
+ readonly 'knowledge.refinement.task.get': {
137
+ readonly method: "GET";
138
+ readonly path: "/api/knowledge/refinement/tasks/{id}";
139
+ };
140
+ readonly 'knowledge.refinement.tasks.list': {
141
+ readonly method: "GET";
142
+ readonly path: "/api/knowledge/refinement/tasks";
143
+ };
144
+ readonly 'knowledge.reindex': {
145
+ readonly method: "POST";
146
+ readonly path: "/api/knowledge/reindex";
147
+ };
148
+ readonly 'knowledge.report.get': {
149
+ readonly method: "GET";
150
+ readonly path: "/api/knowledge/reports/{id}";
151
+ };
152
+ readonly 'knowledge.reports.list': {
153
+ readonly method: "GET";
154
+ readonly path: "/api/knowledge/reports";
155
+ };
156
+ readonly 'knowledge.schedule.delete': {
157
+ readonly method: "DELETE";
158
+ readonly path: "/api/knowledge/schedules/{id}";
159
+ };
160
+ readonly 'knowledge.schedule.enable': {
161
+ readonly method: "POST";
162
+ readonly path: "/api/knowledge/schedules/{id}/enabled";
163
+ };
164
+ readonly 'knowledge.schedule.get': {
165
+ readonly method: "GET";
166
+ readonly path: "/api/knowledge/schedules/{id}";
167
+ };
168
+ readonly 'knowledge.schedule.save': {
169
+ readonly method: "POST";
170
+ readonly path: "/api/knowledge/schedules";
171
+ };
172
+ readonly 'knowledge.schedules.list': {
173
+ readonly method: "GET";
174
+ readonly path: "/api/knowledge/schedules";
175
+ };
176
+ readonly 'knowledge.search': {
177
+ readonly method: "POST";
178
+ readonly path: "/api/knowledge/search";
179
+ };
180
+ readonly 'knowledge.source.extraction.get': {
181
+ readonly method: "GET";
182
+ readonly path: "/api/knowledge/sources/{id}/extraction";
183
+ };
184
+ readonly 'knowledge.sources.list': {
185
+ readonly method: "GET";
186
+ readonly path: "/api/knowledge/sources";
187
+ };
188
+ readonly 'knowledge.status': {
189
+ readonly method: "GET";
190
+ readonly path: "/api/knowledge/status";
191
+ };
192
+ readonly 'knowledge.usage.list': {
193
+ readonly method: "GET";
194
+ readonly path: "/api/knowledge/usage";
195
+ };
196
+ };
197
+ declare const KNOWLEDGE_BROWSER_DOMAINS: readonly ["session", "turn", "tasks", "providers", "knowledge", "control-plane"];
198
+ export type BrowserKnowledgeMethodId = SharedBrowserMethodId | Extract<keyof typeof KNOWLEDGE_BROWSER_ROUTES, OperatorTypedMethodId>;
199
+ export type BrowserKnowledgeDomain = typeof KNOWLEDGE_BROWSER_DOMAINS[number];
200
+ export interface BrowserKnowledgeSdk extends ScopedBrowserSdk<BrowserKnowledgeMethodId, BrowserKnowledgeDomain> {
201
+ readonly knowledge: {
202
+ ask(input: OperatorMethodInput<'knowledge.ask'>): Promise<OperatorMethodOutput<'knowledge.ask'>>;
203
+ search(input: OperatorMethodInput<'knowledge.search'>): Promise<OperatorMethodOutput<'knowledge.search'>>;
204
+ status(): Promise<OperatorMethodOutput<'knowledge.status'>>;
205
+ map(input?: OperatorMethodInput<'knowledge.map'>): Promise<OperatorMethodOutput<'knowledge.map'>>;
206
+ };
207
+ }
208
+ export declare function createBrowserKnowledgeSdk(options?: ScopedBrowserSdkOptions): BrowserKnowledgeSdk;
209
+ export { forScopedBrowserSession as forSession };
210
+ //# sourceMappingURL=browser-knowledge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-knowledge.d.ts","sourceRoot":"","sources":["../src/browser-knowledge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,+DAA+D,CAAC;AACvE,OAAO,EAEL,uBAAuB,EAGvB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAC;AAE7B,QAAA,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiD2D,CAAC;AAE1F,QAAA,MAAM,yBAAyB,kFAOrB,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAChC,qBAAqB,GACrB,OAAO,CAAC,MAAM,OAAO,wBAAwB,EAAE,qBAAqB,CAAC,CAAC;AAE1E,MAAM,MAAM,sBAAsB,GAAG,OAAO,yBAAyB,CAAC,MAAM,CAAC,CAAC;AAE9E,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB,CAAC,wBAAwB,EAAE,sBAAsB,CAAC;IAC7G,QAAQ,CAAC,SAAS,EAAE;QAClB,GAAG,CAAC,KAAK,EAAE,mBAAmB,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC,CAAC;QACjG,MAAM,CAAC,KAAK,EAAE,mBAAmB,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC1G,MAAM,IAAI,OAAO,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC5D,GAAG,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC,CAAC;KACnG,CAAC;CACH;AAED,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,uBAA4B,GAAG,mBAAmB,CAkBpG;AAED,OAAO,EAAE,uBAAuB,IAAI,UAAU,EAAE,CAAC"}
@@ -0,0 +1,75 @@
1
+ import { createScopedBrowserSdk, forScopedBrowserSession, SHARED_BROWSER_ROUTES, } from './browser-scoped.js';
2
+ const KNOWLEDGE_BROWSER_ROUTES = {
3
+ 'knowledge.ask': { method: 'POST', path: '/api/knowledge/ask' },
4
+ 'knowledge.candidate.decide': { method: 'POST', path: '/api/knowledge/candidates/{id}/decide' },
5
+ 'knowledge.candidate.get': { method: 'GET', path: '/api/knowledge/candidates/{id}' },
6
+ 'knowledge.candidates.list': { method: 'GET', path: '/api/knowledge/candidates' },
7
+ 'knowledge.connector.doctor': { method: 'GET', path: '/api/knowledge/connectors/{id}/doctor' },
8
+ 'knowledge.connector.get': { method: 'GET', path: '/api/knowledge/connectors/{id}' },
9
+ 'knowledge.connectors.list': { method: 'GET', path: '/api/knowledge/connectors' },
10
+ 'knowledge.extraction.get': { method: 'GET', path: '/api/knowledge/extractions/{id}' },
11
+ 'knowledge.extractions.list': { method: 'GET', path: '/api/knowledge/extractions' },
12
+ 'knowledge.graphql.execute': { method: 'POST', path: '/api/knowledge/graphql' },
13
+ 'knowledge.graphql.schema': { method: 'GET', path: '/api/knowledge/graphql/schema' },
14
+ 'knowledge.ingest.artifact': { method: 'POST', path: '/api/knowledge/ingest/artifact' },
15
+ 'knowledge.ingest.bookmarks': { method: 'POST', path: '/api/knowledge/ingest/bookmarks' },
16
+ 'knowledge.ingest.browserHistory': { method: 'POST', path: '/api/knowledge/ingest/browser-history' },
17
+ 'knowledge.ingest.connector': { method: 'POST', path: '/api/knowledge/ingest/connector' },
18
+ 'knowledge.ingest.url': { method: 'POST', path: '/api/knowledge/ingest/url' },
19
+ 'knowledge.ingest.urls': { method: 'POST', path: '/api/knowledge/ingest/urls' },
20
+ 'knowledge.issue.review': { method: 'POST', path: '/api/knowledge/issues/{id}/review' },
21
+ 'knowledge.issues.list': { method: 'GET', path: '/api/knowledge/issues' },
22
+ 'knowledge.item.get': { method: 'GET', path: '/api/knowledge/items/{id}' },
23
+ 'knowledge.job-runs.list': { method: 'GET', path: '/api/knowledge/job-runs' },
24
+ 'knowledge.job.get': { method: 'GET', path: '/api/knowledge/jobs/{jobId}' },
25
+ 'knowledge.job.run': { method: 'POST', path: '/api/knowledge/jobs/{jobId}/run' },
26
+ 'knowledge.jobs.list': { method: 'GET', path: '/api/knowledge/jobs' },
27
+ 'knowledge.lint': { method: 'POST', path: '/api/knowledge/lint' },
28
+ 'knowledge.map': { method: 'GET', path: '/api/knowledge/map' },
29
+ 'knowledge.nodes.list': { method: 'GET', path: '/api/knowledge/nodes' },
30
+ 'knowledge.packet': { method: 'POST', path: '/api/knowledge/packet' },
31
+ 'knowledge.projection.materialize': { method: 'POST', path: '/api/knowledge/projections/materialize' },
32
+ 'knowledge.projection.render': { method: 'POST', path: '/api/knowledge/projections/render' },
33
+ 'knowledge.projections.list': { method: 'GET', path: '/api/knowledge/projections' },
34
+ 'knowledge.refinement.run': { method: 'POST', path: '/api/knowledge/refinement/run' },
35
+ 'knowledge.refinement.task.cancel': { method: 'POST', path: '/api/knowledge/refinement/tasks/{id}/cancel' },
36
+ 'knowledge.refinement.task.get': { method: 'GET', path: '/api/knowledge/refinement/tasks/{id}' },
37
+ 'knowledge.refinement.tasks.list': { method: 'GET', path: '/api/knowledge/refinement/tasks' },
38
+ 'knowledge.reindex': { method: 'POST', path: '/api/knowledge/reindex' },
39
+ 'knowledge.report.get': { method: 'GET', path: '/api/knowledge/reports/{id}' },
40
+ 'knowledge.reports.list': { method: 'GET', path: '/api/knowledge/reports' },
41
+ 'knowledge.schedule.delete': { method: 'DELETE', path: '/api/knowledge/schedules/{id}' },
42
+ 'knowledge.schedule.enable': { method: 'POST', path: '/api/knowledge/schedules/{id}/enabled' },
43
+ 'knowledge.schedule.get': { method: 'GET', path: '/api/knowledge/schedules/{id}' },
44
+ 'knowledge.schedule.save': { method: 'POST', path: '/api/knowledge/schedules' },
45
+ 'knowledge.schedules.list': { method: 'GET', path: '/api/knowledge/schedules' },
46
+ 'knowledge.search': { method: 'POST', path: '/api/knowledge/search' },
47
+ 'knowledge.source.extraction.get': { method: 'GET', path: '/api/knowledge/sources/{id}/extraction' },
48
+ 'knowledge.sources.list': { method: 'GET', path: '/api/knowledge/sources' },
49
+ 'knowledge.status': { method: 'GET', path: '/api/knowledge/status' },
50
+ 'knowledge.usage.list': { method: 'GET', path: '/api/knowledge/usage' },
51
+ };
52
+ const KNOWLEDGE_BROWSER_DOMAINS = [
53
+ 'session',
54
+ 'turn',
55
+ 'tasks',
56
+ 'providers',
57
+ 'knowledge',
58
+ 'control-plane',
59
+ ];
60
+ export function createBrowserKnowledgeSdk(options = {}) {
61
+ const sdk = createScopedBrowserSdk({
62
+ ...SHARED_BROWSER_ROUTES,
63
+ ...KNOWLEDGE_BROWSER_ROUTES,
64
+ }, KNOWLEDGE_BROWSER_DOMAINS, options);
65
+ return {
66
+ ...sdk,
67
+ knowledge: {
68
+ ask: (input) => sdk.operator.invoke('knowledge.ask', input),
69
+ search: (input) => sdk.operator.invoke('knowledge.search', input),
70
+ status: () => sdk.operator.invoke('knowledge.status', {}),
71
+ map: (input = {}) => sdk.operator.invoke('knowledge.map', input),
72
+ },
73
+ };
74
+ }
75
+ export { forScopedBrowserSession as forSession };
@@ -0,0 +1,148 @@
1
+ import type { OperatorMethodInput, OperatorMethodOutput, OperatorTypedMethodId } from '@pellux/goodvibes-contracts/generated/foundation-client-types';
2
+ import type { AuthTokenResolver, HttpRetryPolicy, StreamReconnectPolicy, TransportMiddleware } from './transport-http.js';
3
+ import type { GoodVibesAuthClient, GoodVibesTokenStore } from './auth.js';
4
+ import type { SDKObserver } from './observer/index.js';
5
+ export type BrowserScopedRouteDefinition = {
6
+ readonly method: string;
7
+ readonly path: string;
8
+ };
9
+ export interface ScopedBrowserSdkOptions {
10
+ readonly baseUrl?: string | undefined;
11
+ readonly authToken?: string | null | undefined;
12
+ readonly getAuthToken?: AuthTokenResolver | undefined;
13
+ readonly tokenStore?: GoodVibesTokenStore | undefined;
14
+ readonly fetch?: typeof fetch | undefined;
15
+ readonly WebSocketImpl?: typeof WebSocket | undefined;
16
+ readonly headers?: HeadersInit | undefined;
17
+ readonly getHeaders?: (() => HeadersInit | undefined | Promise<HeadersInit | undefined>) | undefined;
18
+ readonly retry?: HttpRetryPolicy | undefined;
19
+ readonly middleware?: readonly TransportMiddleware[] | undefined;
20
+ readonly realtime?: {
21
+ readonly sseReconnect?: StreamReconnectPolicy | undefined;
22
+ readonly onError?: ((error: unknown) => void) | undefined;
23
+ } | undefined;
24
+ readonly observer?: SDKObserver | undefined;
25
+ }
26
+ export interface ScopedInvokeOptions {
27
+ readonly signal?: AbortSignal | undefined;
28
+ readonly headers?: HeadersInit | undefined;
29
+ }
30
+ type ScopedInput<TMethodId extends OperatorTypedMethodId> = OperatorMethodInput<TMethodId>;
31
+ type ScopedOutput<TMethodId extends OperatorTypedMethodId> = OperatorMethodOutput<TMethodId>;
32
+ export interface ScopedOperatorClient<TMethodId extends OperatorTypedMethodId> {
33
+ invoke<TSelectedMethodId extends TMethodId>(methodId: TSelectedMethodId, input?: ScopedInput<TSelectedMethodId>, options?: ScopedInvokeOptions): Promise<ScopedOutput<TSelectedMethodId>>;
34
+ }
35
+ export interface ScopedRuntimeEventEnvelope<TPayload extends {
36
+ readonly type: string;
37
+ } = {
38
+ readonly type: string;
39
+ }> {
40
+ readonly type: string;
41
+ readonly ts: number;
42
+ readonly traceId?: string | undefined;
43
+ readonly sessionId?: string | undefined;
44
+ readonly source?: string | undefined;
45
+ readonly payload: TPayload;
46
+ }
47
+ export interface ScopedRuntimeEventFeed<TPayload extends {
48
+ readonly type: string;
49
+ } = {
50
+ readonly type: string;
51
+ }> {
52
+ on<TType extends string>(type: TType, listener: (payload: TPayload & {
53
+ readonly type: TType;
54
+ }) => void): () => void;
55
+ onEnvelope<TType extends string>(type: TType, listener: (envelope: ScopedRuntimeEventEnvelope<TPayload & {
56
+ readonly type: TType;
57
+ }>) => void): () => void;
58
+ }
59
+ export type ScopedRuntimeEvents<TDomain extends string> = {
60
+ readonly domains: readonly TDomain[];
61
+ domain(domain: TDomain): ScopedRuntimeEventFeed;
62
+ } & {
63
+ readonly [K in TDomain]: ScopedRuntimeEventFeed;
64
+ };
65
+ export interface ScopedBrowserSdk<TMethodId extends OperatorTypedMethodId, TDomain extends string> {
66
+ readonly operator: ScopedOperatorClient<TMethodId>;
67
+ readonly auth: GoodVibesAuthClient;
68
+ readonly realtime: {
69
+ viaSse(): ScopedRuntimeEvents<TDomain>;
70
+ };
71
+ use(middleware: TransportMiddleware): void;
72
+ }
73
+ declare const SHARED_BROWSER_ROUTES: {
74
+ readonly 'accounts.snapshot': {
75
+ readonly method: "GET";
76
+ readonly path: "/api/accounts";
77
+ };
78
+ readonly 'control.auth.current': {
79
+ readonly method: "GET";
80
+ readonly path: "/api/control-plane/auth";
81
+ };
82
+ readonly 'control.auth.login': {
83
+ readonly method: "POST";
84
+ readonly path: "/login";
85
+ };
86
+ readonly 'control.snapshot': {
87
+ readonly method: "GET";
88
+ readonly path: "/api/control-plane";
89
+ };
90
+ readonly 'control.status': {
91
+ readonly method: "GET";
92
+ readonly path: "/status";
93
+ };
94
+ readonly 'providers.get': {
95
+ readonly method: "GET";
96
+ readonly path: "/api/providers/{providerId}";
97
+ };
98
+ readonly 'providers.list': {
99
+ readonly method: "GET";
100
+ readonly path: "/api/providers";
101
+ };
102
+ readonly 'providers.usage.get': {
103
+ readonly method: "GET";
104
+ readonly path: "/api/providers/{providerId}/usage";
105
+ };
106
+ readonly 'sessions.create': {
107
+ readonly method: "POST";
108
+ readonly path: "/api/sessions";
109
+ };
110
+ readonly 'sessions.followUp': {
111
+ readonly method: "POST";
112
+ readonly path: "/api/sessions/{sessionId}/follow-up";
113
+ };
114
+ readonly 'sessions.get': {
115
+ readonly method: "GET";
116
+ readonly path: "/api/sessions/{sessionId}";
117
+ };
118
+ readonly 'sessions.inputs.cancel': {
119
+ readonly method: "POST";
120
+ readonly path: "/api/sessions/{sessionId}/inputs/{inputId}/cancel";
121
+ };
122
+ readonly 'sessions.inputs.list': {
123
+ readonly method: "GET";
124
+ readonly path: "/api/sessions/{sessionId}/inputs";
125
+ };
126
+ readonly 'sessions.list': {
127
+ readonly method: "GET";
128
+ readonly path: "/api/sessions";
129
+ };
130
+ readonly 'sessions.messages.create': {
131
+ readonly method: "POST";
132
+ readonly path: "/api/sessions/{sessionId}/messages";
133
+ };
134
+ readonly 'sessions.messages.list': {
135
+ readonly method: "GET";
136
+ readonly path: "/api/sessions/{sessionId}/messages";
137
+ };
138
+ readonly 'sessions.steer': {
139
+ readonly method: "POST";
140
+ readonly path: "/api/sessions/{sessionId}/steer";
141
+ };
142
+ };
143
+ export type SharedBrowserMethodId = Extract<keyof typeof SHARED_BROWSER_ROUTES, OperatorTypedMethodId>;
144
+ export declare function resolveBrowserBaseUrl(baseUrl?: string): string;
145
+ export declare function forScopedBrowserSession<TDomain extends string>(events: ScopedRuntimeEvents<TDomain>, sessionId: string): ScopedRuntimeEvents<TDomain>;
146
+ export declare function createScopedBrowserSdk<TMethodId extends OperatorTypedMethodId, TDomain extends string>(routes: Record<TMethodId, BrowserScopedRouteDefinition>, domains: readonly TDomain[], options?: ScopedBrowserSdkOptions): ScopedBrowserSdk<TMethodId, TDomain>;
147
+ export { SHARED_BROWSER_ROUTES };
148
+ //# sourceMappingURL=browser-scoped.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-scoped.d.ts","sourceRoot":"","sources":["../src/browser-scoped.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,+DAA+D,CAAC;AACvE,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAK7B,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,WAAW,CAAC;AAInB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,MAAM,4BAA4B,GAAG;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAIF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,YAAY,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,SAAS,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC,GAAG,SAAS,CAAC;IACrG,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,mBAAmB,EAAE,GAAG,SAAS,CAAC;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,YAAY,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;QAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;KAC3D,GAAG,SAAS,CAAC;IACd,QAAQ,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC7C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC5C;AAED,KAAK,WAAW,CAAC,SAAS,SAAS,qBAAqB,IAAI,mBAAmB,CAAC,SAAS,CAAC,CAAC;AAC3F,KAAK,YAAY,CAAC,SAAS,SAAS,qBAAqB,IAAI,oBAAoB,CAAC,SAAS,CAAC,CAAC;AAE7F,MAAM,WAAW,oBAAoB,CAAC,SAAS,SAAS,qBAAqB;IAC3E,MAAM,CAAC,iBAAiB,SAAS,SAAS,EACxC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,CAAC,EAAE,WAAW,CAAC,iBAAiB,CAAC,EACtC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,0BAA0B,CAAC,QAAQ,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;IAChH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB,CAAC,QAAQ,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;IAC5G,EAAE,CAAC,KAAK,SAAS,MAAM,EACrB,IAAI,EAAE,KAAK,EACX,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,GAAG;QAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;KAAE,KAAK,IAAI,GAC/D,MAAM,IAAI,CAAC;IACd,UAAU,CAAC,KAAK,SAAS,MAAM,EAC7B,IAAI,EAAE,KAAK,EACX,QAAQ,EAAE,CAAC,QAAQ,EAAE,0BAA0B,CAAC,QAAQ,GAAG;QAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC,KAAK,IAAI,GAC5F,MAAM,IAAI,CAAC;CACf;AAED,MAAM,MAAM,mBAAmB,CAAC,OAAO,SAAS,MAAM,IAAI;IACxD,QAAQ,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC;IACrC,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,sBAAsB,CAAC;CACjD,GAAG;IAAE,QAAQ,EAAE,CAAC,IAAI,OAAO,GAAG,sBAAsB;CAAE,CAAC;AAExD,MAAM,WAAW,gBAAgB,CAAC,SAAS,SAAS,qBAAqB,EAAE,OAAO,SAAS,MAAM;IAC/F,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC,SAAS,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE;QACjB,MAAM,IAAI,mBAAmB,CAAC,OAAO,CAAC,CAAC;KACxC,CAAC;IACF,GAAG,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAC5C;AAED,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkB8D,CAAC;AAE1F,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,MAAM,OAAO,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;AAEvG,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAS9D;AA6ND,wBAAgB,uBAAuB,CAAC,OAAO,SAAS,MAAM,EAC5D,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC,EACpC,SAAS,EAAE,MAAM,GAChB,mBAAmB,CAAC,OAAO,CAAC,CA4B9B;AAED,wBAAgB,sBAAsB,CAAC,SAAS,SAAS,qBAAqB,EAAE,OAAO,SAAS,MAAM,EACpG,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,4BAA4B,CAAC,EACvD,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC,CAgBtC;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1,243 @@
1
+ import { ConfigurationError, ContractError } from '@pellux/goodvibes-errors';
2
+ import { createHttpTransport, openRawServerSentEventStream, } from './transport-http.js';
3
+ import { createGoodVibesAuthClient, } from './auth.js';
4
+ const SHARED_BROWSER_ROUTES = {
5
+ 'accounts.snapshot': { method: 'GET', path: '/api/accounts' },
6
+ 'control.auth.current': { method: 'GET', path: '/api/control-plane/auth' },
7
+ 'control.auth.login': { method: 'POST', path: '/login' },
8
+ 'control.snapshot': { method: 'GET', path: '/api/control-plane' },
9
+ 'control.status': { method: 'GET', path: '/status' },
10
+ 'providers.get': { method: 'GET', path: '/api/providers/{providerId}' },
11
+ 'providers.list': { method: 'GET', path: '/api/providers' },
12
+ 'providers.usage.get': { method: 'GET', path: '/api/providers/{providerId}/usage' },
13
+ 'sessions.create': { method: 'POST', path: '/api/sessions' },
14
+ 'sessions.followUp': { method: 'POST', path: '/api/sessions/{sessionId}/follow-up' },
15
+ 'sessions.get': { method: 'GET', path: '/api/sessions/{sessionId}' },
16
+ 'sessions.inputs.cancel': { method: 'POST', path: '/api/sessions/{sessionId}/inputs/{inputId}/cancel' },
17
+ 'sessions.inputs.list': { method: 'GET', path: '/api/sessions/{sessionId}/inputs' },
18
+ 'sessions.list': { method: 'GET', path: '/api/sessions' },
19
+ 'sessions.messages.create': { method: 'POST', path: '/api/sessions/{sessionId}/messages' },
20
+ 'sessions.messages.list': { method: 'GET', path: '/api/sessions/{sessionId}/messages' },
21
+ 'sessions.steer': { method: 'POST', path: '/api/sessions/{sessionId}/steer' },
22
+ };
23
+ export function resolveBrowserBaseUrl(baseUrl) {
24
+ const explicit = baseUrl?.trim();
25
+ if (explicit)
26
+ return explicit;
27
+ if (typeof globalThis.location?.origin === 'string' && globalThis.location.origin.trim()) {
28
+ return globalThis.location.origin.trim();
29
+ }
30
+ throw new ConfigurationError('Browser baseUrl is required when location.origin is unavailable.');
31
+ }
32
+ function resolveFetch(fetchImpl) {
33
+ const resolved = fetchImpl ?? globalThis.fetch;
34
+ if (typeof resolved !== 'function') {
35
+ throw new ConfigurationError('Fetch implementation is required. Pass options.fetch or use a browser/runtime that provides global fetch.');
36
+ }
37
+ return resolved;
38
+ }
39
+ function buildRouteError(methodId) {
40
+ return new ContractError(`Operator method "${methodId}" is not available from this scoped browser SDK entrypoint. Import the matching scoped entrypoint instead of the full browser client.`);
41
+ }
42
+ function createScopedOperatorClient(routes, options) {
43
+ const transport = createHttpTransport({
44
+ baseUrl: resolveBrowserBaseUrl(options.baseUrl),
45
+ authToken: options.authToken ?? null,
46
+ getAuthToken: options.tokenStore
47
+ ? () => options.tokenStore.getToken()
48
+ : options.getAuthToken,
49
+ fetch: resolveFetch(options.fetch),
50
+ headers: options.headers,
51
+ getHeaders: options.getHeaders,
52
+ retry: options.retry,
53
+ middleware: options.middleware,
54
+ observer: options.observer,
55
+ });
56
+ const operator = {
57
+ async invoke(methodId, input, invokeOptions = {}) {
58
+ const route = routes[methodId];
59
+ if (!route)
60
+ throw buildRouteError(methodId);
61
+ const resolved = transport.resolveContractRequest(route.method, route.path, input && typeof input === 'object' && !Array.isArray(input)
62
+ ? input
63
+ : {});
64
+ return await transport.requestJson(resolved.url, {
65
+ method: resolved.method,
66
+ body: resolved.body,
67
+ headers: invokeOptions.headers,
68
+ signal: invokeOptions.signal,
69
+ methodId,
70
+ idempotent: false,
71
+ });
72
+ },
73
+ };
74
+ return {
75
+ operator,
76
+ requestJson: (pathOrUrl, requestOptions) => transport.requestJson(pathOrUrl, requestOptions),
77
+ getAuthToken: () => transport.getAuthToken(),
78
+ use: (middleware) => transport.use(middleware),
79
+ };
80
+ }
81
+ function createAuthOperatorShim(operator) {
82
+ return {
83
+ control: {
84
+ auth: {
85
+ current: () => operator.invoke('control.auth.current', {}),
86
+ login: (input) => operator.invoke('control.auth.login', input),
87
+ },
88
+ },
89
+ };
90
+ }
91
+ function createFeed(subscribe) {
92
+ return {
93
+ on(type, listener) {
94
+ return subscribe(type, (envelope) => {
95
+ listener(envelope.payload);
96
+ });
97
+ },
98
+ onEnvelope(type, listener) {
99
+ return subscribe(type, listener);
100
+ },
101
+ };
102
+ }
103
+ function normalizeEnvelope(value) {
104
+ if (!value || typeof value !== 'object')
105
+ return null;
106
+ const envelope = value;
107
+ const payload = envelope.payload;
108
+ if (!payload || typeof payload !== 'object')
109
+ return null;
110
+ const payloadType = payload.type;
111
+ if (typeof payloadType !== 'string')
112
+ return null;
113
+ return {
114
+ type: typeof envelope.type === 'string' ? envelope.type : payloadType,
115
+ ts: typeof envelope.ts === 'number'
116
+ ? envelope.ts
117
+ : typeof envelope.timestamp === 'number'
118
+ ? envelope.timestamp
119
+ : Date.now(),
120
+ traceId: typeof envelope.traceId === 'string' ? envelope.traceId : undefined,
121
+ sessionId: typeof envelope.sessionId === 'string' ? envelope.sessionId : undefined,
122
+ source: typeof envelope.source === 'string' ? envelope.source : undefined,
123
+ payload: payload,
124
+ };
125
+ }
126
+ function buildEventUrl(baseUrl, domain) {
127
+ const url = new URL('/api/control-plane/events', baseUrl);
128
+ url.searchParams.set('domains', domain);
129
+ return url.toString();
130
+ }
131
+ function createScopedRealtime(domains, options, getAuthToken) {
132
+ return {
133
+ viaSse() {
134
+ const baseUrl = resolveBrowserBaseUrl(options.baseUrl);
135
+ const fetchImpl = resolveFetch(options.fetch);
136
+ const feeds = new Map();
137
+ const activeByDomain = new Map();
138
+ const ensureDomain = (domain) => {
139
+ let active = activeByDomain.get(domain);
140
+ if (active)
141
+ return active;
142
+ active = { listenersByType: new Map(), closed: false };
143
+ activeByDomain.set(domain, active);
144
+ void openRawServerSentEventStream(fetchImpl, buildEventUrl(baseUrl, domain), {
145
+ onEvent: (eventName, payload) => {
146
+ if (eventName !== domain)
147
+ return;
148
+ const envelope = normalizeEnvelope(payload);
149
+ if (!envelope)
150
+ return;
151
+ for (const listener of [...(active.listenersByType.get(envelope.payload.type) ?? [])]) {
152
+ listener(envelope);
153
+ }
154
+ },
155
+ onError: (error) => options.realtime?.onError?.(error),
156
+ }, {
157
+ reconnect: options.realtime?.sseReconnect,
158
+ getAuthToken,
159
+ }).then((disconnect) => {
160
+ if (active.closed || activeByDomain.get(domain) !== active) {
161
+ disconnect();
162
+ return;
163
+ }
164
+ active.disconnect = disconnect;
165
+ }).catch((error) => {
166
+ options.realtime?.onError?.(error);
167
+ });
168
+ return active;
169
+ };
170
+ const getFeed = (domain) => {
171
+ let feed = feeds.get(domain);
172
+ if (feed)
173
+ return feed;
174
+ feed = createFeed((type, listener) => {
175
+ const active = ensureDomain(domain);
176
+ const listeners = active.listenersByType.get(type) ?? new Set();
177
+ listeners.add(listener);
178
+ active.listenersByType.set(type, listeners);
179
+ return () => {
180
+ listeners.delete(listener);
181
+ if (listeners.size === 0)
182
+ active.listenersByType.delete(type);
183
+ if (active.listenersByType.size === 0) {
184
+ active.closed = true;
185
+ active.disconnect?.();
186
+ activeByDomain.delete(domain);
187
+ }
188
+ };
189
+ });
190
+ feeds.set(domain, feed);
191
+ return feed;
192
+ };
193
+ return Object.freeze({
194
+ domains,
195
+ domain: getFeed,
196
+ ...Object.fromEntries(domains.map((domain) => [domain, getFeed(domain)])),
197
+ });
198
+ },
199
+ };
200
+ }
201
+ export function forScopedBrowserSession(events, sessionId) {
202
+ const feeds = new Map();
203
+ const getFeed = (domain) => {
204
+ let feed = feeds.get(domain);
205
+ if (feed)
206
+ return feed;
207
+ const baseFeed = events.domain(domain);
208
+ feed = {
209
+ on(type, listener) {
210
+ return baseFeed.onEnvelope(type, (envelope) => {
211
+ if (envelope.sessionId !== sessionId)
212
+ return;
213
+ listener(envelope.payload);
214
+ });
215
+ },
216
+ onEnvelope(type, listener) {
217
+ return baseFeed.onEnvelope(type, (envelope) => {
218
+ if (envelope.sessionId !== sessionId)
219
+ return;
220
+ listener(envelope);
221
+ });
222
+ },
223
+ };
224
+ feeds.set(domain, feed);
225
+ return feed;
226
+ };
227
+ return Object.freeze({
228
+ domains: events.domains,
229
+ domain: getFeed,
230
+ ...Object.fromEntries(events.domains.map((domain) => [domain, getFeed(domain)])),
231
+ });
232
+ }
233
+ export function createScopedBrowserSdk(routes, domains, options = {}) {
234
+ const scoped = createScopedOperatorClient(routes, options);
235
+ const auth = createGoodVibesAuthClient(createAuthOperatorShim(scoped.operator), options.tokenStore ?? null, options.getAuthToken, options.observer, undefined, null);
236
+ return {
237
+ operator: scoped.operator,
238
+ auth,
239
+ realtime: createScopedRealtime(domains, options, scoped.getAuthToken),
240
+ use: scoped.use,
241
+ };
242
+ }
243
+ export { SHARED_BROWSER_ROUTES };
@@ -3,7 +3,7 @@
3
3
  "product": {
4
4
  "id": "goodvibes",
5
5
  "surface": "operator",
6
- "version": "0.33.5"
6
+ "version": "0.33.7"
7
7
  },
8
8
  "auth": {
9
9
  "modes": [
@@ -8,7 +8,7 @@ export interface GoodVibesRuntimeCapability {
8
8
  readonly requirements: readonly GoodVibesRuntimeRequirement[];
9
9
  readonly dependencyFamilies: readonly string[];
10
10
  }
11
- export declare const GOODVIBES_CLIENT_SAFE_ENTRYPOINTS: readonly ["@pellux/goodvibes-sdk", "@pellux/goodvibes-sdk/auth", "@pellux/goodvibes-sdk/browser", "@pellux/goodvibes-sdk/client-auth", "@pellux/goodvibes-sdk/contracts", "@pellux/goodvibes-sdk/errors", "@pellux/goodvibes-sdk/events", "@pellux/goodvibes-sdk/expo", "@pellux/goodvibes-sdk/observer", "@pellux/goodvibes-sdk/operator", "@pellux/goodvibes-sdk/peer", "@pellux/goodvibes-sdk/react-native", "@pellux/goodvibes-sdk/transport-core", "@pellux/goodvibes-sdk/transport-direct", "@pellux/goodvibes-sdk/transport-http", "@pellux/goodvibes-sdk/transport-realtime", "@pellux/goodvibes-sdk/web", "@pellux/goodvibes-sdk/workers"];
11
+ export declare const GOODVIBES_CLIENT_SAFE_ENTRYPOINTS: readonly ["@pellux/goodvibes-sdk", "@pellux/goodvibes-sdk/auth", "@pellux/goodvibes-sdk/browser", "@pellux/goodvibes-sdk/browser/homeassistant", "@pellux/goodvibes-sdk/browser/knowledge", "@pellux/goodvibes-sdk/client-auth", "@pellux/goodvibes-sdk/contracts", "@pellux/goodvibes-sdk/errors", "@pellux/goodvibes-sdk/events", "@pellux/goodvibes-sdk/expo", "@pellux/goodvibes-sdk/observer", "@pellux/goodvibes-sdk/operator", "@pellux/goodvibes-sdk/peer", "@pellux/goodvibes-sdk/react-native", "@pellux/goodvibes-sdk/transport-core", "@pellux/goodvibes-sdk/transport-direct", "@pellux/goodvibes-sdk/transport-http", "@pellux/goodvibes-sdk/transport-realtime", "@pellux/goodvibes-sdk/web", "@pellux/goodvibes-sdk/workers"];
12
12
  export declare const GOODVIBES_NODE_RUNTIME_ENTRYPOINTS: readonly ["@pellux/goodvibes-sdk/platform/node", "@pellux/goodvibes-sdk/platform/node/runtime-boundary", "@pellux/goodvibes-sdk/platform/config", "@pellux/goodvibes-sdk/platform/core", "@pellux/goodvibes-sdk/platform/daemon", "@pellux/goodvibes-sdk/platform/git", "@pellux/goodvibes-sdk/platform/intelligence", "@pellux/goodvibes-sdk/platform/integrations", "@pellux/goodvibes-sdk/platform/knowledge", "@pellux/goodvibes-sdk/platform/knowledge/extensions", "@pellux/goodvibes-sdk/platform/knowledge/home-graph", "@pellux/goodvibes-sdk/platform/multimodal", "@pellux/goodvibes-sdk/platform/pairing", "@pellux/goodvibes-sdk/platform/providers", "@pellux/goodvibes-sdk/platform/runtime", "@pellux/goodvibes-sdk/platform/runtime/observability", "@pellux/goodvibes-sdk/platform/runtime/sandbox", "@pellux/goodvibes-sdk/platform/runtime/settings", "@pellux/goodvibes-sdk/platform/runtime/state", "@pellux/goodvibes-sdk/platform/runtime/store", "@pellux/goodvibes-sdk/platform/runtime/ui", "@pellux/goodvibes-sdk/contracts/node", "@pellux/goodvibes-sdk/platform/tools", "@pellux/goodvibes-sdk/platform/utils", "@pellux/goodvibes-sdk/platform/voice"];
13
13
  export declare const GOODVIBES_RUNTIME_CAPABILITIES: readonly GoodVibesRuntimeCapability[];
14
14
  export declare function isClientSafeGoodVibesEntrypoint(entrypoint: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../../src/platform/node/capabilities.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAC/B,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,MAAM,2BAA2B,GACnC,OAAO,GACP,WAAW,GACX,WAAW,GACX,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,uBAAuB,CAAC;AAE5B,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,QAAQ,CAAC,YAAY,EAAE,SAAS,2BAA2B,EAAE,CAAC;IAC9D,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD;AAED,eAAO,MAAM,iCAAiC,qnBAmBpC,CAAC;AAEX,eAAO,MAAM,kCAAkC,wnCA0BrC,CAAC;AAEX,eAAO,MAAM,8BAA8B,EAAE,SAAS,0BAA0B,EAgGtE,CAAC;AAEX,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE3E;AAED,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE5E;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,CAAC,EAAE,uBAAuB,GAChC,SAAS,0BAA0B,EAAE,CAKvC"}
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../../src/platform/node/capabilities.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAC/B,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,MAAM,2BAA2B,GACnC,OAAO,GACP,WAAW,GACX,WAAW,GACX,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,uBAAuB,CAAC;AAE5B,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACtD,QAAQ,CAAC,YAAY,EAAE,SAAS,2BAA2B,EAAE,CAAC;IAC9D,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD;AAED,eAAO,MAAM,iCAAiC,+sBAqBpC,CAAC;AAEX,eAAO,MAAM,kCAAkC,wnCA0BrC,CAAC;AAEX,eAAO,MAAM,8BAA8B,EAAE,SAAS,0BAA0B,EAgGtE,CAAC;AAEX,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE3E;AAED,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE5E;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,CAAC,EAAE,uBAAuB,GAChC,SAAS,0BAA0B,EAAE,CAKvC"}
@@ -2,6 +2,8 @@ export const GOODVIBES_CLIENT_SAFE_ENTRYPOINTS = [
2
2
  '@pellux/goodvibes-sdk',
3
3
  '@pellux/goodvibes-sdk/auth',
4
4
  '@pellux/goodvibes-sdk/browser',
5
+ '@pellux/goodvibes-sdk/browser/homeassistant',
6
+ '@pellux/goodvibes-sdk/browser/knowledge',
5
7
  '@pellux/goodvibes-sdk/client-auth',
6
8
  '@pellux/goodvibes-sdk/contracts',
7
9
  '@pellux/goodvibes-sdk/errors',
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- let version = '0.33.5';
3
+ let version = '0.33.7';
4
4
  try {
5
5
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
6
6
  version = pkg.version ?? version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-sdk",
3
- "version": "0.33.5",
3
+ "version": "0.33.7",
4
4
  "description": "TypeScript SDK for building GoodVibes operator, peer, web, mobile, and daemon-connected apps with typed contracts, auth, realtime events, and transport layers.",
5
5
  "keywords": [
6
6
  "goodvibes",
@@ -34,6 +34,14 @@
34
34
  "types": "./dist/browser.d.ts",
35
35
  "import": "./dist/browser.js"
36
36
  },
37
+ "./browser/homeassistant": {
38
+ "types": "./dist/browser-homeassistant.d.ts",
39
+ "import": "./dist/browser-homeassistant.js"
40
+ },
41
+ "./browser/knowledge": {
42
+ "types": "./dist/browser-knowledge.d.ts",
43
+ "import": "./dist/browser-knowledge.js"
44
+ },
37
45
  "./client-auth": {
38
46
  "types": "./dist/client-auth/index.d.ts",
39
47
  "import": "./dist/client-auth/index.js"
@@ -441,14 +449,14 @@
441
449
  "sideEffects": false,
442
450
  "type": "module",
443
451
  "dependencies": {
444
- "@pellux/goodvibes-contracts": "0.33.5",
445
- "@pellux/goodvibes-daemon-sdk": "0.33.5",
446
- "@pellux/goodvibes-errors": "0.33.5",
447
- "@pellux/goodvibes-operator-sdk": "0.33.5",
448
- "@pellux/goodvibes-peer-sdk": "0.33.5",
449
- "@pellux/goodvibes-transport-core": "0.33.5",
450
- "@pellux/goodvibes-transport-http": "0.33.5",
451
- "@pellux/goodvibes-transport-realtime": "0.33.5"
452
+ "@pellux/goodvibes-contracts": "0.33.7",
453
+ "@pellux/goodvibes-daemon-sdk": "0.33.7",
454
+ "@pellux/goodvibes-errors": "0.33.7",
455
+ "@pellux/goodvibes-operator-sdk": "0.33.7",
456
+ "@pellux/goodvibes-peer-sdk": "0.33.7",
457
+ "@pellux/goodvibes-transport-core": "0.33.7",
458
+ "@pellux/goodvibes-transport-http": "0.33.7",
459
+ "@pellux/goodvibes-transport-realtime": "0.33.7"
452
460
  },
453
461
  "optionalDependencies": {
454
462
  "@agentclientprotocol/sdk": "^0.21.0",