@ggui-ai/gadgets 0.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +121 -0
- package/dist/codegen.d.mts +78 -0
- package/dist/codegen.d.ts +78 -0
- package/dist/codegen.js +69 -0
- package/dist/codegen.mjs +34 -0
- package/dist/index.d.mts +663 -0
- package/dist/index.d.ts +663 -0
- package/dist/index.js +825 -0
- package/dist/index.mjs +790 -0
- package/package.json +76 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
import { GadgetHook, GadgetDescriptor, GadgetExportBase, JsonValue } from '@ggui-ai/protocol';
|
|
2
|
+
export { GadgetError, GadgetHook, GadgetStatus } from '@ggui-ai/protocol';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `createGguiGadget` — the plugin SDK factory for ggui client
|
|
6
|
+
* library wrappers.
|
|
7
|
+
*
|
|
8
|
+
* Authors compose 3rd-party JS libraries (Leaflet, Mapbox, Stripe,
|
|
9
|
+
* Chart.js, …) into stable React hooks that satisfy
|
|
10
|
+
* {@link GadgetHook}. The factory:
|
|
11
|
+
*
|
|
12
|
+
* 1. Strictly validates the spec at call time via
|
|
13
|
+
* `strictGadgetDescriptorSchema` — non-empty teaching text
|
|
14
|
+
* (`description` / `usage` / `example`), at least one of
|
|
15
|
+
* `package` / `bundleUrl`, plus a non-function `hookImpl` check
|
|
16
|
+
* the schema can't see. Throws {@link WrapperConformanceError}
|
|
17
|
+
* with field-level paths on any violation.
|
|
18
|
+
* 2. Returns the React hook function as the primary export, with
|
|
19
|
+
* the serializable {@link GadgetDescriptor} descriptor attached
|
|
20
|
+
* as `.descriptor`. Single export, dual purpose:
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* export const useLeafletMap = createGguiGadget({
|
|
24
|
+
* hook: 'useLeafletMap',
|
|
25
|
+
* description: '...',
|
|
26
|
+
* usage: '...',
|
|
27
|
+
* example: { ... },
|
|
28
|
+
* package: '@my-org/ggui-leaflet',
|
|
29
|
+
* styleUrl: '/leaflet.css',
|
|
30
|
+
* hookImpl: (options) => { …real React hook… },
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Call as a React hook from generated component code:
|
|
34
|
+
* const map = useLeafletMap({ center: [0, 0], zoom: 2 });
|
|
35
|
+
*
|
|
36
|
+
* // Register on App.gadgets via the descriptor:
|
|
37
|
+
* app.gadgets.push(useLeafletMap.descriptor);
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* Why no `bind: (lib) => …` indirection: wrappers bundle their
|
|
41
|
+
* underlying dependencies at build time (per the "ggui hosts every
|
|
42
|
+
* bundle" model that the CSP derivation depends on). Authors `import L
|
|
43
|
+
* from 'leaflet'` inside the wrapper and tsup/esbuild rolls it into
|
|
44
|
+
* the published bundle. The factory doesn't need to load 3rd-party
|
|
45
|
+
* libs at runtime — just validate the spec + plumb the descriptor.
|
|
46
|
+
*
|
|
47
|
+
* Why no separate `HookResult` shape: the existing protocol
|
|
48
|
+
* {@link GadgetHook} already nails the return contract
|
|
49
|
+
* (`{value, status, error?, start, stop?}`). Re-using it keeps
|
|
50
|
+
* stdlib hooks and 3rd-party plugins indistinguishable at the
|
|
51
|
+
* consumption site — generated component code calls them the same
|
|
52
|
+
* way.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Author input to {@link createGguiGadget}. A `createGguiGadget` call
|
|
57
|
+
* builds a gadget PACKAGE that exposes exactly one HOOK export — so
|
|
58
|
+
* the spec keeps the per-export teaching fields flat (`hook`,
|
|
59
|
+
* `description`, `usage`, `example`, `gotchas`, `permission`,
|
|
60
|
+
* `required`) alongside the package identity + transport fields
|
|
61
|
+
* (`package`, `version`, `bundleUrl`, …) and a `hookImpl` runtime
|
|
62
|
+
* function. The factory assembles these into a
|
|
63
|
+
* {@link GadgetDescriptor} of the package+exports shape.
|
|
64
|
+
*
|
|
65
|
+
* Generic over `TOutput` / `TOptions` so consumers get type-safe
|
|
66
|
+
* value + options surfaces. Defaults to `void` / `unknown` for hooks
|
|
67
|
+
* that take no options.
|
|
68
|
+
*/
|
|
69
|
+
interface GguiGadgetSpec<TOutput, TOptions = void> extends Omit<GadgetDescriptor, 'exports'>, Omit<GadgetExportBase, 'description' | 'usage' | 'example'> {
|
|
70
|
+
/**
|
|
71
|
+
* Hook name — `use`-prefixed camelCase. Becomes the single hook
|
|
72
|
+
* export of the assembled descriptor.
|
|
73
|
+
*/
|
|
74
|
+
hook: string;
|
|
75
|
+
/** REQUIRED — see {@link GadgetExportBase.description}. */
|
|
76
|
+
description: string;
|
|
77
|
+
/** REQUIRED — see {@link GadgetExportBase.usage}. */
|
|
78
|
+
usage: string;
|
|
79
|
+
/** REQUIRED — see {@link GadgetExportBase.example}. */
|
|
80
|
+
example: JsonValue;
|
|
81
|
+
/**
|
|
82
|
+
* The React hook implementation. Conforms to
|
|
83
|
+
* {@link GadgetHook} — same shape stdlib hooks satisfy.
|
|
84
|
+
* Authors `import` underlying 3rd-party libs at build time and
|
|
85
|
+
* compose inside this function.
|
|
86
|
+
*/
|
|
87
|
+
hookImpl: GadgetHook<TOutput, TOptions>;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Output of {@link createGguiGadget} — the React hook
|
|
91
|
+
* function with the serializable {@link GadgetDescriptor}
|
|
92
|
+
* descriptor attached as `.descriptor`. Authors export this as their
|
|
93
|
+
* primary surface; consumers call it as a hook and operators
|
|
94
|
+
* register the descriptor.
|
|
95
|
+
*/
|
|
96
|
+
type GguiGadget<TOutput, TOptions = void> = GadgetHook<TOutput, TOptions> & {
|
|
97
|
+
/** Serializable registry entry — register on App.gadgets. */
|
|
98
|
+
readonly descriptor: GadgetDescriptor;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Conformance violation thrown by the wrapper-author SDK
|
|
102
|
+
* ({@link createGguiGadget} / `defineGadgetPackage`) when the supplied
|
|
103
|
+
* spec fails the strict registry schema or the SDK-specific checks
|
|
104
|
+
* (`impl` shape). Carries the zod issues so authoring tools can
|
|
105
|
+
* highlight individual fields.
|
|
106
|
+
*/
|
|
107
|
+
declare class WrapperConformanceError extends Error {
|
|
108
|
+
readonly code: "wrapper_conformance";
|
|
109
|
+
readonly violations: ReadonlyArray<{
|
|
110
|
+
readonly path: ReadonlyArray<string | number>;
|
|
111
|
+
readonly message: string;
|
|
112
|
+
}>;
|
|
113
|
+
constructor(
|
|
114
|
+
/** Identifying label for the failing spec — a hook name
|
|
115
|
+
* (`createGguiGadget`) or a package name (`defineGadgetPackage`). */
|
|
116
|
+
label: string | undefined, violations: ReadonlyArray<{
|
|
117
|
+
readonly path: ReadonlyArray<string | number>;
|
|
118
|
+
readonly message: string;
|
|
119
|
+
}>);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build a ggui gadget. See file-level docstring for
|
|
123
|
+
* the usage pattern.
|
|
124
|
+
*
|
|
125
|
+
* Throws {@link WrapperConformanceError} synchronously when the spec
|
|
126
|
+
* is malformed — caller-time validation means a bad wrapper fails at
|
|
127
|
+
* module-load, not at first invocation.
|
|
128
|
+
*/
|
|
129
|
+
declare function createGguiGadget<TOutput, TOptions = void>(spec: GguiGadgetSpec<TOutput, TOptions>): GguiGadget<TOutput, TOptions>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* `defineGadgetPackage` — the wrapper-author SDK builder for a gadget
|
|
133
|
+
* PACKAGE that ships one or more exports, hooks AND/OR components,
|
|
134
|
+
* behind a single npm identity.
|
|
135
|
+
*
|
|
136
|
+
* Where {@link createGguiGadget} is the single-hook convenience (the
|
|
137
|
+
* common case — returns the callable hook with `.descriptor` grafted
|
|
138
|
+
* on), `defineGadgetPackage` is the general builder: it takes the
|
|
139
|
+
* package identity + transport metadata once, plus a list of export
|
|
140
|
+
* declarations, and returns the validated {@link GadgetDescriptor}.
|
|
141
|
+
*
|
|
142
|
+
* A gadget package mixing kinds — say a chart package exporting a
|
|
143
|
+
* `Chart` component + a `useChartTheme` hook — is exactly one
|
|
144
|
+
* descriptor with two `exports[]`. Authoring it:
|
|
145
|
+
*
|
|
146
|
+
* ```ts
|
|
147
|
+
* export const Chart: ComponentType<ChartProps> = (props) => { … };
|
|
148
|
+
* export const useChartTheme: GadgetHook<ChartTheme> = () => { … };
|
|
149
|
+
*
|
|
150
|
+
* export const chartDescriptor = defineGadgetPackage({
|
|
151
|
+
* package: '@my-org/gadget-chart',
|
|
152
|
+
* version: '0.0.1',
|
|
153
|
+
* styleUrl: 'https://…/chart.css',
|
|
154
|
+
* exports: [
|
|
155
|
+
* { component: 'Chart', impl: Chart,
|
|
156
|
+
* description: '…', usage: '…', example: { … } },
|
|
157
|
+
* { hook: 'useChartTheme', impl: useChartTheme,
|
|
158
|
+
* description: '…', usage: '…', example: { … } },
|
|
159
|
+
* ],
|
|
160
|
+
* });
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* The author exports each impl directly (typed where defined — no
|
|
164
|
+
* casts) and `defineGadgetPackage` produces the registry descriptor.
|
|
165
|
+
* `impl` is threaded purely so the SDK can conformance-check it is a
|
|
166
|
+
* function at module-load (the same fail-fast `createGguiGadget` does
|
|
167
|
+
* for `hookImpl`); the builder never inspects its signature.
|
|
168
|
+
*
|
|
169
|
+
* Throws {@link WrapperConformanceError} synchronously on a malformed
|
|
170
|
+
* spec — a bad package fails at module-load, not at first use.
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Any callable — a React hook or component. `defineGadgetPackage`
|
|
175
|
+
* conformance-checks `impl` is a function but never depends on its
|
|
176
|
+
* signature, so the broadest "some function" type is correct here
|
|
177
|
+
* (`never[]` params accept any concrete signature without variance
|
|
178
|
+
* friction; it is NOT `any` — the value stays opaque).
|
|
179
|
+
*/
|
|
180
|
+
type GadgetImpl = (...args: never[]) => unknown;
|
|
181
|
+
/** Per-export teaching text — required for the registry-strict schema. */
|
|
182
|
+
interface GadgetExportTeaching {
|
|
183
|
+
/** Human-readable description of what the export does. */
|
|
184
|
+
readonly description: string;
|
|
185
|
+
/** When / why / by-whom the export is used. */
|
|
186
|
+
readonly usage: string;
|
|
187
|
+
/** Concrete usage example for boilerplate + prompt priming. */
|
|
188
|
+
readonly example: JsonValue;
|
|
189
|
+
/** Anti-patterns + known gotchas surfaced in code-gen prompts. */
|
|
190
|
+
readonly gotchas?: string;
|
|
191
|
+
/** Optional Web-Permissions identifier the export gates on. */
|
|
192
|
+
readonly permission?: string;
|
|
193
|
+
/** Whether the UI MUST mount this export. Default `false`. */
|
|
194
|
+
readonly required?: boolean;
|
|
195
|
+
}
|
|
196
|
+
/** A hook export declaration — `use`-prefixed name + its impl. */
|
|
197
|
+
interface GadgetHookExportSpec extends GadgetExportTeaching {
|
|
198
|
+
/** Hook name — `use`-prefixed camelCase (`HOOK_NAME_RE`). */
|
|
199
|
+
readonly hook: string;
|
|
200
|
+
/** The React hook implementation. */
|
|
201
|
+
readonly impl: GadgetImpl;
|
|
202
|
+
}
|
|
203
|
+
/** A component export declaration — PascalCase name + its impl. */
|
|
204
|
+
interface GadgetComponentExportSpec extends GadgetExportTeaching {
|
|
205
|
+
/** Component name — PascalCase (`COMPONENT_NAME_RE`). */
|
|
206
|
+
readonly component: string;
|
|
207
|
+
/** The React component implementation. */
|
|
208
|
+
readonly impl: GadgetImpl;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* One export of a gadget package — a hook or a component,
|
|
212
|
+
* discriminated by which identifier field is present. Mirrors the
|
|
213
|
+
* protocol's {@link GadgetExport} field-presence union.
|
|
214
|
+
*/
|
|
215
|
+
type GadgetExportSpec = GadgetHookExportSpec | GadgetComponentExportSpec;
|
|
216
|
+
/** Author input to {@link defineGadgetPackage}. */
|
|
217
|
+
interface GadgetPackageSpec {
|
|
218
|
+
/** Bare npm package name. */
|
|
219
|
+
readonly package: string;
|
|
220
|
+
/** Exact semver pin. */
|
|
221
|
+
readonly version: string;
|
|
222
|
+
/** ggui-hosted ESM bundle URL. */
|
|
223
|
+
readonly bundleUrl?: string;
|
|
224
|
+
/** Registry hostname the bundle URL is derived from. */
|
|
225
|
+
readonly bundleHost?: string;
|
|
226
|
+
/** `sha384-<base64>` SRI of the bundle. */
|
|
227
|
+
readonly bundleSri?: string;
|
|
228
|
+
/** Stylesheet URL the package ships. */
|
|
229
|
+
readonly styleUrl?: string;
|
|
230
|
+
/** Outbound origins the package's exports call at runtime (CSP). */
|
|
231
|
+
readonly connect?: readonly string[];
|
|
232
|
+
/** `App.publicEnv` keys the package's exports require. */
|
|
233
|
+
readonly requires?: readonly string[];
|
|
234
|
+
/** Published `.d.ts` URL — required registry-side for non-stdlib. */
|
|
235
|
+
readonly typesUrl?: string;
|
|
236
|
+
/** `sha384-<base64>` SRI of the `.d.ts`. */
|
|
237
|
+
readonly typesSri?: string;
|
|
238
|
+
/** The exports the package ships — at least one, hooks and/or
|
|
239
|
+
* components. */
|
|
240
|
+
readonly exports: readonly GadgetExportSpec[];
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Build + validate a gadget package descriptor. See the file-level
|
|
244
|
+
* docstring for the authoring pattern.
|
|
245
|
+
*
|
|
246
|
+
* Throws {@link WrapperConformanceError} synchronously when the spec
|
|
247
|
+
* is malformed (non-function `impl`, missing teaching text, malformed
|
|
248
|
+
* package identity / export name).
|
|
249
|
+
*/
|
|
250
|
+
declare function defineGadgetPackage(spec: GadgetPackageSpec): GadgetDescriptor;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* `@ggui-ai/gadgets/catalog-adapter`.
|
|
254
|
+
*
|
|
255
|
+
* The contract surface between the ggui server and a per-deployment
|
|
256
|
+
* gadget catalog. The wire-side `DataContract.clientCapabilities.gadgets`
|
|
257
|
+
* is intentionally narrow — it is package-keyed and carries identity
|
|
258
|
+
* only (`(package, export name)`, no `version`, no transport
|
|
259
|
+
* metadata), so push-time resolution looks up the matching
|
|
260
|
+
* {@link GadgetDescriptor} descriptor by npm package name. This module
|
|
261
|
+
* declares the pluggable "where do descriptors come from?" port + ships
|
|
262
|
+
* two batteries-included implementations:
|
|
263
|
+
*
|
|
264
|
+
* - {@link InMemoryGadgetCatalog} — static map, configured at
|
|
265
|
+
* construction. Right for tests, the OSS default seed, and
|
|
266
|
+
* deployments that ship a fixed catalog at boot.
|
|
267
|
+
*
|
|
268
|
+
* - {@link CachingGadgetCatalog} — decorator over any other adapter
|
|
269
|
+
* with per-appId TTL caching + single-flight deduplication. Right
|
|
270
|
+
* for production cloud paths where descriptors live in DynamoDB /
|
|
271
|
+
* a registry service and re-fetching on every push would burn
|
|
272
|
+
* network round-trips. Caches are scoped per-appId so two apps
|
|
273
|
+
* never see each other's catalogs.
|
|
274
|
+
*
|
|
275
|
+
* ## Design contract
|
|
276
|
+
*
|
|
277
|
+
* - One method: `list(appId)`. Single batch read — never an N+1
|
|
278
|
+
* "fetch descriptor for one package at a time" pattern. The
|
|
279
|
+
* resolution caller indexes the returned array by `package`
|
|
280
|
+
* itself. Single network call per push (with cache, often zero).
|
|
281
|
+
*
|
|
282
|
+
* - Return type is `readonly GadgetDescriptor[]` — the same shape the
|
|
283
|
+
* wire push-time resolution + downstream consumers (boilerplate
|
|
284
|
+
* generator, CSP builder, Permissions-Policy deriver, system
|
|
285
|
+
* prompt builder) already speak.
|
|
286
|
+
*
|
|
287
|
+
* - Errors propagate. Adapters MUST throw on retrieval failure
|
|
288
|
+
* rather than returning an empty array — silent "no gadgets"
|
|
289
|
+
* would let pushes through with broken gadget refs and surface
|
|
290
|
+
* as render-time hook-resolution failures. The caller's job is
|
|
291
|
+
* to decide whether the push fails (gate fires) or proceeds
|
|
292
|
+
* ungated.
|
|
293
|
+
*
|
|
294
|
+
* ## Deployment-specific adapters
|
|
295
|
+
*
|
|
296
|
+
* Per-deployment adapters wear this same interface: a JSON-backed
|
|
297
|
+
* adapter reads from the `ggui.json#app.gadgets` array; a
|
|
298
|
+
* database-backed adapter reads from an app-metadata store. Both
|
|
299
|
+
* implement `GadgetCatalogAdapter`, so the enrichment pipeline doesn't
|
|
300
|
+
* care which environment is feeding it.
|
|
301
|
+
*/
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Per-deployment source of registered gadget descriptors.
|
|
305
|
+
*
|
|
306
|
+
* Named parties: caller (push-time resolution / dev tools) ↔ adapter
|
|
307
|
+
* (deployment-specific descriptor backing store, e.g., JSON, DynamoDB,
|
|
308
|
+
* in-memory).
|
|
309
|
+
*
|
|
310
|
+
* Obligations:
|
|
311
|
+
* - `list(appId)` MUST return the full set of descriptors registered
|
|
312
|
+
* for `appId` in a single call. No pagination at this layer;
|
|
313
|
+
* adapters that page internally MUST aggregate before returning.
|
|
314
|
+
* - On retrieval failure, the adapter MUST throw — silently
|
|
315
|
+
* returning `[]` is forbidden (it would mask broken catalogs).
|
|
316
|
+
*
|
|
317
|
+
* Failure mode: thrown error propagates to caller. Caller decides
|
|
318
|
+
* whether to fail the push (strict) or fall back to a default set
|
|
319
|
+
* (lenient).
|
|
320
|
+
*
|
|
321
|
+
* Observable violation: caller observes a thrown error or a
|
|
322
|
+
* descriptor-list whose contents are inconsistent with `appId`.
|
|
323
|
+
*/
|
|
324
|
+
interface GadgetCatalogAdapter {
|
|
325
|
+
/**
|
|
326
|
+
* Resolve the full registered gadget catalog for a given app.
|
|
327
|
+
*
|
|
328
|
+
* Single-batch by design. Callers MUST NOT call this in a loop
|
|
329
|
+
* per-package; index the returned array by `entry.package` instead.
|
|
330
|
+
*/
|
|
331
|
+
list(appId: string): Promise<readonly GadgetDescriptor[]>;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Static map-backed adapter. Pre-populated at construction; never
|
|
335
|
+
* fetches anything at runtime. Right for tests, examples, and
|
|
336
|
+
* deployments whose catalog is known at boot.
|
|
337
|
+
*/
|
|
338
|
+
declare class InMemoryGadgetCatalog implements GadgetCatalogAdapter {
|
|
339
|
+
#private;
|
|
340
|
+
constructor(byApp: ReadonlyMap<string, readonly GadgetDescriptor[]>);
|
|
341
|
+
/**
|
|
342
|
+
* Convenience factory for the common "every app gets the same
|
|
343
|
+
* catalog" case (the OSS stdlib seed pattern). Apps not explicitly
|
|
344
|
+
* keyed fall back to the supplied default.
|
|
345
|
+
*/
|
|
346
|
+
static withDefault(defaultEntries: readonly GadgetDescriptor[], perApp?: ReadonlyMap<string, readonly GadgetDescriptor[]>): InMemoryGadgetCatalog;
|
|
347
|
+
list(appId: string): Promise<readonly GadgetDescriptor[]>;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Decorator adapter — wraps any {@link GadgetCatalogAdapter} with
|
|
351
|
+
* per-appId TTL caching + single-flight deduplication. Right for
|
|
352
|
+
* production paths where the inner adapter hits DynamoDB / a registry
|
|
353
|
+
* service and per-push fetches would dominate latency.
|
|
354
|
+
*
|
|
355
|
+
* Concurrent `list(appId)` calls during a cache miss share ONE
|
|
356
|
+
* inflight Promise — no thundering herd against the inner adapter.
|
|
357
|
+
*
|
|
358
|
+
* Caches are scoped per-appId; entry TTL is configurable
|
|
359
|
+
* (default 30s — short enough that operator changes propagate
|
|
360
|
+
* promptly, long enough to amortize cold-start). Set `ttlMs: 0` for
|
|
361
|
+
* single-flight-only behavior (no TTL caching, just dedup).
|
|
362
|
+
*/
|
|
363
|
+
interface CachingGadgetCatalogOptions {
|
|
364
|
+
/**
|
|
365
|
+
* Per-entry time-to-live in milliseconds. Cache entries older than
|
|
366
|
+
* this are refetched on next `list()`. `0` disables TTL caching
|
|
367
|
+
* entirely (single-flight dedup only).
|
|
368
|
+
*
|
|
369
|
+
* Default: 30000 (30s).
|
|
370
|
+
*/
|
|
371
|
+
readonly ttlMs?: number;
|
|
372
|
+
/**
|
|
373
|
+
* Clock injection for tests. Default `Date.now`.
|
|
374
|
+
*/
|
|
375
|
+
readonly now?: () => number;
|
|
376
|
+
}
|
|
377
|
+
declare class CachingGadgetCatalog implements GadgetCatalogAdapter {
|
|
378
|
+
#private;
|
|
379
|
+
constructor(inner: GadgetCatalogAdapter, options?: CachingGadgetCatalogOptions);
|
|
380
|
+
list(appId: string): Promise<readonly GadgetDescriptor[]>;
|
|
381
|
+
/**
|
|
382
|
+
* Drop the cached entry for `appId`. Right for operator-triggered
|
|
383
|
+
* invalidation (gadget registered / unregistered / updated). When
|
|
384
|
+
* `appId` is omitted, drops every cached entry.
|
|
385
|
+
*/
|
|
386
|
+
invalidate(appId?: string): void;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* `getPublicEnv(key, opts?)`.
|
|
391
|
+
*
|
|
392
|
+
* Wrapper-author accessor for the public env channel. Reads values
|
|
393
|
+
* the operator stamped on `App.publicEnv` and the server projected
|
|
394
|
+
* (filtered to declared wrappers' `requires`) onto
|
|
395
|
+
* `globalThis.__ggui__.publicEnv`.
|
|
396
|
+
*
|
|
397
|
+
* Usage pattern (inside a wrapper's `hookImpl`):
|
|
398
|
+
*
|
|
399
|
+
* ```ts
|
|
400
|
+
* import { createGguiGadget, getPublicEnv } from '@ggui-ai/gadgets';
|
|
401
|
+
* import mapboxgl from 'mapbox-gl';
|
|
402
|
+
*
|
|
403
|
+
* export const useMapbox = createGguiGadget({
|
|
404
|
+
* hook: 'useMapbox',
|
|
405
|
+
* requires: ['GGUI_PUBLIC_APP_MAPBOX_TOKEN'],
|
|
406
|
+
* hookImpl: (opts) => {
|
|
407
|
+
* mapboxgl.accessToken = getPublicEnv('GGUI_PUBLIC_APP_MAPBOX_TOKEN');
|
|
408
|
+
* return useMapboxInternal(opts);
|
|
409
|
+
* },
|
|
410
|
+
* // …
|
|
411
|
+
* });
|
|
412
|
+
* ```
|
|
413
|
+
*
|
|
414
|
+
* Semantics
|
|
415
|
+
* ---------
|
|
416
|
+
*
|
|
417
|
+
* - **Throws** when called before the iframe runtime initializes
|
|
418
|
+
* (`globalThis.__ggui__` absent). This indicates the wrapper is
|
|
419
|
+
* running outside the ggui iframe (test misconfig, host SDK
|
|
420
|
+
* misuse).
|
|
421
|
+
* - **Throws** by default when the requested key is not present in
|
|
422
|
+
* the registry. The thrown error names the missing key + lists
|
|
423
|
+
* available keys — gives gadget authors actionable diagnostics
|
|
424
|
+
* without leaking the values themselves.
|
|
425
|
+
* - Pass `{ optional: true }` to get `undefined` for a missing key
|
|
426
|
+
* instead of throwing. Use when the wrapper has a sensible
|
|
427
|
+
* fallback (e.g., a default origin); the push gate enforces that
|
|
428
|
+
* declared `requires` keys are present, so the typical wrapper
|
|
429
|
+
* path uses the throwing default.
|
|
430
|
+
* - Empty-string values are returned verbatim (the operator may
|
|
431
|
+
* have intentionally configured a key with no value).
|
|
432
|
+
*
|
|
433
|
+
* The push gate (`assertPublicEnvSatisfied`) verifies the
|
|
434
|
+
* `App.publicEnv` satisfies every declared wrapper's `requires` BEFORE
|
|
435
|
+
* the iframe boots. So in well-configured deployments, the only
|
|
436
|
+
* `getPublicEnv` throws are gadget authoring bugs (typoed key, key
|
|
437
|
+
* not declared in `requires`). In production, the push gate catches
|
|
438
|
+
* the misconfiguration upstream.
|
|
439
|
+
*/
|
|
440
|
+
interface GetPublicEnvOptions {
|
|
441
|
+
/**
|
|
442
|
+
* When true, returns `undefined` for a missing key instead of
|
|
443
|
+
* throwing. Use sparingly — the push gate enforces declared
|
|
444
|
+
* `requires`, so a missing key usually indicates a wrapper bug
|
|
445
|
+
* (key not in `requires` array). The throwing default is the
|
|
446
|
+
* right call for keys that ARE declared in `requires`.
|
|
447
|
+
*/
|
|
448
|
+
readonly optional?: boolean;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Return the public env value at `key`. Throws on missing-required;
|
|
452
|
+
* returns `undefined` when `{ optional: true }`.
|
|
453
|
+
*
|
|
454
|
+
* `target` is the global root to read from; defaults to `globalThis`.
|
|
455
|
+
* Exposed for tests; production callers omit it.
|
|
456
|
+
*/
|
|
457
|
+
declare function getPublicEnv(key: string, opts?: GetPublicEnvOptions, target?: typeof globalThis): string | undefined;
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* `useGeolocation` — browser-capability hook for reading the user's
|
|
461
|
+
* current location via the Geolocation API. Satisfies
|
|
462
|
+
* `GadgetHook<GeolocationCoords, GeolocationOptions>`.
|
|
463
|
+
*
|
|
464
|
+
* Lifecycle:
|
|
465
|
+
* - `idle` — initial, no request fired.
|
|
466
|
+
* - `prompting` — permission prompt visible (browser-controlled).
|
|
467
|
+
* - `active` — permission granted; for watch mode, position updates
|
|
468
|
+
* stream as they arrive.
|
|
469
|
+
* - `completed` — terminal for one-shot mode (`watch: false`) after
|
|
470
|
+
* a successful read.
|
|
471
|
+
* - `denied` — user rejected the permission prompt or the request
|
|
472
|
+
* errored with `PERMISSION_DENIED`.
|
|
473
|
+
* - `error` — any other failure (`POSITION_UNAVAILABLE`, `TIMEOUT`,
|
|
474
|
+
* or `Geolocation API unavailable`).
|
|
475
|
+
*
|
|
476
|
+
* Contract authors declare this hook via
|
|
477
|
+
* `clientCapabilities.gadgets['@ggui-ai/gadgets'] = { useGeolocation: {} }`
|
|
478
|
+
* and the UI generator emits the import + call site. Values surface to
|
|
479
|
+
* the agent via `contextSpec` (the component code threads `value` into
|
|
480
|
+
* the relevant slot's setter).
|
|
481
|
+
*/
|
|
482
|
+
|
|
483
|
+
/** Coordinates returned by the hook. Pure JSON for easy contextSpec
|
|
484
|
+
* threading. */
|
|
485
|
+
interface GeolocationCoords {
|
|
486
|
+
readonly latitude: number;
|
|
487
|
+
readonly longitude: number;
|
|
488
|
+
readonly accuracy: number;
|
|
489
|
+
readonly altitude?: number;
|
|
490
|
+
readonly altitudeAccuracy?: number;
|
|
491
|
+
readonly heading?: number;
|
|
492
|
+
readonly speed?: number;
|
|
493
|
+
readonly timestamp: number;
|
|
494
|
+
}
|
|
495
|
+
/** Options accepted by `useGeolocation`. */
|
|
496
|
+
interface GeolocationOptions {
|
|
497
|
+
/** Continuously stream updates instead of single read. Default: false. */
|
|
498
|
+
readonly watch?: boolean;
|
|
499
|
+
/** Request high-accuracy positioning. Default: false. */
|
|
500
|
+
readonly enableHighAccuracy?: boolean;
|
|
501
|
+
/** Max age (ms) of a cached position the browser may return.
|
|
502
|
+
* Default: 0 (always fresh). */
|
|
503
|
+
readonly maximumAge?: number;
|
|
504
|
+
/** Request timeout in ms. Default: Infinity. */
|
|
505
|
+
readonly timeout?: number;
|
|
506
|
+
}
|
|
507
|
+
declare const useGeolocation: GadgetHook<GeolocationCoords, GeolocationOptions>;
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* `useClipboardWrite` — browser-capability hook for writing text to
|
|
511
|
+
* the system clipboard via `navigator.clipboard.writeText`. Satisfies
|
|
512
|
+
* `GadgetHook<string, ClipboardWriteOptions>`.
|
|
513
|
+
*
|
|
514
|
+
* One-shot semantics: call `start({text})` to write; status moves
|
|
515
|
+
* `idle → prompting → completed` on success or `idle → prompting →
|
|
516
|
+
* denied/error` on failure. The hook's `value` carries the most
|
|
517
|
+
* recently written text so component code can confirm what landed
|
|
518
|
+
* on the clipboard.
|
|
519
|
+
*
|
|
520
|
+
* `useClipboardPaste` is a separate hook — the read direction has
|
|
521
|
+
* different permission semantics (requires explicit user-gesture
|
|
522
|
+
* activation in most browsers).
|
|
523
|
+
*/
|
|
524
|
+
|
|
525
|
+
interface ClipboardWriteOptions {
|
|
526
|
+
/** Text to write. Required at call site, not at hook construction. */
|
|
527
|
+
readonly text: string;
|
|
528
|
+
}
|
|
529
|
+
declare const useClipboardWrite: GadgetHook<string, ClipboardWriteOptions>;
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* `useClipboardPaste` — browser-capability hook for reading text from
|
|
533
|
+
* the system clipboard via `navigator.clipboard.readText`. Satisfies
|
|
534
|
+
* `GadgetHook<string, void>`.
|
|
535
|
+
*
|
|
536
|
+
* Most browsers require an explicit user gesture (button click) to
|
|
537
|
+
* invoke `start()` — wire this hook to a "paste" button rather than
|
|
538
|
+
* firing on mount.
|
|
539
|
+
*
|
|
540
|
+
* Lifecycle: idle → prompting → completed (with the text in `value`)
|
|
541
|
+
* on success; denied/error on failure.
|
|
542
|
+
*/
|
|
543
|
+
|
|
544
|
+
declare const useClipboardPaste: GadgetHook<string>;
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* `useNotifications` — browser-capability hook for showing system
|
|
548
|
+
* notifications via the Notification API. Satisfies
|
|
549
|
+
* `GadgetHook<NotificationResult, NotificationOptions>`.
|
|
550
|
+
*
|
|
551
|
+
* Permission semantics: the first `start()` call requests permission
|
|
552
|
+
* via `Notification.requestPermission()`; subsequent calls reuse the
|
|
553
|
+
* granted permission. Permission denial is sticky on the browser
|
|
554
|
+
* side — once denied, future `start()` calls error with
|
|
555
|
+
* `permission_denied` without re-prompting.
|
|
556
|
+
*
|
|
557
|
+
* Lifecycle: idle → prompting → completed (after notification
|
|
558
|
+
* dismissed/clicked) or denied/error.
|
|
559
|
+
*/
|
|
560
|
+
|
|
561
|
+
interface NotificationOptions_ {
|
|
562
|
+
readonly title: string;
|
|
563
|
+
readonly body?: string;
|
|
564
|
+
readonly icon?: string;
|
|
565
|
+
readonly tag?: string;
|
|
566
|
+
}
|
|
567
|
+
interface NotificationResult {
|
|
568
|
+
readonly outcome: 'clicked' | 'closed';
|
|
569
|
+
readonly tag?: string;
|
|
570
|
+
}
|
|
571
|
+
declare const useNotifications: GadgetHook<NotificationResult, NotificationOptions_>;
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* `useFilePicker` — browser-capability hook for prompting the user
|
|
575
|
+
* to select one or more files. Uses `<input type="file">` as the
|
|
576
|
+
* universal fallback; the File System Access API
|
|
577
|
+
* (`showOpenFilePicker`) is preferred when available.
|
|
578
|
+
*
|
|
579
|
+
* Returns one entry per selected file with `name`, `size`, `type`,
|
|
580
|
+
* and the raw `File` handle on `_file` for component code that
|
|
581
|
+
* wants to read content (the contract doesn't carry the File over
|
|
582
|
+
* the wire — component reads + extracts what it needs for the
|
|
583
|
+
* agent's contextSpec / actionSpec payload).
|
|
584
|
+
*
|
|
585
|
+
* Lifecycle: idle → prompting → completed (with picked files) or
|
|
586
|
+
* denied/error.
|
|
587
|
+
*/
|
|
588
|
+
|
|
589
|
+
interface FilePickerOptions {
|
|
590
|
+
/** Allow multi-select. Default: false. */
|
|
591
|
+
readonly multiple?: boolean;
|
|
592
|
+
/** MIME-type filter (e.g., 'image/*', '.pdf'). Optional. */
|
|
593
|
+
readonly accept?: string;
|
|
594
|
+
}
|
|
595
|
+
interface PickedFile {
|
|
596
|
+
readonly name: string;
|
|
597
|
+
readonly size: number;
|
|
598
|
+
readonly type: string;
|
|
599
|
+
/** Raw File handle. NOT serialized — component reads + extracts. */
|
|
600
|
+
readonly _file: File;
|
|
601
|
+
}
|
|
602
|
+
interface FilePickerResult {
|
|
603
|
+
readonly files: readonly PickedFile[];
|
|
604
|
+
}
|
|
605
|
+
declare const useFilePicker: GadgetHook<FilePickerResult, FilePickerOptions>;
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* `useMicrophone` — browser-capability hook for capturing audio via
|
|
609
|
+
* `MediaDevices.getUserMedia({audio: true})` + MediaRecorder.
|
|
610
|
+
*
|
|
611
|
+
* Lifecycle: idle → prompting → active (recording) → completed
|
|
612
|
+
* (with the captured blob). `stop()` ends the recording; without it,
|
|
613
|
+
* the recording continues until the user revokes mic access or the
|
|
614
|
+
* tab loses focus.
|
|
615
|
+
*
|
|
616
|
+
* Returns the captured audio as a Blob + duration metadata so
|
|
617
|
+
* component code can thread the URL or upload-handle into a
|
|
618
|
+
* contextSpec slot or actionSpec payload.
|
|
619
|
+
*/
|
|
620
|
+
|
|
621
|
+
interface MicrophoneOptions {
|
|
622
|
+
/** MIME type for the recorder. Defaults to whatever the browser supports. */
|
|
623
|
+
readonly mimeType?: string;
|
|
624
|
+
}
|
|
625
|
+
interface MicrophoneResult {
|
|
626
|
+
readonly blob: Blob;
|
|
627
|
+
readonly durationMs: number;
|
|
628
|
+
readonly mimeType: string;
|
|
629
|
+
}
|
|
630
|
+
declare const useMicrophone: GadgetHook<MicrophoneResult, MicrophoneOptions>;
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* `useCamera` — browser-capability hook for capturing a still photo
|
|
634
|
+
* via `MediaDevices.getUserMedia({video: true})` + canvas drawing.
|
|
635
|
+
*
|
|
636
|
+
* Lifecycle: idle → prompting → active (camera live) → completed
|
|
637
|
+
* (with the captured photo as a data URL). The hook returns a single
|
|
638
|
+
* snapshot per `start()` — call `stop()` to release the camera
|
|
639
|
+
* without taking a photo.
|
|
640
|
+
*
|
|
641
|
+
* Component code threads the data URL into a contextSpec slot or
|
|
642
|
+
* actionSpec payload. For continuous video / multi-frame capture, a
|
|
643
|
+
* different hook would be needed (out of v1 scope).
|
|
644
|
+
*/
|
|
645
|
+
|
|
646
|
+
interface CameraOptions {
|
|
647
|
+
/** Prefer front ('user') or rear ('environment') camera. Optional. */
|
|
648
|
+
readonly facingMode?: 'user' | 'environment';
|
|
649
|
+
/** MIME type for the encoded snapshot. Default: 'image/png'. */
|
|
650
|
+
readonly mimeType?: string;
|
|
651
|
+
/** JPEG quality 0–1. Only used when mimeType is image/jpeg. */
|
|
652
|
+
readonly quality?: number;
|
|
653
|
+
}
|
|
654
|
+
interface CameraResult {
|
|
655
|
+
/** Encoded snapshot as a data URL. */
|
|
656
|
+
readonly dataUrl: string;
|
|
657
|
+
readonly width: number;
|
|
658
|
+
readonly height: number;
|
|
659
|
+
readonly mimeType: string;
|
|
660
|
+
}
|
|
661
|
+
declare const useCamera: GadgetHook<CameraResult, CameraOptions>;
|
|
662
|
+
|
|
663
|
+
export { CachingGadgetCatalog, type CachingGadgetCatalogOptions, type CameraOptions, type CameraResult, type ClipboardWriteOptions, type FilePickerOptions, type FilePickerResult, type GadgetCatalogAdapter, type GadgetComponentExportSpec, type GadgetExportSpec, type GadgetHookExportSpec, type GadgetImpl, type GadgetPackageSpec, type GeolocationCoords, type GeolocationOptions, type GetPublicEnvOptions, type GguiGadget, type GguiGadgetSpec, InMemoryGadgetCatalog, type MicrophoneOptions, type MicrophoneResult, type NotificationOptions_ as NotificationOptions, type NotificationResult, type PickedFile, WrapperConformanceError, createGguiGadget, defineGadgetPackage, getPublicEnv, useCamera, useClipboardPaste, useClipboardWrite, useFilePicker, useGeolocation, useMicrophone, useNotifications };
|