@glassly/miniapp 0.3.5 → 0.3.6-dev.848
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 +16 -2
- package/dist/display/index.d.ts +2 -2
- package/dist/display/index.d.ts.map +1 -1
- package/dist/display/index.js +1 -1
- package/dist/display/index.js.map +1 -1
- package/dist/display/scene/types.d.ts +13 -0
- package/dist/display/scene/types.d.ts.map +1 -1
- package/dist/display/scene/types.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/manifest.d.ts +2 -2
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +2 -2
- package/dist/manifest.js.map +1 -1
- package/dist/mirror/canvas.d.ts.map +1 -1
- package/dist/mirror/canvas.js +17 -1
- package/dist/mirror/canvas.js.map +1 -1
- package/dist/mirror/geometry.d.ts +11 -0
- package/dist/mirror/geometry.d.ts.map +1 -1
- package/dist/mirror/geometry.js +27 -0
- package/dist/mirror/geometry.js.map +1 -1
- package/dist/modules/ai.d.ts +1 -1
- package/dist/modules/ai.d.ts.map +1 -1
- package/dist/modules/events.d.ts +17 -1
- package/dist/modules/events.d.ts.map +1 -1
- package/dist/modules/events.js.map +1 -1
- package/dist/modules/keys.d.ts +1 -1
- package/dist/modules/keys.d.ts.map +1 -1
- package/dist/modules/memory.d.ts +39 -0
- package/dist/modules/memory.d.ts.map +1 -1
- package/dist/modules/memory.js +19 -0
- package/dist/modules/memory.js.map +1 -1
- package/dist/modules/miniapps.d.ts +1 -0
- package/dist/modules/miniapps.d.ts.map +1 -1
- package/dist/modules/miniapps.js.map +1 -1
- package/dist/modules/widgets.d.ts +74 -12
- package/dist/modules/widgets.d.ts.map +1 -1
- package/dist/modules/widgets.js +45 -9
- package/dist/modules/widgets.js.map +1 -1
- package/dist/protocol.d.ts +8 -4
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +7 -3
- package/dist/protocol.js.map +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +6 -1
- package/dist/session.js.map +1 -1
- package/package.json +2 -2
- package/src/display/index.ts +2 -1
- package/src/display/scene/types.ts +14 -0
- package/src/index.ts +5 -0
- package/src/manifest.ts +2 -2
- package/src/mirror/canvas.ts +17 -1
- package/src/mirror/geometry.ts +35 -1
- package/src/modules/ai.ts +1 -1
- package/src/modules/events.ts +18 -0
- package/src/modules/keys.ts +1 -1
- package/src/modules/memory.ts +56 -0
- package/src/modules/miniapps.ts +1 -0
- package/src/modules/widgets.ts +93 -16
- package/src/protocol.ts +7 -3
- package/src/session.ts +7 -2
package/src/modules/widgets.ts
CHANGED
|
@@ -6,9 +6,14 @@
|
|
|
6
6
|
* The host hands it a box; the provider pushes a frame for that box with
|
|
7
7
|
* `update()` whenever its state changes and takes the wearer's input
|
|
8
8
|
* through `onEvent` while the widget is active: a tap on the selected
|
|
9
|
-
* card activates it, a double tap hands input back. A
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* card activates it, a double tap hands input back. A widget that lists
|
|
10
|
+
* the `EX` size is expanded by that tap instead while the wearer leaves
|
|
11
|
+
* expansion on (the miniapp's settings page, or `setExpandable`): the
|
|
12
|
+
* host gives it the full screen, the provider draws it with
|
|
13
|
+
* `update(elements, {view: "expanded"})`, and a double tap collapses it
|
|
14
|
+
* back to the card. A provider runs in widget mode while a host has its
|
|
15
|
+
* widget placed: no card in the app switcher, no frame of its own on the
|
|
16
|
+
* glasses, no touch input of its own.
|
|
12
17
|
* - Host (HOST_WIDGETS): `list()` the declared widgets, `place()` one in a
|
|
13
18
|
* box, hear its frames through `onFrame()`, forward input with `send()`
|
|
14
19
|
* and `unplace()` it. A provider with nothing placed stops.
|
|
@@ -21,7 +26,10 @@ import type {RenderElement} from "./display"
|
|
|
21
26
|
import {MiniappErrorCode, MiniappRequestType} from "../protocol"
|
|
22
27
|
import {MiniappSession} from "../session"
|
|
23
28
|
|
|
24
|
-
export type WidgetSize = "XS" | "SM" | "MD" | "LG"
|
|
29
|
+
export type WidgetSize = "XS" | "XSM" | "SM" | "MD" | "LG"
|
|
30
|
+
|
|
31
|
+
/** Which surface a frame draws: the card in its box, or the full-screen expanded view. */
|
|
32
|
+
export type WidgetView = "card" | "expanded"
|
|
25
33
|
|
|
26
34
|
/** The box a widget draws into: its size name and its pixel extent. Frames use box-local coordinates. */
|
|
27
35
|
export interface WidgetBox {
|
|
@@ -30,16 +38,35 @@ export interface WidgetBox {
|
|
|
30
38
|
height: number
|
|
31
39
|
}
|
|
32
40
|
|
|
41
|
+
/** The full-screen box an expanded widget draws into, in its own local coordinates. */
|
|
42
|
+
export interface WidgetExpandedBox {
|
|
43
|
+
width: number
|
|
44
|
+
height: number
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
/** The wearer's input, forwarded by the host while the widget is active. */
|
|
34
48
|
export type WidgetEvent =
|
|
35
49
|
/** The wearer tapped the selected widget: it owns every swipe and tap until it is deactivated. */
|
|
36
50
|
| {type: "activate"}
|
|
37
51
|
/** The wearer double-tapped out, or the dashboard closed: show no selection. */
|
|
38
52
|
| {type: "deactivate"}
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
/**
|
|
54
|
+
* The wearer tapped the selected widget and the host gave it the full
|
|
55
|
+
* screen: draw the expanded view for this box with `update(elements,
|
|
56
|
+
* {view: "expanded"})`. Like activate, it owns every swipe and tap until
|
|
57
|
+
* collapsed. Only sent to widgets that list `EX` with expansion on.
|
|
58
|
+
*/
|
|
59
|
+
| {type: "expand"; width: number; height: number}
|
|
60
|
+
/** The wearer double-tapped back to the card, or the dashboard closed: back to the card, show no selection. */
|
|
61
|
+
| {type: "collapse"}
|
|
62
|
+
/** A swipe while active or expanded. `input2d` is set when it came from a 2D controller such as a Neural Band. */
|
|
63
|
+
| {type: "swipe"; direction: "left" | "right" | "up" | "down"; input2d?: boolean}
|
|
64
|
+
/** A tap while active or expanded. */
|
|
42
65
|
| {type: "tap"}
|
|
66
|
+
/** The wearer pressed and held while active or expanded. */
|
|
67
|
+
| {type: "hold"}
|
|
68
|
+
/** The held press ended. Some controllers report a hold without a release. */
|
|
69
|
+
| {type: "release"}
|
|
43
70
|
/** The host is about to show the widget: refresh what it draws, then return. */
|
|
44
71
|
| {type: "beforeShow"}
|
|
45
72
|
|
|
@@ -57,10 +84,23 @@ export interface WidgetHandle {
|
|
|
57
84
|
readonly id: string
|
|
58
85
|
/** The box the host assigned, or null while unplaced. */
|
|
59
86
|
readonly box: WidgetBox | null
|
|
60
|
-
/**
|
|
61
|
-
|
|
87
|
+
/** The full-screen box while the host has the widget expanded, else null. */
|
|
88
|
+
readonly expanded: WidgetExpandedBox | null
|
|
89
|
+
/**
|
|
90
|
+
* Push the frame for the current box, or with `{view: "expanded"}` for the
|
|
91
|
+
* expanded box. Coalesced by the host; drawn while the dashboard shows.
|
|
92
|
+
*/
|
|
93
|
+
update(elements: RenderElement[], opts?: {view?: WidgetView}): void
|
|
62
94
|
/** Stop serving the widget. Calls still arrive until the host unplaces it. */
|
|
63
95
|
release(): void
|
|
96
|
+
/** Whether a tap expands the widget; false when it does not list `EX`. */
|
|
97
|
+
getExpandable(): Promise<boolean>
|
|
98
|
+
/**
|
|
99
|
+
* Turn tap-to-expand on or off, the same choice the wearer makes on the
|
|
100
|
+
* miniapp's settings page; resolves with the setting now in force. Rejects
|
|
101
|
+
* for a widget that does not list `EX`.
|
|
102
|
+
*/
|
|
103
|
+
setExpandable(expandable: boolean): Promise<boolean>
|
|
64
104
|
}
|
|
65
105
|
|
|
66
106
|
/** One declared widget, as a host lists it. */
|
|
@@ -71,6 +111,8 @@ export interface WidgetInfo {
|
|
|
71
111
|
name: string
|
|
72
112
|
sizes: WidgetSize[]
|
|
73
113
|
defaultSize: WidgetSize
|
|
114
|
+
/** A tap on the selected widget expands it to the full screen instead of activating the card. */
|
|
115
|
+
expandable: boolean
|
|
74
116
|
/** The provider's background context is up (in widget mode or opened by the wearer). */
|
|
75
117
|
running: boolean
|
|
76
118
|
/** The provider can run on the connected glasses. */
|
|
@@ -81,6 +123,7 @@ export interface WidgetFrame {
|
|
|
81
123
|
packageName: string
|
|
82
124
|
widgetId: string
|
|
83
125
|
elements: RenderElement[]
|
|
126
|
+
view: WidgetView
|
|
84
127
|
}
|
|
85
128
|
|
|
86
129
|
export interface SendOptions {
|
|
@@ -106,6 +149,7 @@ const widgetKey = (packageName: string, widgetId: string): string => `${packageN
|
|
|
106
149
|
|
|
107
150
|
class Handle implements WidgetHandle {
|
|
108
151
|
box: WidgetBox | null = null
|
|
152
|
+
expanded: WidgetExpandedBox | null = null
|
|
109
153
|
|
|
110
154
|
constructor(
|
|
111
155
|
readonly id: string,
|
|
@@ -113,13 +157,21 @@ class Handle implements WidgetHandle {
|
|
|
113
157
|
private readonly module: WidgetsModule,
|
|
114
158
|
) {}
|
|
115
159
|
|
|
116
|
-
update(elements: RenderElement[]): void {
|
|
117
|
-
this.module._update(this.id, elements)
|
|
160
|
+
update(elements: RenderElement[], opts?: {view?: WidgetView}): void {
|
|
161
|
+
this.module._update(this.id, elements, opts?.view ?? "card")
|
|
118
162
|
}
|
|
119
163
|
|
|
120
164
|
release(): void {
|
|
121
165
|
this.module._release(this.id, this)
|
|
122
166
|
}
|
|
167
|
+
|
|
168
|
+
getExpandable(): Promise<boolean> {
|
|
169
|
+
return this.module._expandable(this.id)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
setExpandable(expandable: boolean): Promise<boolean> {
|
|
173
|
+
return this.module._expandable(this.id, expandable)
|
|
174
|
+
}
|
|
123
175
|
}
|
|
124
176
|
|
|
125
177
|
export class WidgetsModule {
|
|
@@ -154,8 +206,23 @@ export class WidgetsModule {
|
|
|
154
206
|
}
|
|
155
207
|
|
|
156
208
|
/** @internal */
|
|
157
|
-
_update(widgetId: string, elements: RenderElement[]): void {
|
|
158
|
-
this.session.sendOneShot({
|
|
209
|
+
_update(widgetId: string, elements: RenderElement[], view: WidgetView): void {
|
|
210
|
+
this.session.sendOneShot({
|
|
211
|
+
type: MiniappRequestType.WIDGET_UPDATE,
|
|
212
|
+
widgetId,
|
|
213
|
+
elements,
|
|
214
|
+
...(view === "expanded" ? {view} : {}),
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** @internal */
|
|
219
|
+
async _expandable(widgetId: string, expandable?: boolean): Promise<boolean> {
|
|
220
|
+
const result = await this.session.sendRequest<{expandable?: boolean}>({
|
|
221
|
+
type: MiniappRequestType.WIDGET_EXPANDABLE,
|
|
222
|
+
widgetId,
|
|
223
|
+
...(expandable === undefined ? {} : {expandable}),
|
|
224
|
+
})
|
|
225
|
+
return result?.expandable === true
|
|
159
226
|
}
|
|
160
227
|
|
|
161
228
|
/** @internal */
|
|
@@ -200,10 +267,13 @@ export class WidgetsModule {
|
|
|
200
267
|
try {
|
|
201
268
|
if (kind === "box") {
|
|
202
269
|
handle.box = box
|
|
270
|
+
if (!box) handle.expanded = null
|
|
203
271
|
handle.hooks.onBox?.(box)
|
|
204
272
|
this.reply(callId, true, null)
|
|
205
273
|
return
|
|
206
274
|
}
|
|
275
|
+
if (event?.type === "expand") handle.expanded = {width: event.width, height: event.height}
|
|
276
|
+
else if (event?.type === "collapse") handle.expanded = null
|
|
207
277
|
const result = event && handle.hooks.onEvent ? await handle.hooks.onEvent(event) : undefined
|
|
208
278
|
this.reply(callId, true, result ?? null)
|
|
209
279
|
} catch (err) {
|
|
@@ -237,16 +307,23 @@ export class WidgetsModule {
|
|
|
237
307
|
/**
|
|
238
308
|
* Place a widget in a box. Starts the provider in widget mode when it is
|
|
239
309
|
* not running, hands it the box, and resolves with the provider's last
|
|
240
|
-
* frame for the widget, or null when it has not drawn yet.
|
|
241
|
-
*
|
|
310
|
+
* card frame for the widget, or null when it has not drawn yet. A cached
|
|
311
|
+
* expanded frame is delivered to the `onFrame` listeners (with `view:
|
|
312
|
+
* "expanded"`) before it resolves. Placing again with a new box resizes.
|
|
242
313
|
*/
|
|
243
314
|
async place(packageName: string, widgetId: string, box: WidgetBox): Promise<RenderElement[] | null> {
|
|
244
|
-
const result = await this.session.sendRequest<{
|
|
315
|
+
const result = await this.session.sendRequest<{
|
|
316
|
+
frame: RenderElement[] | null
|
|
317
|
+
expandedFrame?: RenderElement[] | null
|
|
318
|
+
}>({
|
|
245
319
|
type: MiniappRequestType.WIDGET_PLACE,
|
|
246
320
|
packageName,
|
|
247
321
|
widgetId,
|
|
248
322
|
box,
|
|
249
323
|
})
|
|
324
|
+
if (Array.isArray(result?.expandedFrame)) {
|
|
325
|
+
this._deliverFrame({packageName, widgetId, elements: result.expandedFrame, view: "expanded"})
|
|
326
|
+
}
|
|
250
327
|
return result?.frame ?? null
|
|
251
328
|
}
|
|
252
329
|
|
package/src/protocol.ts
CHANGED
|
@@ -183,6 +183,8 @@ export enum MiniappRequestType {
|
|
|
183
183
|
MEMORY_QUERY = "miniapp_memory_query",
|
|
184
184
|
MEMORY_WINDOW = "miniapp_memory_window",
|
|
185
185
|
MEMORY_EXPORT_TEXT = "miniapp_memory_export_text",
|
|
186
|
+
MEMORY_EXPORT_FILE = "miniapp_memory_export_file",
|
|
187
|
+
MEMORY_IMPORT_FILE = "miniapp_memory_import_file",
|
|
186
188
|
MEMORY_SUMMARY_ADD = "miniapp_memory_summary_add",
|
|
187
189
|
MEMORY_SUMMARY_LIST = "miniapp_memory_summary_list",
|
|
188
190
|
MEMORY_PENDING_SUMMARY_HOUR = "miniapp_memory_pending_summary_hour",
|
|
@@ -321,18 +323,20 @@ export enum MiniappRequestType {
|
|
|
321
323
|
// A provider declares widgets in its manifest and serves them through
|
|
322
324
|
// session.widgets.provide; a host (HOST_WIDGETS) places them and forwards
|
|
323
325
|
// the wearer's input. The host routes every call; neither side names the other.
|
|
324
|
-
/** Provider → host, one-shot: the latest frame for one of its widgets. */
|
|
326
|
+
/** Provider → host, one-shot: the latest frame for one of its widgets; `view: "expanded"` for the expanded view. */
|
|
325
327
|
WIDGET_UPDATE = "miniapp_widget_update",
|
|
326
328
|
/** Provider → host: the result of a delivered WIDGET_CALL, correlated by callId. */
|
|
327
329
|
WIDGET_RESULT = "miniapp_widget_result",
|
|
328
330
|
/** Every widget the installed miniapps declare. HOST_WIDGETS. */
|
|
329
331
|
WIDGETS_LIST = "miniapp_widgets_list",
|
|
330
|
-
/** Place a widget in a box: starts the provider in widget mode and hands it the box. HOST_WIDGETS. */
|
|
332
|
+
/** Place a widget in a box: starts the provider in widget mode and hands it the box. Answers {frame, expandedFrame}. HOST_WIDGETS. */
|
|
331
333
|
WIDGET_PLACE = "miniapp_widget_place",
|
|
332
334
|
/** Take a widget off: the provider stops once nothing of it is placed. HOST_WIDGETS. */
|
|
333
335
|
WIDGET_UNPLACE = "miniapp_widget_unplace",
|
|
334
336
|
/** Forward an input event to a placed widget and wait for its answer. HOST_WIDGETS. */
|
|
335
337
|
WIDGET_SEND = "miniapp_widget_send",
|
|
338
|
+
/** Provider: read, or set with `expandable`, whether a tap expands one of its `EX` widgets. Answers {expandable}. */
|
|
339
|
+
WIDGET_EXPANDABLE = "miniapp_widget_expandable",
|
|
336
340
|
}
|
|
337
341
|
|
|
338
342
|
// ============================================================================
|
|
@@ -410,7 +414,7 @@ export enum MiniappResponseType {
|
|
|
410
414
|
* expects a WIDGET_RESULT keyed by callId.
|
|
411
415
|
*/
|
|
412
416
|
WIDGET_CALL = "miniapp_widget_call",
|
|
413
|
-
/** Host → widget host: a provider pushed a new frame for a widget this app placed. */
|
|
417
|
+
/** Host → widget host: a provider pushed a new frame for a widget this app placed; `view: "expanded"` for the expanded view. */
|
|
414
418
|
WIDGET_FRAME = "miniapp_widget_frame",
|
|
415
419
|
|
|
416
420
|
/**
|
package/src/session.ts
CHANGED
|
@@ -338,7 +338,7 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
338
338
|
/**
|
|
339
339
|
* User-supplied provider API keys (Settings > API Keys). Requires the
|
|
340
340
|
* API_KEYS manifest permission; only an allowlisted provider set is
|
|
341
|
-
* readable (anthropic / gemini / elevenlabs / mapbox — never soniox).
|
|
341
|
+
* readable (anthropic / gemini / openai / deepseek / elevenlabs / mapbox — never soniox).
|
|
342
342
|
*/
|
|
343
343
|
/**
|
|
344
344
|
* Platform LLM completions. Requires the AI manifest permission. The
|
|
@@ -957,7 +957,12 @@ export class MiniappSession<TChannels extends object = any> {
|
|
|
957
957
|
const packageName = payload.packageName as string | undefined
|
|
958
958
|
const widgetId = payload.widgetId as string | undefined
|
|
959
959
|
if (!packageName || !widgetId || !Array.isArray(payload.elements)) return
|
|
960
|
-
this.widgets._deliverFrame({
|
|
960
|
+
this.widgets._deliverFrame({
|
|
961
|
+
packageName,
|
|
962
|
+
widgetId,
|
|
963
|
+
elements: payload.elements,
|
|
964
|
+
view: payload.view === "expanded" ? "expanded" : "card",
|
|
965
|
+
} as WidgetFrame)
|
|
961
966
|
return
|
|
962
967
|
}
|
|
963
968
|
|