@glassly/engine 0.3.3-dev.625 → 0.3.3-dev.628
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/build/generated/releaseMetadata.js +3 -3
- package/build/generated/releaseMetadata.js.map +1 -1
- package/build/services/LocalMiniappRuntime.d.ts +1 -0
- package/build/services/LocalMiniappRuntime.d.ts.map +1 -1
- package/build/services/LocalMiniappRuntime.js +10 -6
- package/build/services/LocalMiniappRuntime.js.map +1 -1
- package/build/services/MiniappIcons.d.ts +16 -0
- package/build/services/MiniappIcons.d.ts.map +1 -0
- package/build/services/MiniappIcons.js +54 -0
- package/build/services/MiniappIcons.js.map +1 -0
- package/package.json +8 -7
- package/src/generated/releaseMetadata.ts +3 -3
- package/src/services/LocalMiniappRuntime.ts +22 -11
- package/src/services/MiniappIcons.ts +50 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type IconApp = {
|
|
2
|
+
packageName: string;
|
|
3
|
+
version?: string;
|
|
4
|
+
logoUrl: string;
|
|
5
|
+
};
|
|
6
|
+
/** Small thumbnails keep the inter-miniapp bridge and every grid frame lightweight. */
|
|
7
|
+
declare function thumbnail(uri: string): Promise<string | undefined>;
|
|
8
|
+
/** Cache by installed version and icon URL; failed icons never prevent listing apps. */
|
|
9
|
+
export declare class MiniappIcons {
|
|
10
|
+
private readonly load;
|
|
11
|
+
private cache;
|
|
12
|
+
constructor(load?: typeof thumbnail);
|
|
13
|
+
read(app: IconApp): Promise<string | undefined>;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=MiniappIcons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MiniappIcons.d.ts","sourceRoot":"","sources":["../../src/services/MiniappIcons.ts"],"names":[],"mappings":"AAGA,KAAK,OAAO,GAAG;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAA;AAEvE,uFAAuF;AACvF,iBAAe,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqBjE;AAED,wFAAwF;AACxF,qBAAa,YAAY;IAGX,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,KAAK,CAAuE;gBAEvD,IAAI,mBAAY;IAE7C,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAchD"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { File } from "expo-file-system";
|
|
2
|
+
import { ImageManipulator, SaveFormat } from "expo-image-manipulator";
|
|
3
|
+
/** Small thumbnails keep the inter-miniapp bridge and every grid frame lightweight. */
|
|
4
|
+
async function thumbnail(uri) {
|
|
5
|
+
const context = ImageManipulator.manipulate(uri);
|
|
6
|
+
let image;
|
|
7
|
+
let savedUri;
|
|
8
|
+
try {
|
|
9
|
+
context.resize({ width: 32, height: 32 });
|
|
10
|
+
image = await context.renderAsync();
|
|
11
|
+
const saved = await image.saveAsync({ format: SaveFormat.PNG, base64: true });
|
|
12
|
+
savedUri = saved.uri;
|
|
13
|
+
return saved.base64;
|
|
14
|
+
}
|
|
15
|
+
finally {
|
|
16
|
+
image?.release();
|
|
17
|
+
context.release();
|
|
18
|
+
if (savedUri) {
|
|
19
|
+
try {
|
|
20
|
+
new File(savedUri).delete();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
/* Already removed by cache cleanup. */
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Cache by installed version and icon URL; failed icons never prevent listing apps. */
|
|
29
|
+
export class MiniappIcons {
|
|
30
|
+
load;
|
|
31
|
+
cache = new Map();
|
|
32
|
+
constructor(load = thumbnail) {
|
|
33
|
+
this.load = load;
|
|
34
|
+
}
|
|
35
|
+
read(app) {
|
|
36
|
+
if (!app.logoUrl)
|
|
37
|
+
return Promise.resolve(undefined);
|
|
38
|
+
const key = JSON.stringify([app.version, app.logoUrl]);
|
|
39
|
+
const cached = this.cache.get(app.packageName);
|
|
40
|
+
if (cached?.key === key)
|
|
41
|
+
return cached.value;
|
|
42
|
+
const value = this.load(app.logoUrl).catch(() => {
|
|
43
|
+
if (this.cache.get(app.packageName)?.value === value)
|
|
44
|
+
this.cache.delete(app.packageName);
|
|
45
|
+
return undefined;
|
|
46
|
+
});
|
|
47
|
+
this.cache.set(app.packageName, { key, value });
|
|
48
|
+
// Bound memory even if apps are repeatedly installed and removed.
|
|
49
|
+
if (this.cache.size > 64)
|
|
50
|
+
this.cache.delete(this.cache.keys().next().value);
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=MiniappIcons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MiniappIcons.js","sourceRoot":"","sources":["../../src/services/MiniappIcons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;AACrC,OAAO,EAAC,gBAAgB,EAAE,UAAU,EAAC,MAAM,wBAAwB,CAAA;AAInE,uFAAuF;AACvF,KAAK,UAAU,SAAS,CAAC,GAAW;IAClC,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;IAChD,IAAI,KAAkE,CAAA;IACtE,IAAI,QAA4B,CAAA;IAChC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,EAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAC,CAAC,CAAA;QACvC,KAAK,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAA;QACnC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,EAAC,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAC,CAAC,CAAA;QAC3E,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAA;QACpB,OAAO,KAAK,CAAC,MAAM,CAAA;IACrB,CAAC;YAAS,CAAC;QACT,KAAK,EAAE,OAAO,EAAE,CAAA;QAChB,OAAO,CAAC,OAAO,EAAE,CAAA;QACjB,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC;gBACH,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAA;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,uCAAuC;YACzC,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,wFAAwF;AACxF,MAAM,OAAO,YAAY;IAGM;IAFrB,KAAK,GAAG,IAAI,GAAG,EAA6D,CAAA;IAEpF,YAA6B,OAAO,SAAS;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjD,IAAI,CAAC,GAAY;QACf,IAAI,CAAC,GAAG,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAC9C,IAAI,MAAM,EAAE,GAAG,KAAK,GAAG;YAAE,OAAO,MAAM,CAAC,KAAK,CAAA;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC9C,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,KAAK,KAAK,KAAK;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;YACxF,OAAO,SAAS,CAAA;QAClB,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,EAAC,GAAG,EAAE,KAAK,EAAC,CAAC,CAAA;QAC7C,kEAAkE;QAClE,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE;YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAM,CAAC,CAAA;QAC5E,OAAO,KAAK,CAAA;IACd,CAAC;CACF","sourcesContent":["import {File} from \"expo-file-system\"\nimport {ImageManipulator, SaveFormat} from \"expo-image-manipulator\"\n\ntype IconApp = {packageName: string; version?: string; logoUrl: string}\n\n/** Small thumbnails keep the inter-miniapp bridge and every grid frame lightweight. */\nasync function thumbnail(uri: string): Promise<string | undefined> {\n const context = ImageManipulator.manipulate(uri)\n let image: Awaited<ReturnType<typeof context.renderAsync>> | undefined\n let savedUri: string | undefined\n try {\n context.resize({width: 32, height: 32})\n image = await context.renderAsync()\n const saved = await image.saveAsync({format: SaveFormat.PNG, base64: true})\n savedUri = saved.uri\n return saved.base64\n } finally {\n image?.release()\n context.release()\n if (savedUri) {\n try {\n new File(savedUri).delete()\n } catch {\n /* Already removed by cache cleanup. */\n }\n }\n }\n}\n\n/** Cache by installed version and icon URL; failed icons never prevent listing apps. */\nexport class MiniappIcons {\n private cache = new Map<string, {key: string; value: Promise<string | undefined>}>()\n\n constructor(private readonly load = thumbnail) {}\n\n read(app: IconApp): Promise<string | undefined> {\n if (!app.logoUrl) return Promise.resolve(undefined)\n const key = JSON.stringify([app.version, app.logoUrl])\n const cached = this.cache.get(app.packageName)\n if (cached?.key === key) return cached.value\n const value = this.load(app.logoUrl).catch(() => {\n if (this.cache.get(app.packageName)?.value === value) this.cache.delete(app.packageName)\n return undefined\n })\n this.cache.set(app.packageName, {key, value})\n // Bound memory even if apps are repeatedly installed and removed.\n if (this.cache.size > 64) this.cache.delete(this.cache.keys().next().value!)\n return value\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glassly/engine",
|
|
3
|
-
"version": "0.3.3-dev.
|
|
3
|
+
"version": "0.3.3-dev.628",
|
|
4
4
|
"description": "Glassly Engine — miniapp registry, WebView bridge, and miniapp store",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -97,17 +97,17 @@
|
|
|
97
97
|
"registry": "https://registry.npmjs.org/"
|
|
98
98
|
},
|
|
99
99
|
"dependencies": {
|
|
100
|
-
"@glassly/bluetooth-sdk": "0.3.3-dev.
|
|
101
|
-
"@glassly/cloud-client": "0.3.3-dev.
|
|
102
|
-
"@glassly/cloud-protocol": "0.3.3-dev.
|
|
103
|
-
"@glassly/crust": "0.3.3-dev.
|
|
104
|
-
"@glassly/miniapp": "0.3.3-dev.
|
|
100
|
+
"@glassly/bluetooth-sdk": "0.3.3-dev.628",
|
|
101
|
+
"@glassly/cloud-client": "0.3.3-dev.628",
|
|
102
|
+
"@glassly/cloud-protocol": "0.3.3-dev.628",
|
|
103
|
+
"@glassly/crust": "0.3.3-dev.628",
|
|
104
|
+
"@glassly/miniapp": "0.3.3-dev.628",
|
|
105
105
|
"buffer": "^6.0.3",
|
|
106
106
|
"events": "^3.3.0",
|
|
107
107
|
"react-native-marked": "8.1.1",
|
|
108
108
|
"semver": "^7.7.4",
|
|
109
109
|
"typesafe-ts": "^1.7.1",
|
|
110
|
-
"@glassly/llm-providers": "0.3.3-dev.
|
|
110
|
+
"@glassly/llm-providers": "0.3.3-dev.628"
|
|
111
111
|
},
|
|
112
112
|
"devDependencies": {
|
|
113
113
|
"@glassly/llm-providers": "workspace:*",
|
|
@@ -132,6 +132,7 @@
|
|
|
132
132
|
"react-native-reanimated": ">=4.2.1 <5",
|
|
133
133
|
"react-native-worklets": ">=0.7.4 <1",
|
|
134
134
|
"expo-file-system": ">=55.0.0",
|
|
135
|
+
"expo-image-manipulator": ">=55.0.0",
|
|
135
136
|
"react-native-zip-archive": "7.1.1",
|
|
136
137
|
"zustand": "*",
|
|
137
138
|
"expo-battery": ">=55.0.0",
|
|
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
|
|
|
12
12
|
export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "0.3.3",
|
|
15
|
-
"releaseIdentity": "0.3.3-dev.
|
|
16
|
-
"releaseSetId": "glassly-0.3.3-dev.
|
|
17
|
-
"sourceCommit": "
|
|
15
|
+
"releaseIdentity": "0.3.3-dev.628",
|
|
16
|
+
"releaseSetId": "glassly-0.3.3-dev.628",
|
|
17
|
+
"sourceCommit": "bd030b9d1f80511d224d95ead9b8be543c72d153",
|
|
18
18
|
"otaManifestUrl": null,
|
|
19
19
|
"otaManifestSha256": null
|
|
20
20
|
})
|
|
@@ -72,6 +72,7 @@ import overlayPages from "./pages/OverlayPages"
|
|
|
72
72
|
import dashboardOpenTrace from "./debug/DashboardOpenTrace"
|
|
73
73
|
import {isAppForegrounded, isPhoneActive, onAppForegroundChange, onPhoneActivityChange} from "./PhoneActivity"
|
|
74
74
|
import {installedNotificationApps} from "./PhoneNotificationsSync"
|
|
75
|
+
import {MiniappIcons} from "./MiniappIcons"
|
|
75
76
|
import {
|
|
76
77
|
DERIVED_SETTINGS_KEYS,
|
|
77
78
|
SETTINGS_BRIDGE_KEYS,
|
|
@@ -1719,7 +1720,7 @@ class LocalMiniappRuntime {
|
|
|
1719
1720
|
// Inter-miniapp interop (lifecycle is SYSTEM-only; actions are open,
|
|
1720
1721
|
// gated per-action by the target's declared visibility)
|
|
1721
1722
|
case MiniappRequestType.MINIAPPS_LIST:
|
|
1722
|
-
this.handleMiniappsList(packageName, payload, requestId)
|
|
1723
|
+
void this.handleMiniappsList(packageName, payload, requestId)
|
|
1723
1724
|
break
|
|
1724
1725
|
case MiniappRequestType.MINIAPPS_START:
|
|
1725
1726
|
void this.handleMiniappsStart(packageName, payload, requestId)
|
|
@@ -5904,18 +5905,28 @@ class LocalMiniappRuntime {
|
|
|
5904
5905
|
}
|
|
5905
5906
|
}
|
|
5906
5907
|
|
|
5907
|
-
private
|
|
5908
|
+
private miniappIcons = new MiniappIcons()
|
|
5909
|
+
|
|
5910
|
+
private async handleMiniappsList(
|
|
5911
|
+
packageName: string,
|
|
5912
|
+
payload: Record<string, unknown>,
|
|
5913
|
+
requestId?: string,
|
|
5914
|
+
): Promise<void> {
|
|
5908
5915
|
if (!this.requireMiniappsPermission(packageName, requestId, "list")) return
|
|
5909
5916
|
const includeIncompatible = payload.includeIncompatible === true
|
|
5910
|
-
const
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
.map((
|
|
5917
|
+
const apps = this.interopApps().filter(
|
|
5918
|
+
(a) =>
|
|
5919
|
+
a.packageName &&
|
|
5920
|
+
a.packageName !== packageName &&
|
|
5921
|
+
!a.packageName.includes("@empty") &&
|
|
5922
|
+
(includeIncompatible || a.compatibility?.isCompatible !== false),
|
|
5923
|
+
)
|
|
5924
|
+
const infos = await Promise.all(
|
|
5925
|
+
apps.map(async (app) => ({
|
|
5926
|
+
...this.buildMiniappInfo(app),
|
|
5927
|
+
...(payload.includeIcons === true ? {icon: await this.miniappIcons.read(app)} : {}),
|
|
5928
|
+
})),
|
|
5929
|
+
)
|
|
5919
5930
|
this.sendResult(packageName, requestId, true, infos)
|
|
5920
5931
|
this.auditInterop({caller: packageName, op: "list", ok: true})
|
|
5921
5932
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {File} from "expo-file-system"
|
|
2
|
+
import {ImageManipulator, SaveFormat} from "expo-image-manipulator"
|
|
3
|
+
|
|
4
|
+
type IconApp = {packageName: string; version?: string; logoUrl: string}
|
|
5
|
+
|
|
6
|
+
/** Small thumbnails keep the inter-miniapp bridge and every grid frame lightweight. */
|
|
7
|
+
async function thumbnail(uri: string): Promise<string | undefined> {
|
|
8
|
+
const context = ImageManipulator.manipulate(uri)
|
|
9
|
+
let image: Awaited<ReturnType<typeof context.renderAsync>> | undefined
|
|
10
|
+
let savedUri: string | undefined
|
|
11
|
+
try {
|
|
12
|
+
context.resize({width: 32, height: 32})
|
|
13
|
+
image = await context.renderAsync()
|
|
14
|
+
const saved = await image.saveAsync({format: SaveFormat.PNG, base64: true})
|
|
15
|
+
savedUri = saved.uri
|
|
16
|
+
return saved.base64
|
|
17
|
+
} finally {
|
|
18
|
+
image?.release()
|
|
19
|
+
context.release()
|
|
20
|
+
if (savedUri) {
|
|
21
|
+
try {
|
|
22
|
+
new File(savedUri).delete()
|
|
23
|
+
} catch {
|
|
24
|
+
/* Already removed by cache cleanup. */
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Cache by installed version and icon URL; failed icons never prevent listing apps. */
|
|
31
|
+
export class MiniappIcons {
|
|
32
|
+
private cache = new Map<string, {key: string; value: Promise<string | undefined>}>()
|
|
33
|
+
|
|
34
|
+
constructor(private readonly load = thumbnail) {}
|
|
35
|
+
|
|
36
|
+
read(app: IconApp): Promise<string | undefined> {
|
|
37
|
+
if (!app.logoUrl) return Promise.resolve(undefined)
|
|
38
|
+
const key = JSON.stringify([app.version, app.logoUrl])
|
|
39
|
+
const cached = this.cache.get(app.packageName)
|
|
40
|
+
if (cached?.key === key) return cached.value
|
|
41
|
+
const value = this.load(app.logoUrl).catch(() => {
|
|
42
|
+
if (this.cache.get(app.packageName)?.value === value) this.cache.delete(app.packageName)
|
|
43
|
+
return undefined
|
|
44
|
+
})
|
|
45
|
+
this.cache.set(app.packageName, {key, value})
|
|
46
|
+
// Bound memory even if apps are repeatedly installed and removed.
|
|
47
|
+
if (this.cache.size > 64) this.cache.delete(this.cache.keys().next().value!)
|
|
48
|
+
return value
|
|
49
|
+
}
|
|
50
|
+
}
|