@ekanos/sdk 0.1.2 → 0.1.3
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 +1093 -140
- package/api-report.md +202 -0
- package/dist/components/index.d.ts +3 -2
- package/dist/components/index.js +3 -2
- package/dist/components/index.js.map +1 -1
- package/dist/components/widgets/widget-context.js.map +1 -1
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context/index.js.map +1 -1
- package/dist/context/types.d.ts +1 -1
- package/dist/context/types.js.map +1 -1
- package/dist/hooks/activation-actions-context.d.ts +4 -4
- package/dist/hooks/activation-actions-context.js +1 -1
- package/dist/hooks/activation-actions-context.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +2 -2
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/use-oauth-connection-status.d.ts +18 -72
- package/dist/hooks/use-oauth-connection-status.js +1 -1
- package/dist/hooks/use-oauth-connection-status.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/integration/define-integration.d.ts +2 -3
- package/dist/integration/define-integration.js +2 -3
- package/dist/integration/define-integration.js.map +1 -1
- package/dist/integration/index.d.ts +2 -2
- package/dist/integration/index.js +2 -2
- package/dist/integration/index.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/types/index.d.ts +3 -4
- package/dist/types/index.js +3 -4
- package/dist/types/index.js.map +1 -1
- package/dist/types/integration.d.ts +2 -2
- package/dist/types/integration.js.map +1 -1
- package/dist/types/widget-ask-context.d.ts +1 -1
- package/dist/types/widget-ask-context.js.map +1 -1
- package/eslint.preset.mjs +2 -4
- package/package.json +14 -16
- package/dist/mcp/guards.d.ts +0 -40
- package/dist/mcp/guards.js +0 -99
- package/dist/mcp/guards.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -22
- package/dist/mcp/index.js +0 -22
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/ownership.d.ts +0 -74
- package/dist/mcp/ownership.js +0 -83
- package/dist/mcp/ownership.js.map +0 -1
- package/dist/mcp/types.d.ts +0 -145
- package/dist/mcp/types.js +0 -2
- package/dist/mcp/types.js.map +0 -1
|
@@ -42,7 +42,7 @@ export interface UseOAuthConnectionStatusOptions {
|
|
|
42
42
|
export declare function useOAuthConnectionStatus(accountId: string, options: UseOAuthConnectionStatusOptions): {
|
|
43
43
|
oauthJustCompleted: boolean;
|
|
44
44
|
oauthError: string | null;
|
|
45
|
-
data:
|
|
45
|
+
data: {
|
|
46
46
|
isConnected: boolean;
|
|
47
47
|
error: string | undefined;
|
|
48
48
|
obtainedAt?: undefined;
|
|
@@ -50,7 +50,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
50
50
|
isConnected: boolean;
|
|
51
51
|
obtainedAt: string | null | undefined;
|
|
52
52
|
error?: undefined;
|
|
53
|
-
}
|
|
53
|
+
};
|
|
54
54
|
error: Error;
|
|
55
55
|
isError: true;
|
|
56
56
|
isPending: false;
|
|
@@ -73,7 +73,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
73
73
|
isRefetching: boolean;
|
|
74
74
|
isStale: boolean;
|
|
75
75
|
isEnabled: boolean;
|
|
76
|
-
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<
|
|
76
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
|
|
77
77
|
isConnected: boolean;
|
|
78
78
|
error: string | undefined;
|
|
79
79
|
obtainedAt?: undefined;
|
|
@@ -81,21 +81,12 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
81
81
|
isConnected: boolean;
|
|
82
82
|
obtainedAt: string | null | undefined;
|
|
83
83
|
error?: undefined;
|
|
84
|
-
}
|
|
84
|
+
}, Error>>;
|
|
85
85
|
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
86
|
-
promise: Promise<NoInfer<{
|
|
87
|
-
isConnected: boolean;
|
|
88
|
-
error: string | undefined;
|
|
89
|
-
obtainedAt?: undefined;
|
|
90
|
-
} | {
|
|
91
|
-
isConnected: boolean;
|
|
92
|
-
obtainedAt: string | null | undefined;
|
|
93
|
-
error?: undefined;
|
|
94
|
-
}>>;
|
|
95
86
|
} | {
|
|
96
87
|
oauthJustCompleted: boolean;
|
|
97
88
|
oauthError: string | null;
|
|
98
|
-
data:
|
|
89
|
+
data: {
|
|
99
90
|
isConnected: boolean;
|
|
100
91
|
error: string | undefined;
|
|
101
92
|
obtainedAt?: undefined;
|
|
@@ -103,7 +94,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
103
94
|
isConnected: boolean;
|
|
104
95
|
obtainedAt: string | null | undefined;
|
|
105
96
|
error?: undefined;
|
|
106
|
-
}
|
|
97
|
+
};
|
|
107
98
|
error: null;
|
|
108
99
|
isError: false;
|
|
109
100
|
isPending: false;
|
|
@@ -126,7 +117,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
126
117
|
isRefetching: boolean;
|
|
127
118
|
isStale: boolean;
|
|
128
119
|
isEnabled: boolean;
|
|
129
|
-
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<
|
|
120
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
|
|
130
121
|
isConnected: boolean;
|
|
131
122
|
error: string | undefined;
|
|
132
123
|
obtainedAt?: undefined;
|
|
@@ -134,17 +125,8 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
134
125
|
isConnected: boolean;
|
|
135
126
|
obtainedAt: string | null | undefined;
|
|
136
127
|
error?: undefined;
|
|
137
|
-
}
|
|
128
|
+
}, Error>>;
|
|
138
129
|
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
139
|
-
promise: Promise<NoInfer<{
|
|
140
|
-
isConnected: boolean;
|
|
141
|
-
error: string | undefined;
|
|
142
|
-
obtainedAt?: undefined;
|
|
143
|
-
} | {
|
|
144
|
-
isConnected: boolean;
|
|
145
|
-
obtainedAt: string | null | undefined;
|
|
146
|
-
error?: undefined;
|
|
147
|
-
}>>;
|
|
148
130
|
} | {
|
|
149
131
|
oauthJustCompleted: boolean;
|
|
150
132
|
oauthError: string | null;
|
|
@@ -171,7 +153,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
171
153
|
isRefetching: boolean;
|
|
172
154
|
isStale: boolean;
|
|
173
155
|
isEnabled: boolean;
|
|
174
|
-
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<
|
|
156
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
|
|
175
157
|
isConnected: boolean;
|
|
176
158
|
error: string | undefined;
|
|
177
159
|
obtainedAt?: undefined;
|
|
@@ -179,17 +161,8 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
179
161
|
isConnected: boolean;
|
|
180
162
|
obtainedAt: string | null | undefined;
|
|
181
163
|
error?: undefined;
|
|
182
|
-
}
|
|
164
|
+
}, Error>>;
|
|
183
165
|
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
184
|
-
promise: Promise<NoInfer<{
|
|
185
|
-
isConnected: boolean;
|
|
186
|
-
error: string | undefined;
|
|
187
|
-
obtainedAt?: undefined;
|
|
188
|
-
} | {
|
|
189
|
-
isConnected: boolean;
|
|
190
|
-
obtainedAt: string | null | undefined;
|
|
191
|
-
error?: undefined;
|
|
192
|
-
}>>;
|
|
193
166
|
} | {
|
|
194
167
|
oauthJustCompleted: boolean;
|
|
195
168
|
oauthError: string | null;
|
|
@@ -216,7 +189,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
216
189
|
isRefetching: boolean;
|
|
217
190
|
isStale: boolean;
|
|
218
191
|
isEnabled: boolean;
|
|
219
|
-
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<
|
|
192
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
|
|
220
193
|
isConnected: boolean;
|
|
221
194
|
error: string | undefined;
|
|
222
195
|
obtainedAt?: undefined;
|
|
@@ -224,17 +197,8 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
224
197
|
isConnected: boolean;
|
|
225
198
|
obtainedAt: string | null | undefined;
|
|
226
199
|
error?: undefined;
|
|
227
|
-
}
|
|
200
|
+
}, Error>>;
|
|
228
201
|
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
229
|
-
promise: Promise<NoInfer<{
|
|
230
|
-
isConnected: boolean;
|
|
231
|
-
error: string | undefined;
|
|
232
|
-
obtainedAt?: undefined;
|
|
233
|
-
} | {
|
|
234
|
-
isConnected: boolean;
|
|
235
|
-
obtainedAt: string | null | undefined;
|
|
236
|
-
error?: undefined;
|
|
237
|
-
}>>;
|
|
238
202
|
} | {
|
|
239
203
|
oauthJustCompleted: boolean;
|
|
240
204
|
oauthError: string | null;
|
|
@@ -261,7 +225,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
261
225
|
isRefetching: boolean;
|
|
262
226
|
isStale: boolean;
|
|
263
227
|
isEnabled: boolean;
|
|
264
|
-
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<
|
|
228
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
|
|
265
229
|
isConnected: boolean;
|
|
266
230
|
error: string | undefined;
|
|
267
231
|
obtainedAt?: undefined;
|
|
@@ -269,21 +233,12 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
269
233
|
isConnected: boolean;
|
|
270
234
|
obtainedAt: string | null | undefined;
|
|
271
235
|
error?: undefined;
|
|
272
|
-
}
|
|
236
|
+
}, Error>>;
|
|
273
237
|
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
274
|
-
promise: Promise<NoInfer<{
|
|
275
|
-
isConnected: boolean;
|
|
276
|
-
error: string | undefined;
|
|
277
|
-
obtainedAt?: undefined;
|
|
278
|
-
} | {
|
|
279
|
-
isConnected: boolean;
|
|
280
|
-
obtainedAt: string | null | undefined;
|
|
281
|
-
error?: undefined;
|
|
282
|
-
}>>;
|
|
283
238
|
} | {
|
|
284
239
|
oauthJustCompleted: boolean;
|
|
285
240
|
oauthError: string | null;
|
|
286
|
-
data:
|
|
241
|
+
data: {
|
|
287
242
|
isConnected: boolean;
|
|
288
243
|
error: string | undefined;
|
|
289
244
|
obtainedAt?: undefined;
|
|
@@ -291,7 +246,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
291
246
|
isConnected: boolean;
|
|
292
247
|
obtainedAt: string | null | undefined;
|
|
293
248
|
error?: undefined;
|
|
294
|
-
}
|
|
249
|
+
};
|
|
295
250
|
isError: false;
|
|
296
251
|
error: null;
|
|
297
252
|
isPending: false;
|
|
@@ -314,7 +269,7 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
314
269
|
isRefetching: boolean;
|
|
315
270
|
isStale: boolean;
|
|
316
271
|
isEnabled: boolean;
|
|
317
|
-
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<
|
|
272
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<{
|
|
318
273
|
isConnected: boolean;
|
|
319
274
|
error: string | undefined;
|
|
320
275
|
obtainedAt?: undefined;
|
|
@@ -322,17 +277,8 @@ export declare function useOAuthConnectionStatus(accountId: string, options: Use
|
|
|
322
277
|
isConnected: boolean;
|
|
323
278
|
obtainedAt: string | null | undefined;
|
|
324
279
|
error?: undefined;
|
|
325
|
-
}
|
|
280
|
+
}, Error>>;
|
|
326
281
|
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
327
|
-
promise: Promise<NoInfer<{
|
|
328
|
-
isConnected: boolean;
|
|
329
|
-
error: string | undefined;
|
|
330
|
-
obtainedAt?: undefined;
|
|
331
|
-
} | {
|
|
332
|
-
isConnected: boolean;
|
|
333
|
-
obtainedAt: string | null | undefined;
|
|
334
|
-
error?: undefined;
|
|
335
|
-
}>>;
|
|
336
282
|
};
|
|
337
283
|
/**
|
|
338
284
|
* Resolves the gating booleans every OAuth-backed dashboard widget needs:
|
|
@@ -42,7 +42,7 @@ export function useOAuthConnectionStatus(accountId, options) {
|
|
|
42
42
|
refetchOnWindowFocus: false,
|
|
43
43
|
});
|
|
44
44
|
const errorParamName = errorParam === null || errorParam === void 0 ? void 0 : errorParam.name;
|
|
45
|
-
// Justified useEffect
|
|
45
|
+
// Justified useEffect: after the OAuth redirect lands back
|
|
46
46
|
// on this page with `?oauth_success=true`, we must (1) strip the transient
|
|
47
47
|
// query params from the URL and (2) invalidate the cached connection status
|
|
48
48
|
// so widgets flip to connected without a manual refresh. Both are
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-oauth-connection-status.js","sourceRoot":"","sources":["../../src/hooks/use-oauth-connection-status.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAuCjE;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAAiB,EACjB,OAAwC;IAExC,MAAM,EACJ,aAAa,EACb,eAAe,EACf,OAAO,GAAG,IAAI,EACd,UAAU,GACX,GAAG,OAAO,CAAC;IACZ,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,yEAAyE;IACzE,0EAA0E;IAC1E,MAAM,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE;QACzC,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO,KAAK,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3D,OAAO,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,KAAK,MAAM,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAgB,GAAG,EAAE;QAChD,IAAI,CAAC,UAAU,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC;QAC9D,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAC3D,UAAU,CAAC,IAAI,CAChB,CAAC;QACF,OAAO,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,QAAQ,CAAC;QACrB,QAAQ,EAAE,CAAC,kBAAkB,EAAE,SAAS,EAAE,aAAa,CAAC;QACxD,OAAO,EAAE,KAAK,IAAI,EAAE;;YAClB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;YAEpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YACrD,CAAC;YAED,OAAO;gBACL,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,MAAA,MAAM,CAAC,IAAI,0CAAE,UAAU;aACpC,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC,SAAS;QAC/B,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;QACxB,oBAAoB,EAAE,KAAK;KAC5B,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,IAAI,CAAC;IAExC,
|
|
1
|
+
{"version":3,"file":"use-oauth-connection-status.js","sourceRoot":"","sources":["../../src/hooks/use-oauth-connection-status.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAuCjE;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,SAAiB,EACjB,OAAwC;IAExC,MAAM,EACJ,aAAa,EACb,eAAe,EACf,OAAO,GAAG,IAAI,EACd,UAAU,GACX,GAAG,OAAO,CAAC;IACZ,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,yEAAyE;IACzE,0EAA0E;IAC1E,MAAM,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE;QACzC,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO,KAAK,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3D,OAAO,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,KAAK,MAAM,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAgB,GAAG,EAAE;QAChD,IAAI,CAAC,UAAU,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC;QAC9D,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAC3D,UAAU,CAAC,IAAI,CAChB,CAAC;QACF,OAAO,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,QAAQ,CAAC;QACrB,QAAQ,EAAE,CAAC,kBAAkB,EAAE,SAAS,EAAE,aAAa,CAAC;QACxD,OAAO,EAAE,KAAK,IAAI,EAAE;;YAClB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;YAEpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YACrD,CAAC;YAED,OAAO;gBACL,WAAW,EAAE,IAAI;gBACjB,UAAU,EAAE,MAAA,MAAM,CAAC,IAAI,0CAAE,UAAU;aACpC,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC,SAAS;QAC/B,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;QACxB,oBAAoB,EAAE,KAAK;KAC5B,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,IAAI,CAAC;IAExC,2DAA2D;IAC3D,2EAA2E;IAC3E,4EAA4E;IAC5E,kEAAkE;IAClE,oEAAoE;IACpE,uCAAuC;IACvC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,kBAAkB;YAAE,OAAO;QAEhC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1C,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAEzC,IAAI,cAAc,EAAE,CAAC;YACnB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAC1C,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QAE/D,WAAW,CAAC,iBAAiB,CAAC;YAC5B,QAAQ,EAAE,CAAC,kBAAkB,EAAE,SAAS,EAAE,aAAa,CAAC;SACzD,CAAC,CAAC;IACL,CAAC,EAAE;QACD,kBAAkB;QAClB,SAAS;QACT,aAAa;QACb,cAAc;QACd,WAAW;KACZ,CAAC,CAAC;IAEH,uCAAY,KAAK,KAAE,kBAAkB,EAAE,UAAU,IAAG;AACtD,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAA6B,EAC7B,iBAA0B,EAC1B,OAGC;;IAED,MAAM,OAAO,GAAG,iBAAiB,IAAI,CAAC,CAAC,SAAS,CAAC;IACjD,MAAM,KAAK,GAAG,wBAAwB,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,EAAE,kCACjD,OAAO,KACV,OAAO,IACP,CAAC;IAEH,MAAM,iBAAiB,GAAG,OAAO,IAAI,KAAK,CAAC,SAAS,CAAC;IACrD,MAAM,eAAe,GAAG,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC;IACjD,MAAM,WAAW,GAAG,CAAA,MAAA,KAAK,CAAC,IAAI,0CAAE,WAAW,MAAK,IAAI,CAAC;IACrD,MAAM,WAAW,GAAG,OAAO,IAAI,WAAW,CAAC;IAC3C,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,YAAY,GAChB,OAAO,IAAI,CAAC,iBAAiB,IAAI,CAAC,eAAe,IAAI,CAAC,WAAW,CAAC;IAEpE,OAAO;QACL,OAAO;QACP,WAAW;QACX,iBAAiB;QACjB,eAAe;QACf,WAAW;QACX,YAAY;KACb,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\n\nimport { useQuery, useQueryClient } from '@tanstack/react-query';\n\n/**\n * Result shape of an integration's check-connection server action\n * (the standard enhanceAction envelope).\n */\nexport interface ConnectionCheckResult {\n success: boolean;\n data?: { obtainedAt?: string | null } | null;\n error?: string;\n}\n\nexport type ConnectionCheckAction = (input: {\n accountId: string;\n}) => Promise<ConnectionCheckResult>;\n\n/**\n * Optional OAuth failure query param an integration's connect route may\n * append on redirect (e.g. dropbox_error=credentials_not_configured).\n */\nexport interface OAuthErrorParam {\n name: string;\n /** Map the raw param value to a user-facing message; return null to ignore. */\n toMessage: (value: string) => string | null;\n}\n\nexport interface UseOAuthConnectionStatusOptions {\n /**\n * Cache key segment, by convention `<slug>-connection`. The full query key\n * is ['integration-data', accountId, connectionKey] so all widgets and the\n * activation form share one deduped request per dashboard load.\n */\n connectionKey: string;\n checkConnection: ConnectionCheckAction;\n /** Gate the query (e.g. on integration-active state). Defaults to true. */\n enabled?: boolean;\n errorParam?: OAuthErrorParam;\n}\n\n/**\n * Shared OAuth connection-status hook. Detects the `oauth_success=true`\n * return from an integration's connect route, strips the transient params\n * from the URL, and invalidates the cached status so dependent UI flips to\n * connected without a manual refresh.\n */\nexport function useOAuthConnectionStatus(\n accountId: string,\n options: UseOAuthConnectionStatusOptions,\n) {\n const {\n connectionKey,\n checkConnection,\n enabled = true,\n errorParam,\n } = options;\n const queryClient = useQueryClient();\n\n // Read the OAuth return params synchronously on mount (not in an effect)\n // so the first render already knows whether we just came back from OAuth.\n const [oauthJustCompleted] = useState(() => {\n if (typeof window === 'undefined') return false;\n const params = new URLSearchParams(window.location.search);\n return params.get('oauth_success') === 'true';\n });\n\n const [oauthError] = useState<string | null>(() => {\n if (!errorParam || typeof window === 'undefined') return null;\n const value = new URLSearchParams(window.location.search).get(\n errorParam.name,\n );\n return value ? errorParam.toMessage(value) : null;\n });\n\n const query = useQuery({\n queryKey: ['integration-data', accountId, connectionKey],\n queryFn: async () => {\n const result = await checkConnection({ accountId });\n\n if (!result.success) {\n return { isConnected: false, error: result.error };\n }\n\n return {\n isConnected: true,\n obtainedAt: result.data?.obtainedAt,\n };\n },\n enabled: enabled && !!accountId,\n staleTime: 5 * 60 * 1000,\n refetchOnWindowFocus: false,\n });\n\n const errorParamName = errorParam?.name;\n\n // Justified useEffect: after the OAuth redirect lands back\n // on this page with `?oauth_success=true`, we must (1) strip the transient\n // query params from the URL and (2) invalidate the cached connection status\n // so widgets flip to connected without a manual refresh. Both are\n // post-render side effects on external systems (history API + query\n // cache), not derivable during render.\n useEffect(() => {\n if (!oauthJustCompleted) return;\n\n const url = new URL(window.location.href);\n url.searchParams.delete('oauth_success');\n\n if (errorParamName) {\n url.searchParams.delete(errorParamName);\n }\n\n window.history.replaceState({}, '', url.pathname + url.search);\n\n queryClient.invalidateQueries({\n queryKey: ['integration-data', accountId, connectionKey],\n });\n }, [\n oauthJustCompleted,\n accountId,\n connectionKey,\n errorParamName,\n queryClient,\n ]);\n\n return { ...query, oauthJustCompleted, oauthError };\n}\n\n/**\n * Resolves the gating booleans every OAuth-backed dashboard widget needs:\n *\n * - `enabled` — the integration is active and an account id is present.\n * - `isConnected` — a live OAuth connection exists (access token).\n * - `dataEnabled` — safe to fire the widget's data query (active + connected).\n * - `connectionPending` — still resolving the connection status.\n * - `connectionError` — the connection check itself failed (network/5xx).\n * Distinct from `notConnected`: a transient failure should surface as an\n * error, not as a misleading \"connect X\" prompt.\n * - `notConnected` — activated, resolved without error, but no OAuth\n * connection. The widget should render its \"connect X\" inactive state.\n *\n * The underlying connection check shares one query key across all widgets,\n * so react-query dedupes it to a single request per dashboard load.\n */\nexport function useOAuthWidgetGate(\n accountId: string | undefined,\n integrationActive: boolean,\n options: Pick<\n UseOAuthConnectionStatusOptions,\n 'connectionKey' | 'checkConnection'\n >,\n) {\n const enabled = integrationActive && !!accountId;\n const query = useOAuthConnectionStatus(accountId ?? '', {\n ...options,\n enabled,\n });\n\n const connectionPending = enabled && query.isPending;\n const connectionError = enabled && query.isError;\n const isConnected = query.data?.isConnected === true;\n const dataEnabled = enabled && isConnected;\n // Only treat as \"not connected\" when the check resolved successfully with\n // no token — a query error is an error state, not a disconnected account.\n const notConnected =\n enabled && !connectionPending && !connectionError && !isConnected;\n\n return {\n enabled,\n isConnected,\n connectionPending,\n connectionError,\n dataEnabled,\n notConnected,\n };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
*
|
|
9
9
|
* The SDK OWNS these definitions (`./types` — nothing imported from `@kit/*`);
|
|
10
10
|
* `@kit/integrations-core` keeps copies of some for now, and the parity guard
|
|
11
|
-
* (
|
|
11
|
+
* (a host-side parity test asserts it —
|
|
12
12
|
* core-side since the inversion, because the dependency arrow is core → SDK)
|
|
13
13
|
* fails core's typecheck on any drift.
|
|
14
14
|
*
|
|
15
15
|
* Surface discipline: additions require a second consumer and a line in
|
|
16
|
-
*
|
|
16
|
+
* api-report.md, the checked-in snapshot of every entrypoint's exports.
|
|
17
|
+
* Keep the whole surface readable in one pass.
|
|
17
18
|
*/
|
|
18
19
|
export type { IntegrationMetadata, IntegrationCapability, IntegrationPermission, IntegrationConfig, IntegrationComponentProps, ActivationFormProps, ActivationResult, MarketplaceTileProps, WidgetConfig, WorkspaceTargetDefinition, WidgetAskContext, WidgetSnapshot, WidgetSuggestedPrompt, HealthCheckResult, HealthStatus, AccountProductData, AccountProductDataType, } from './types/index.js';
|
|
19
20
|
export type { IntegrationContext, IntegrationActor, IntegrationStorage, ScopedStore, IntegrationSecrets, IntegrationFetch, IntegrationLogger, StorageEntry, StorageWriteOptions, StorageSchemas, StorageSchemaMap, StorageScopeSchemas, StorageKeyDeclaration, StorageKeyDeclarationInput, StorageKeySchema, } from './context/types.js';
|
package/dist/index.js
CHANGED
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
*
|
|
9
9
|
* The SDK OWNS these definitions (`./types` — nothing imported from `@kit/*`);
|
|
10
10
|
* `@kit/integrations-core` keeps copies of some for now, and the parity guard
|
|
11
|
-
* (
|
|
11
|
+
* (a host-side parity test asserts it —
|
|
12
12
|
* core-side since the inversion, because the dependency arrow is core → SDK)
|
|
13
13
|
* fails core's typecheck on any drift.
|
|
14
14
|
*
|
|
15
15
|
* Surface discipline: additions require a second consumer and a line in
|
|
16
|
-
*
|
|
16
|
+
* api-report.md, the checked-in snapshot of every entrypoint's exports.
|
|
17
|
+
* Keep the whole surface readable in one pass.
|
|
17
18
|
*/
|
|
18
19
|
export {};
|
|
19
20
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG","sourcesContent":["/**\n * @ekanos/sdk — the integration contract.\n *\n * Types only. This entrypoint is importable from any module, client or\n * server, and must stay that way: every export below is a `type` re-export,\n * so nothing here can pull runtime code into a client bundle. Runtime lives\n * in `@ekanos/sdk/components`, `@ekanos/sdk/hooks`, and `@ekanos/sdk/mcp`.\n *\n * The SDK OWNS these definitions (`./types` — nothing imported from `@kit/*`);\n * `@kit/integrations-core` keeps copies of some for now, and the parity guard\n * (a host-side parity test asserts it —\n * core-side since the inversion, because the dependency arrow is core → SDK)\n * fails core's typecheck on any drift.\n *\n * Surface discipline: additions require a second consumer and a line in\n * api-report.md, the checked-in snapshot of every entrypoint's exports.\n * Keep the whole surface readable in one pass.\n */\n\nexport type {\n // The integration definition\n IntegrationMetadata,\n IntegrationCapability,\n IntegrationPermission,\n IntegrationConfig,\n\n // Component contracts\n IntegrationComponentProps,\n ActivationFormProps,\n ActivationResult,\n MarketplaceTileProps,\n WidgetConfig,\n WorkspaceTargetDefinition,\n\n // AI ask-footer contract\n WidgetAskContext,\n WidgetSnapshot,\n WidgetSuggestedPrompt,\n\n // Health contract (required to implement checkHealth)\n HealthCheckResult,\n HealthStatus,\n\n // Account-scoped data seam\n AccountProductData,\n AccountProductDataType,\n} from './types';\n\nexport type {\n // The capability context — the one object partner code receives;\n // handed to MCP tool run() and server handlers; the mock lives in\n // @ekanos/sdk/testing, the shared runtime values in @ekanos/sdk/context.\n IntegrationContext,\n IntegrationActor,\n IntegrationStorage,\n ScopedStore,\n IntegrationSecrets,\n IntegrationFetch,\n IntegrationLogger,\n StorageEntry,\n StorageWriteOptions,\n\n // Storage schema declaration (ruling 1) — consumed by defineIntegration()\n // and createMockContext()\n StorageSchemas,\n StorageSchemaMap,\n StorageScopeSchemas,\n\n // Per-key declaration form carrying exposure flags. `clientReadable`\n // (default false) is what opts a key in to the generic browser-readable\n // storage route — see StorageKeyDeclaration for the full rationale.\n StorageKeyDeclaration,\n StorageKeyDeclarationInput,\n StorageKeySchema,\n} from './context/types';\n"]}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `defineIntegration()` — the v1 partner authoring contract
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the host adapts it internally).
|
|
3
|
+
* Partners never extend a base class: they hand the host a validated, frozen
|
|
4
|
+
* definition and the host adapts it internally.
|
|
6
5
|
*
|
|
7
6
|
* The validation logic and the schema itself live in the dependency-pure
|
|
8
7
|
* `@ekanos/integration-schema` (F3/F9): `defineIntegration()` validates at
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `defineIntegration()` — the v1 partner authoring contract
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the host adapts it internally).
|
|
3
|
+
* Partners never extend a base class: they hand the host a validated, frozen
|
|
4
|
+
* definition and the host adapts it internally.
|
|
6
5
|
*
|
|
7
6
|
* The validation logic and the schema itself live in the dependency-pure
|
|
8
7
|
* `@ekanos/integration-schema` (F3/F9): `defineIntegration()` validates at
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-integration.js","sourceRoot":"","sources":["../../src/integration/define-integration.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"define-integration.js","sourceRoot":"","sources":["../../src/integration/define-integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAGL,0BAA0B,GAC3B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAE/B,UAA0C;IAC1C,4EAA4E;IAC5E,yEAAyE;IACzE,uEAAuE;IACvE,6BAA6B;IAC7B,MAAM,MAAM,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAEtD,wEAAwE;IACxE,4EAA4E;IAC5E,uCAAuC;IACvC,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAEjC,OAAO,MAAmD,CAAC;AAC7D,CAAC","sourcesContent":["/**\n * `defineIntegration()` — the v1 partner authoring contract\n * Partners never extend a base class: they hand the host a validated, frozen\n * definition and the host adapts it internally.\n *\n * The validation logic and the schema itself live in the dependency-pure\n * `@ekanos/integration-schema` (F3/F9): `defineIntegration()` validates at\n * authoring time and `registerPartnerIntegration()` re-validates against the\n * SAME schema at the host trust boundary, so there is one contract with no\n * hand-written twin. This function adds only the generic authoring type;\n * `IntegrationDefinitionSchema` is re-exported for the promote gate and\n * dev-mcp validators.\n */\nimport {\n type IntegrationDefinition,\n type StorageSchemas,\n parseIntegrationDefinition,\n} from '@ekanos/integration-schema';\n\nimport { assertEventSurfacesValid } from './event-surfaces';\n\n/**\n * Validates a partner integration definition and returns it deep-frozen.\n *\n * `parseIntegrationDefinition` performs the validation AND the deep-freeze\n * (F4: the canonical parser freezes so both this and\n * `registerPartnerIntegration()` return immutable output). Throws with a\n * remediation-instruction message on invalid input. The declared `Schemas`\n * generic threads through to `ctx.storage` typing in each tool's `run`\n * handler and is preserved by `registerPartnerIntegration()`.\n * Cross-DEFINITION collisions (two packages, one slug) are\n * `validateIntegrationDefinitions()`'s job.\n */\nexport function defineIntegration<\n Schemas extends StorageSchemas = StorageSchemas,\n>(definition: IntegrationDefinition<Schemas>): IntegrationDefinition<Schemas> {\n // parseIntegrationDefinition returns the loose (default-generic) shape; the\n // storage/tool generic cannot be recovered from a runtime parse, but the\n // parsed value IS the same definition, so re-narrowing to the caller's\n // declared Schemas is sound.\n const parsed = parseIntegrationDefinition(definition);\n\n // SDK-layer event-surface rules the zod-only schema package cannot own:\n // 5-field cron syntax on every schedule, and OAuth endpoint origins covered\n // by the definition's own egress list.\n assertEventSurfacesValid(parsed);\n\n return parsed as unknown as IntegrationDefinition<Schemas>;\n}\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @ekanos/sdk/integration — the partner authoring contract.
|
|
3
3
|
*
|
|
4
4
|
* `defineIntegration()` is THE way a partner declares an integration
|
|
5
|
-
*
|
|
5
|
+
* Partners never extend a base class.
|
|
6
6
|
* The host adapts the returned definition internally via
|
|
7
7
|
* `registerPartnerIntegration` in `@kit/integrations-core`, which re-parses
|
|
8
8
|
* against the SAME canonical schema (`@ekanos/integration-schema`) at the
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* no `server-only`.
|
|
13
13
|
*
|
|
14
14
|
* Surface discipline: additions require an entry in
|
|
15
|
-
*
|
|
15
|
+
* api-report.md, regenerated by `pnpm --filter @ekanos/sdk api-report`.
|
|
16
16
|
*/
|
|
17
17
|
export { defineIntegration } from './define-integration.js';
|
|
18
18
|
export { parseCronExpression } from './cron.js';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @ekanos/sdk/integration — the partner authoring contract.
|
|
3
3
|
*
|
|
4
4
|
* `defineIntegration()` is THE way a partner declares an integration
|
|
5
|
-
*
|
|
5
|
+
* Partners never extend a base class.
|
|
6
6
|
* The host adapts the returned definition internally via
|
|
7
7
|
* `registerPartnerIntegration` in `@kit/integrations-core`, which re-parses
|
|
8
8
|
* against the SAME canonical schema (`@ekanos/integration-schema`) at the
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* no `server-only`.
|
|
13
13
|
*
|
|
14
14
|
* Surface discipline: additions require an entry in
|
|
15
|
-
*
|
|
15
|
+
* api-report.md, regenerated by `pnpm --filter @ekanos/sdk api-report`.
|
|
16
16
|
*/
|
|
17
17
|
export { defineIntegration } from './define-integration.js';
|
|
18
18
|
// Event-surface validation values: the 5-field cron parser backing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/integration/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,mEAAmE;AACnE,0EAA0E;AAC1E,0EAA0E;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAE7C,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC","sourcesContent":["/**\n * @ekanos/sdk/integration — the partner authoring contract.\n *\n * `defineIntegration()` is THE way a partner declares an integration\n *
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/integration/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,mEAAmE;AACnE,0EAA0E;AAC1E,0EAA0E;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAE7C,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC","sourcesContent":["/**\n * @ekanos/sdk/integration — the partner authoring contract.\n *\n * `defineIntegration()` is THE way a partner declares an integration\n * Partners never extend a base class.\n * The host adapts the returned definition internally via\n * `registerPartnerIntegration` in `@kit/integrations-core`, which re-parses\n * against the SAME canonical schema (`@ekanos/integration-schema`) at the\n * trust boundary — one contract, no structural twin (F3/F9).\n *\n * Dependency-pure and isomorphic: zod plus the schema package, no `@kit/*`,\n * no `server-only`.\n *\n * Surface discipline: additions require an entry in\n * api-report.md, regenerated by `pnpm --filter @ekanos/sdk api-report`.\n */\n\nexport { defineIntegration } from './define-integration';\n\n// Event-surface validation values: the 5-field cron parser backing\n// `defineIntegration()`'s schedule validation, exported so validators and\n// the harness can check/describe an expression the same way the SDK does.\nexport { parseCronExpression } from './cron';\n\nexport {\n IntegrationDefinitionSchema,\n validateIntegrationDefinitions,\n} from '@ekanos/integration-schema';\n\nexport type {\n IntegrationDefinition,\n IntegrationComponentDeclarations,\n IntegrationProposals,\n IntegrationCapabilityDeclaration,\n IntegrationPermissionDeclaration,\n PartnerWidgetDeclaration,\n PartnerToolModule,\n PartnerToolParameters,\n ToolClassificationProposal,\n DefinitionCollisionInput,\n FirstPartyInventory,\n // Event surfaces (webhooks, schedules, OAuth): declared in the definition,\n // executed locally by the harness/testing helpers today; the host's real\n // transports (public ingress, scheduler, hosted OAuth callback) bind to\n // these exact declarations later with no partner code change.\n PartnerWebhookDeclaration,\n WebhookSignatureDeclaration,\n WebhookEvent,\n WebhookResult,\n PartnerScheduleDeclaration,\n ScheduleInvocation,\n ScheduleResult,\n PartnerOAuthDeclaration,\n OAuthProviderDeclaration,\n OAuthTokens,\n} from '@ekanos/integration-schema';\n"]}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* shared implementation from `@ekanos/sdk/context` that production uses.
|
|
9
9
|
*
|
|
10
10
|
* Surface discipline: additions require an entry in
|
|
11
|
-
*
|
|
11
|
+
* api-report.md, regenerated by `pnpm --filter @ekanos/sdk api-report`.
|
|
12
12
|
*/
|
|
13
13
|
export { createMockContext } from './mock-context.js';
|
|
14
14
|
export type { MockContextOptions, MockFetchHandler, MockIntegrationContext, RecordedFetchCall, RecordedLog, } from './mock-context.js';
|
package/dist/testing/index.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* shared implementation from `@ekanos/sdk/context` that production uses.
|
|
9
9
|
*
|
|
10
10
|
* Surface discipline: additions require an entry in
|
|
11
|
-
*
|
|
11
|
+
* api-report.md, regenerated by `pnpm --filter @ekanos/sdk api-report`.
|
|
12
12
|
*/
|
|
13
13
|
export { createMockContext } from './mock-context.js';
|
|
14
14
|
// Event-surface invocation: run declared webhook/schedule handlers locally,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AASnD,4EAA4E;AAC5E,6EAA6E;AAC7E,4EAA4E;AAC5E,eAAe;AACf,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC","sourcesContent":["/**\n * @ekanos/sdk/testing — the partner test harness surface.\n *\n * `createMockContext()` is the day-1 in-memory `IntegrationContext`\n * (proposal §4): partners code and test against `ctx` here before anything\n * lands in a sandbox. Self-contained — no Supabase, no Vault, no network —\n * and enforcement (storage schemas, secret tiers, egress) is the same\n * shared implementation from `@ekanos/sdk/context` that production uses.\n *\n * Surface discipline: additions require an entry in\n *
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AASnD,4EAA4E;AAC5E,6EAA6E;AAC7E,4EAA4E;AAC5E,eAAe;AACf,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC","sourcesContent":["/**\n * @ekanos/sdk/testing — the partner test harness surface.\n *\n * `createMockContext()` is the day-1 in-memory `IntegrationContext`\n * (proposal §4): partners code and test against `ctx` here before anything\n * lands in a sandbox. Self-contained — no Supabase, no Vault, no network —\n * and enforcement (storage schemas, secret tiers, egress) is the same\n * shared implementation from `@ekanos/sdk/context` that production uses.\n *\n * Surface discipline: additions require an entry in\n * api-report.md, regenerated by `pnpm --filter @ekanos/sdk api-report`.\n */\n\nexport { createMockContext } from './mock-context';\nexport type {\n MockContextOptions,\n MockFetchHandler,\n MockIntegrationContext,\n RecordedFetchCall,\n RecordedLog,\n} from './mock-context';\n\n// Event-surface invocation: run declared webhook/schedule handlers locally,\n// with the same payload-validation and context-derivation semantics the real\n// transports will have. Used by partner unit tests and the harness Triggers\n// panel alike.\nexport { invokeWebhook, invokeSchedule } from './invoke';\nexport type {\n DefinitionContextOptions,\n InvokeWebhookOptions,\n InvokeScheduleOptions,\n WebhookInvocationOutcome,\n ScheduleInvocationOutcome,\n} from './invoke';\n"]}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SDK-owned type definitions
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `@kit/integrations-core`'s copies by `__tests__/core-parity.test-d.ts`.
|
|
2
|
+
* SDK-owned type definitions: the canonical partner-facing shapes live here,
|
|
3
|
+
* import nothing from `@kit/*`, and are held mutually assignable with the
|
|
4
|
+
* host's copies by a parity test. The full export list is api-report.md.
|
|
6
5
|
*/
|
|
7
6
|
export type { IconRenderer } from './icon.js';
|
|
8
7
|
export type { AccountProductData, AccountProductDataType, ActivationFormProps, ActivationResult, HealthCheckResult, HealthStatus, IntegrationCapability, IntegrationComponentProps, IntegrationConfig, IntegrationMetadata, IntegrationPermission, MarketplaceTileProps, WidgetConfig, } from './integration.js';
|
package/dist/types/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SDK-owned type definitions
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `@kit/integrations-core`'s copies by `__tests__/core-parity.test-d.ts`.
|
|
2
|
+
* SDK-owned type definitions: the canonical partner-facing shapes live here,
|
|
3
|
+
* import nothing from `@kit/*`, and are held mutually assignable with the
|
|
4
|
+
* host's copies by a parity test. The full export list is api-report.md.
|
|
6
5
|
*/
|
|
7
6
|
export {};
|
|
8
7
|
//# sourceMappingURL=index.js.map
|
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG","sourcesContent":["/**\n * SDK-owned type definitions: the canonical partner-facing shapes live here,\n * import nothing from `@kit/*`, and are held mutually assignable with the\n * host's copies by a parity test. The full export list is api-report.md.\n */\n\nexport type { IconRenderer } from './icon';\n\nexport type {\n AccountProductData,\n AccountProductDataType,\n ActivationFormProps,\n ActivationResult,\n HealthCheckResult,\n HealthStatus,\n IntegrationCapability,\n IntegrationComponentProps,\n IntegrationConfig,\n IntegrationMetadata,\n IntegrationPermission,\n MarketplaceTileProps,\n WidgetConfig,\n} from './integration';\n\nexport type {\n WidgetAskContext,\n WidgetSnapshot,\n WidgetSuggestedPrompt,\n} from './widget-ask-context';\n\nexport type { WorkspaceTargetDefinition } from './workspace-target';\n"]}
|
|
@@ -112,7 +112,7 @@ export interface IntegrationMetadata {
|
|
|
112
112
|
* 'user' — credentials or identity are personal (ctx.user.id, personal
|
|
113
113
|
* OAuth, session reads like getSupabaseServerClient()/requireUser()).
|
|
114
114
|
* NEVER machine-executable: a workflow would silently ride one
|
|
115
|
-
* employee's personal grant
|
|
115
|
+
* employee's personal grant.
|
|
116
116
|
* 'source' — platform-level credentials (diagnostics-class integrations).
|
|
117
117
|
* Not exposed to account workflows.
|
|
118
118
|
*
|
|
@@ -143,7 +143,7 @@ export interface IntegrationMetadata {
|
|
|
143
143
|
* declare `getSidebarNav()` and MUST NOT declare `getWorkspaceTargets()` —
|
|
144
144
|
* its widgets are placed onto whatever workspace an admin chooses in the
|
|
145
145
|
* composer (`/admin/sources/[id]/layout`) rather than onto a workspace
|
|
146
|
-
* named after itself.
|
|
146
|
+
* named after itself. A host-side test
|
|
147
147
|
* fails the build on either violation.
|
|
148
148
|
*/
|
|
149
149
|
kind?: 'integration' | 'feature';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.js","sourceRoot":"","sources":["../../src/types/integration.ts"],"names":[],"mappings":"","sourcesContent":["import type { ComponentType } from 'react';\n\nimport type { IconRenderer } from './icon';\n\n// Capability shown on the integration detail page (numbered grid)\nexport interface IntegrationCapability {\n label: string;\n description: string;\n icon?: IconRenderer;\n}\n\n// Permission scope shown on the integration detail page\nexport interface IntegrationPermission {\n label: string;\n detail: string;\n type: 'read' | 'write';\n}\n\n// ---- Integration Health Monitoring (issue #474) -----------------------------\n\n// Higher = healthier. Used internally for \"least healthy wins\" merging.\nexport type HealthStatus = 'healthy' | 'degraded' | 'unhealthy' | 'unknown';\n\n/**\n * Result returned by `BaseIntegration.healthCheck(accountId)`. Routed through\n * `classifyHealth()` (server-side) before writing to\n * `integration_health_status`.\n */\nexport interface HealthCheckResult {\n status: HealthStatus;\n errorCode?: string;\n errorMessage?: string;\n /** Rolling 24h error rate from `account_product_usage_events`, 0..100. */\n errorRatePct?: number;\n /** Sample size used to compute errorRatePct; if below threshold, treated as unknown. */\n sampleSize?: number;\n /** Whether the most recent observed call succeeded. */\n lastObservationSucceeded?: boolean;\n /** Token/credential expiry, if known. Drives token-expiry warnings. */\n tokenExpiresAt?: string;\n /** Free-form per-integration data carried to the dashboard. */\n metadata?: Record<string, unknown>;\n}\n\n// Activation result from integration\nexport interface ActivationResult {\n success: boolean;\n configData?: Record<string, unknown>;\n externalId?: string;\n errorMessage?: string;\n metadata?: Record<string, unknown>;\n}\n\n// Base props that all integration components need\ninterface BaseIntegrationComponentProps {\n accountId: string;\n sourceId?: string;\n integrationConfig?: Record<string, unknown>;\n}\n\n// Discriminated union for product reference - only one allowed\ntype ProductReference =\n | { productId: string; productSlug?: never }\n | { productSlug: string; productId?: never };\n\n// New base type using discriminated union\nexport type IntegrationComponentProps = BaseIntegrationComponentProps &\n ProductReference;\n\n// Marketplace tile props\nexport type MarketplaceTileProps = IntegrationComponentProps & {\n onActivate?: () => void;\n isActivated?: boolean;\n /** Navigation URL for the integration detail page */\n href?: string;\n};\n\n// Activation form props\nexport type ActivationFormProps = IntegrationComponentProps & {\n onSuccess?: (result: ActivationResult) => void;\n onCancel?: () => void;\n isLoading?: boolean;\n /** Render inline instead of in a dialog */\n inline?: boolean;\n /**\n * The TEAM account context the user is activating within — separate from\n * `accountId`, which for `scope: 'user'` integrations is collapsed to the\n * personal account for activation storage/token purposes. Only consumed by\n * workspace materialization (`materializeWorkspaceOnActivation`), never for\n * activation/token storage itself (plan 009 Part A2). Optional: undefined\n * for team-scoped integrations (their `accountId` already IS the team) and\n * for any caller that hasn't threaded it yet — the server action falls back\n * to `accountId` when absent.\n */\n teamAccountId?: string;\n};\n\n// Integration metadata\nexport interface IntegrationMetadata {\n productId: string;\n productSlug: string;\n integrationName: string;\n description: string;\n category: string;\n version: string;\n icon?: string;\n /** Bundled logo URL — overrides product.logo_path on the marketplace */\n logoPath?: string;\n /** When 'user', activation data is stored under the user's personal account (user.id) instead of the team account */\n scope?: 'user' | 'team';\n /**\n * Set FALSE to assert this integration has NO self-serve activation surface —\n * the marketplace detail page then renders no activation form at all.\n *\n * This is deliberately distinct from \"has no CUSTOM activation form\": an\n * integration that omits `getActivationForm()` still gets the generic one, and\n * six integrations depend on that. Use this flag only when submitting ANY\n * activation form would be a dead end (e.g. Workflows, which is turned on by\n * the `source_configs.enable_workflows` feature flag and whose `activate()`\n * throws 'not implemented' — showing a form there hands the user a button that\n * cannot work). Undefined/true = normal self-serve activation.\n */\n selfServeActivation?: boolean;\n /**\n * How this integration's MCP tools resolve credentials — the integration's\n * SELF-DECLARATION of machine-executability, consumed dynamically by the\n * workflow engine's fail-closed tool allowlist (isGatewayExposableTool).\n *\n * 'account' — credentials/identity resolve from team- or source-level\n * config via the ToolContext (`getAccountId(ctx)` + `ctx.supabase`).\n * Safe for durable machine-principal execution (workflows): eligible\n * tools (read + public/internal sensitivity) become workflow-callable.\n * 'user' — credentials or identity are personal (ctx.user.id, personal\n * OAuth, session reads like getSupabaseServerClient()/requireUser()).\n * NEVER machine-executable: a workflow would silently ride one\n * employee's personal grant (N8N_INTEGRATION_PLAN adversarial #4).\n * 'source' — platform-level credentials (diagnostics-class integrations).\n * Not exposed to account workflows.\n *\n * UNDECLARED = fail closed (treated as not machine-executable). Declaring\n * 'account' is a security assertion: the integration's MCP run() handlers\n * must use ctx-based resolution ONLY — no session clients, no personal\n * grants. A guard test in @kit/integrations-workflows enforces the obvious\n * violations (session-client reads in mcp/ code of 'account' declarers).\n */\n credentialModel?: 'account' | 'user' | 'source';\n /**\n * What KIND of thing this integration is — the platform's presentation and\n * governance discriminant. Undefined means `'integration'`, which is what\n * every third-party connector is; the field only ever needs setting to opt\n * INTO feature treatment.\n *\n * 'integration' — connects Fusion to a third party. Has credentials, an\n * activation flow, and a marketplace presence. Its widgets live on\n * workspace dashboards and it declares its workspaces via\n * `getWorkspaceTargets()`.\n * 'feature' — a Fusion-native capability with a bespoke experience: no\n * third-party credentials, its own route tree under\n * `/home/[account]/…`, and its own sidebar section declared via\n * `getSidebarNav()` (optionally rendered by its own\n * `getSidebarComponent()`).\n *\n * The two are mutually exclusive on the nav question. A `'feature'` MUST\n * declare `getSidebarNav()` and MUST NOT declare `getWorkspaceTargets()` —\n * its widgets are placed onto whatever workspace an admin chooses in the\n * composer (`/admin/sources/[id]/layout`) rather than onto a workspace\n * named after itself. `apps/web/lib/workspaces/__tests__/sidebar-nav-declarations.test.ts`\n * fails the build on either violation.\n */\n kind?: 'integration' | 'feature';\n}\n\n// Widget configuration\nexport interface WidgetConfig {\n id: string;\n name: string;\n component: ComponentType<IntegrationComponentProps>;\n gridSize?: { cols: number; rows: number } | { cols: number; rows: number }[];\n gridPosition?: { col: number; row: number };\n widgetState: 'active' | 'inactive' | 'disabled';\n // React-grid-layout format\n layouts?: {\n lg?: { x: number; y: number; w: number; h: number; maxHeight?: number };\n md?: { x: number; y: number; w: number; h: number; maxHeight?: number };\n sm?: { x: number; y: number; w: number; h: number; maxHeight?: number };\n };\n // Integration metadata for widgets\n integrationMetadata?: IntegrationMetadata;\n category?: { id: string; name: string; slug: string; icon: string | null };\n // Database product ID (UUID) from widget_config table\n productId?: string;\n isCollapsible?: boolean;\n // For collapsed state persistence\n collapsed?: boolean;\n widgetConfigId?: string;\n // Resolved workspace placement (explicit widget_config.workspace_id\n // override, else the product's inheriting attachment). Populated by the\n // dashboard widgets loader; null = no workspace (unscoped dashboard).\n workspaceId?: string | null;\n isPinnable?: boolean;\n isPinned?: boolean;\n // When true, the dashboard renders the \"Ask about this\" AI footer bar for\n // this widget. The widget may still pass `askContext` to the wrapper for a\n // rich snapshot; otherwise a minimal default is used.\n aiFooterEnabled?: boolean;\n // Integration health for this widget's product. `unhealthy` downgrades the\n // widget to `disabled`; `degraded` surfaces a stale-data footer.\n health?: {\n status: HealthStatus;\n lastSuccessAt?: string | null;\n errorMessage?: string | null;\n };\n}\n\n// Database types for integration tables.\n//\n// PARTNER-VISIBLE SUBSET: these row types deliberately OMIT `vault_secret_id`.\n// A vault id is a host handle to a decryptable secret; the partner surface\n// never exposes one (docs/devex/sdk-export-map.md, \"Vault access\" —\n// `ctx.secrets` fences it off). `@kit/integrations-core` keeps the full row\n// (host code needs the handle); `types/__tests__/core-parity.test-d.ts` pins\n// the SDK type as core's row minus exactly the host-only fields, so a new\n// core column cannot drift in here unnoticed.\nexport interface IntegrationConfig {\n id: string;\n account_id: string | null;\n product_id: string;\n config_type: 'api_credentials' | 'activation_data' | 'settings';\n config_data: Record<string, unknown>;\n status: 'active' | 'inactive' | 'pending' | 'error' | 'suspended';\n is_active: boolean;\n created_at: string;\n updated_at: string;\n created_by: string | null;\n updated_by: string | null;\n}\n\n/**\n * The PARTNER-VISIBLE `data_type` values on `account_product_data` — a strict\n * SUBSET of `@kit/integrations-core`'s union.\n *\n * `'secret'` is deliberately absent. Secret rows are host-managed (one row per\n * secret name, value in Vault, `vault_secret_id` on the row), written only by\n * the capability context's `persistSecret` and read only through\n * `ctx.secrets`. Naming the kind here would advertise a row shape partner code\n * must never address: `ctx.storage` rejects it, and core's generic accessors\n * reject it too (`config-utils.ts`, `assertNotHostOnlyDataType`) precisely\n * because a write there would land the plaintext in the `data` column.\n *\n * When you add an integration-specific kind, add it in BOTH places (core owns\n * the full union) and keep this one partner-appropriate. Prefer `dataSubtype`\n * for orthogonal slicing within a kind (e.g. `data_type='cache'`,\n * `data_subtype='profile'`); reserve a new top-level kind for data that has a\n * distinct lifecycle or is queried independently.\n */\nexport type AccountProductDataType =\n | 'activation'\n | 'settings'\n | 'metrics_summary'\n | 'sync_state'\n | 'cache'\n // Integration-specific kinds — extend here when needed.\n | 'cash_forecast' // quickbooks — user-supplied manual cash-forecast estimates\n | 'tax_config'; // quickbooks — per-user federal/state tax rate config\n\nexport interface AccountProductData {\n id: string;\n account_id: string;\n product_id: string;\n data_type: AccountProductDataType;\n data_subtype?: string;\n data: Record<string, unknown>;\n expires_at?: string;\n integration_config_id?: string;\n external_id?: string;\n created_at: string;\n updated_at: string;\n created_by: string | null;\n updated_by: string | null;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"integration.js","sourceRoot":"","sources":["../../src/types/integration.ts"],"names":[],"mappings":"","sourcesContent":["import type { ComponentType } from 'react';\n\nimport type { IconRenderer } from './icon';\n\n// Capability shown on the integration detail page (numbered grid)\nexport interface IntegrationCapability {\n label: string;\n description: string;\n icon?: IconRenderer;\n}\n\n// Permission scope shown on the integration detail page\nexport interface IntegrationPermission {\n label: string;\n detail: string;\n type: 'read' | 'write';\n}\n\n// ---- Integration Health Monitoring (issue #474) -----------------------------\n\n// Higher = healthier. Used internally for \"least healthy wins\" merging.\nexport type HealthStatus = 'healthy' | 'degraded' | 'unhealthy' | 'unknown';\n\n/**\n * Result returned by `BaseIntegration.healthCheck(accountId)`. Routed through\n * `classifyHealth()` (server-side) before writing to\n * `integration_health_status`.\n */\nexport interface HealthCheckResult {\n status: HealthStatus;\n errorCode?: string;\n errorMessage?: string;\n /** Rolling 24h error rate from `account_product_usage_events`, 0..100. */\n errorRatePct?: number;\n /** Sample size used to compute errorRatePct; if below threshold, treated as unknown. */\n sampleSize?: number;\n /** Whether the most recent observed call succeeded. */\n lastObservationSucceeded?: boolean;\n /** Token/credential expiry, if known. Drives token-expiry warnings. */\n tokenExpiresAt?: string;\n /** Free-form per-integration data carried to the dashboard. */\n metadata?: Record<string, unknown>;\n}\n\n// Activation result from integration\nexport interface ActivationResult {\n success: boolean;\n configData?: Record<string, unknown>;\n externalId?: string;\n errorMessage?: string;\n metadata?: Record<string, unknown>;\n}\n\n// Base props that all integration components need\ninterface BaseIntegrationComponentProps {\n accountId: string;\n sourceId?: string;\n integrationConfig?: Record<string, unknown>;\n}\n\n// Discriminated union for product reference - only one allowed\ntype ProductReference =\n | { productId: string; productSlug?: never }\n | { productSlug: string; productId?: never };\n\n// New base type using discriminated union\nexport type IntegrationComponentProps = BaseIntegrationComponentProps &\n ProductReference;\n\n// Marketplace tile props\nexport type MarketplaceTileProps = IntegrationComponentProps & {\n onActivate?: () => void;\n isActivated?: boolean;\n /** Navigation URL for the integration detail page */\n href?: string;\n};\n\n// Activation form props\nexport type ActivationFormProps = IntegrationComponentProps & {\n onSuccess?: (result: ActivationResult) => void;\n onCancel?: () => void;\n isLoading?: boolean;\n /** Render inline instead of in a dialog */\n inline?: boolean;\n /**\n * The TEAM account context the user is activating within — separate from\n * `accountId`, which for `scope: 'user'` integrations is collapsed to the\n * personal account for activation storage/token purposes. Only consumed by\n * workspace materialization (`materializeWorkspaceOnActivation`), never for\n * activation/token storage itself (plan 009 Part A2). Optional: undefined\n * for team-scoped integrations (their `accountId` already IS the team) and\n * for any caller that hasn't threaded it yet — the server action falls back\n * to `accountId` when absent.\n */\n teamAccountId?: string;\n};\n\n// Integration metadata\nexport interface IntegrationMetadata {\n productId: string;\n productSlug: string;\n integrationName: string;\n description: string;\n category: string;\n version: string;\n icon?: string;\n /** Bundled logo URL — overrides product.logo_path on the marketplace */\n logoPath?: string;\n /** When 'user', activation data is stored under the user's personal account (user.id) instead of the team account */\n scope?: 'user' | 'team';\n /**\n * Set FALSE to assert this integration has NO self-serve activation surface —\n * the marketplace detail page then renders no activation form at all.\n *\n * This is deliberately distinct from \"has no CUSTOM activation form\": an\n * integration that omits `getActivationForm()` still gets the generic one, and\n * six integrations depend on that. Use this flag only when submitting ANY\n * activation form would be a dead end (e.g. Workflows, which is turned on by\n * the `source_configs.enable_workflows` feature flag and whose `activate()`\n * throws 'not implemented' — showing a form there hands the user a button that\n * cannot work). Undefined/true = normal self-serve activation.\n */\n selfServeActivation?: boolean;\n /**\n * How this integration's MCP tools resolve credentials — the integration's\n * SELF-DECLARATION of machine-executability, consumed dynamically by the\n * workflow engine's fail-closed tool allowlist (isGatewayExposableTool).\n *\n * 'account' — credentials/identity resolve from team- or source-level\n * config via the ToolContext (`getAccountId(ctx)` + `ctx.supabase`).\n * Safe for durable machine-principal execution (workflows): eligible\n * tools (read + public/internal sensitivity) become workflow-callable.\n * 'user' — credentials or identity are personal (ctx.user.id, personal\n * OAuth, session reads like getSupabaseServerClient()/requireUser()).\n * NEVER machine-executable: a workflow would silently ride one\n * employee's personal grant.\n * 'source' — platform-level credentials (diagnostics-class integrations).\n * Not exposed to account workflows.\n *\n * UNDECLARED = fail closed (treated as not machine-executable). Declaring\n * 'account' is a security assertion: the integration's MCP run() handlers\n * must use ctx-based resolution ONLY — no session clients, no personal\n * grants. A guard test in @kit/integrations-workflows enforces the obvious\n * violations (session-client reads in mcp/ code of 'account' declarers).\n */\n credentialModel?: 'account' | 'user' | 'source';\n /**\n * What KIND of thing this integration is — the platform's presentation and\n * governance discriminant. Undefined means `'integration'`, which is what\n * every third-party connector is; the field only ever needs setting to opt\n * INTO feature treatment.\n *\n * 'integration' — connects Fusion to a third party. Has credentials, an\n * activation flow, and a marketplace presence. Its widgets live on\n * workspace dashboards and it declares its workspaces via\n * `getWorkspaceTargets()`.\n * 'feature' — a Fusion-native capability with a bespoke experience: no\n * third-party credentials, its own route tree under\n * `/home/[account]/…`, and its own sidebar section declared via\n * `getSidebarNav()` (optionally rendered by its own\n * `getSidebarComponent()`).\n *\n * The two are mutually exclusive on the nav question. A `'feature'` MUST\n * declare `getSidebarNav()` and MUST NOT declare `getWorkspaceTargets()` —\n * its widgets are placed onto whatever workspace an admin chooses in the\n * composer (`/admin/sources/[id]/layout`) rather than onto a workspace\n * named after itself. A host-side test\n * fails the build on either violation.\n */\n kind?: 'integration' | 'feature';\n}\n\n// Widget configuration\nexport interface WidgetConfig {\n id: string;\n name: string;\n component: ComponentType<IntegrationComponentProps>;\n gridSize?: { cols: number; rows: number } | { cols: number; rows: number }[];\n gridPosition?: { col: number; row: number };\n widgetState: 'active' | 'inactive' | 'disabled';\n // React-grid-layout format\n layouts?: {\n lg?: { x: number; y: number; w: number; h: number; maxHeight?: number };\n md?: { x: number; y: number; w: number; h: number; maxHeight?: number };\n sm?: { x: number; y: number; w: number; h: number; maxHeight?: number };\n };\n // Integration metadata for widgets\n integrationMetadata?: IntegrationMetadata;\n category?: { id: string; name: string; slug: string; icon: string | null };\n // Database product ID (UUID) from widget_config table\n productId?: string;\n isCollapsible?: boolean;\n // For collapsed state persistence\n collapsed?: boolean;\n widgetConfigId?: string;\n // Resolved workspace placement (explicit widget_config.workspace_id\n // override, else the product's inheriting attachment). Populated by the\n // dashboard widgets loader; null = no workspace (unscoped dashboard).\n workspaceId?: string | null;\n isPinnable?: boolean;\n isPinned?: boolean;\n // When true, the dashboard renders the \"Ask about this\" AI footer bar for\n // this widget. The widget may still pass `askContext` to the wrapper for a\n // rich snapshot; otherwise a minimal default is used.\n aiFooterEnabled?: boolean;\n // Integration health for this widget's product. `unhealthy` downgrades the\n // widget to `disabled`; `degraded` surfaces a stale-data footer.\n health?: {\n status: HealthStatus;\n lastSuccessAt?: string | null;\n errorMessage?: string | null;\n };\n}\n\n// Database types for integration tables.\n//\n// PARTNER-VISIBLE SUBSET: these row types deliberately OMIT `vault_secret_id`.\n// A vault id is a host handle to a decryptable secret; the partner surface\n// never exposes one — `ctx.secrets` fences it off. Host code keeps the full\n// row because it needs the handle; a parity test pins the SDK type as the\n// host's row minus exactly the host-only fields, so a new column cannot drift\n// in here unnoticed.\nexport interface IntegrationConfig {\n id: string;\n account_id: string | null;\n product_id: string;\n config_type: 'api_credentials' | 'activation_data' | 'settings';\n config_data: Record<string, unknown>;\n status: 'active' | 'inactive' | 'pending' | 'error' | 'suspended';\n is_active: boolean;\n created_at: string;\n updated_at: string;\n created_by: string | null;\n updated_by: string | null;\n}\n\n/**\n * The PARTNER-VISIBLE `data_type` values on `account_product_data` — a strict\n * SUBSET of `@kit/integrations-core`'s union.\n *\n * `'secret'` is deliberately absent. Secret rows are host-managed (one row per\n * secret name, value in Vault, `vault_secret_id` on the row), written only by\n * the capability context's `persistSecret` and read only through\n * `ctx.secrets`. Naming the kind here would advertise a row shape partner code\n * must never address: `ctx.storage` rejects it, and core's generic accessors\n * reject it too (`config-utils.ts`, `assertNotHostOnlyDataType`) precisely\n * because a write there would land the plaintext in the `data` column.\n *\n * When you add an integration-specific kind, add it in BOTH places (core owns\n * the full union) and keep this one partner-appropriate. Prefer `dataSubtype`\n * for orthogonal slicing within a kind (e.g. `data_type='cache'`,\n * `data_subtype='profile'`); reserve a new top-level kind for data that has a\n * distinct lifecycle or is queried independently.\n */\nexport type AccountProductDataType =\n | 'activation'\n | 'settings'\n | 'metrics_summary'\n | 'sync_state'\n | 'cache'\n // Integration-specific kinds — extend here when needed.\n | 'cash_forecast' // quickbooks — user-supplied manual cash-forecast estimates\n | 'tax_config'; // quickbooks — per-user federal/state tax rate config\n\nexport interface AccountProductData {\n id: string;\n account_id: string;\n product_id: string;\n data_type: AccountProductDataType;\n data_subtype?: string;\n data: Record<string, unknown>;\n expires_at?: string;\n integration_config_id?: string;\n external_id?: string;\n created_at: string;\n updated_at: string;\n created_by: string | null;\n updated_by: string | null;\n}\n"]}
|
|
@@ -16,7 +16,7 @@ export interface WidgetSuggestedPrompt {
|
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Context a widget passes to the AI assistant when its "Ask about this"
|
|
19
|
-
* bar is submitted. The bridge
|
|
19
|
+
* bar is submitted. The host's bridge attaches `snapshot` to the user
|
|
20
20
|
* message as AI SDK message metadata (NOT as visible chat text). The chat
|
|
21
21
|
* API route injects the snapshot into the system instruction so the model
|
|
22
22
|
* has authoritative widget state; the dock UI renders a small attachment
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-ask-context.js","sourceRoot":"","sources":["../../src/types/widget-ask-context.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A widget snapshot is a JSON-serializable view of what the user currently\n * sees in the widget. It MUST NOT contain React nodes, functions, class\n * instances, credentials, tokens, or internal-only IDs. The chat API route\n * validates the shape before injecting it into the system prompt.\n */\nexport type WidgetSnapshot = Record<string, unknown> | null;\n\n/**\n * A pre-canned prompt rendered as a pill inside the expanded \"Ask about this\"\n * footer. Clicking a suggestion dispatches the prompt to the assistant dock\n * along with the widget's snapshot.\n */\nexport interface WidgetSuggestedPrompt {\n label: string;\n prompt: string;\n}\n\n/**\n * Context a widget passes to the AI assistant when its \"Ask about this\"\n * bar is submitted. The bridge
|
|
1
|
+
{"version":3,"file":"widget-ask-context.js","sourceRoot":"","sources":["../../src/types/widget-ask-context.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * A widget snapshot is a JSON-serializable view of what the user currently\n * sees in the widget. It MUST NOT contain React nodes, functions, class\n * instances, credentials, tokens, or internal-only IDs. The chat API route\n * validates the shape before injecting it into the system prompt.\n */\nexport type WidgetSnapshot = Record<string, unknown> | null;\n\n/**\n * A pre-canned prompt rendered as a pill inside the expanded \"Ask about this\"\n * footer. Clicking a suggestion dispatches the prompt to the assistant dock\n * along with the widget's snapshot.\n */\nexport interface WidgetSuggestedPrompt {\n label: string;\n prompt: string;\n}\n\n/**\n * Context a widget passes to the AI assistant when its \"Ask about this\"\n * bar is submitted. The host's bridge attaches `snapshot` to the user\n * message as AI SDK message metadata (NOT as visible chat text). The chat\n * API route injects the snapshot into the system instruction so the model\n * has authoritative widget state; the dock UI renders a small attachment\n * chip above the user bubble using `title` as the label.\n */\nexport interface WidgetAskContext {\n widgetId: string;\n title: string;\n snapshot: WidgetSnapshot;\n suggestedPrompt: string;\n /**\n * Optional pre-canned prompts shown as pills above the input in the\n * expanded \"Ask about this\" footer. Use these to surface the same\n * contextual prompts that previously sat on the widget body.\n */\n suggestedPrompts?: WidgetSuggestedPrompt[];\n}\n"]}
|
package/eslint.preset.mjs
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* runs UNSANDBOXED, in-process, inside the host: the generated
|
|
6
6
|
* `partner-integration-bootstrap.ts` statically imports each partner package,
|
|
7
7
|
* so a partner module graph evaluates with full host authority before any
|
|
8
|
-
* validation runs
|
|
9
|
-
* `apps/web/scripts/generate-partner-integration-bootstrap.ts`).
|
|
8
|
+
* validation runs.
|
|
10
9
|
*
|
|
11
10
|
* The accepted T1 trust tier rests on exactly two controls:
|
|
12
11
|
*
|
|
@@ -16,8 +15,7 @@
|
|
|
16
15
|
* invitation to spot `globalThis.fetch` by eye.
|
|
17
16
|
*
|
|
18
17
|
* Runtime SANDBOXING of handlers is the deferred T3 tier. Until it exists,
|
|
19
|
-
* every rule below is load-bearing.
|
|
20
|
-
* (review outcome F1), `docs/devex/adversarial-review-2026-08-30.md`.
|
|
18
|
+
* every rule below is load-bearing.
|
|
21
19
|
*
|
|
22
20
|
* ── Why it lives here ────────────────────────────────────────────────────
|
|
23
21
|
* A partner already installs `@ekanos/sdk`, so the control ships with the
|