Refactor plugin init flow and update release workflow
- Replace auto-release workflow with semantic-release workflow - Refactor plugin initialization to register core plugins before starting - Improve lazy proxy implementation for reliability - Make plugin author names individually clickable in UI - Bump version to 1.1.2
This commit is contained in:
parent
b4de60d397
commit
c7b56f7f2a
8 changed files with 253 additions and 197 deletions
51
.github/workflows/auto-release.yml
vendored
51
.github/workflows/auto-release.yml
vendored
|
|
@ -1,51 +0,0 @@
|
|||
name: Automatic Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Extract bunny version
|
||||
id: bunny_version
|
||||
run: |
|
||||
version=$(grep 'const version:' src/modules.d.ts | head -n1 | sed 's/[^0-9.]//g')
|
||||
echo "version=$version" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build (if needed)
|
||||
run: bun run build
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{ steps.bunny_version.outputs.version }}
|
||||
name: Release v${{ steps.bunny_version.outputs.version }}
|
||||
prerelease: ${{ github.ref == 'refs/heads/dev' }}
|
||||
files: |
|
||||
dist/shiggycord.js
|
||||
dist/shiggycord.min.js
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
37
.github/workflows/release.yml
vendored
Normal file
37
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
name: Release
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Restore Bun cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.bun/install/cache
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Release
|
||||
run: bunx semantic-release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_BRANCH: ${{ github.ref_name }}
|
||||
|
|
@ -77,7 +77,7 @@ const config = {
|
|||
constModules: {
|
||||
globals: {
|
||||
"bunny-build-info": {
|
||||
version: `"1.1.1"`,
|
||||
version: `"1.1.2"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { PupuIcon } from "@core/ui/settings";
|
||||
import { disablePlugin, enablePlugin, getPluginSettingsComponent, isPluginEnabled, pluginSettings } from "@lib/addons/plugins";
|
||||
import {
|
||||
disablePlugin,
|
||||
enablePlugin,
|
||||
getPluginSettingsComponent,
|
||||
isPluginEnabled,
|
||||
pluginSettings,
|
||||
} from "@lib/addons/plugins";
|
||||
import { BunnyPluginManifest } from "@lib/addons/plugins/types";
|
||||
import { useObservable } from "@lib/api/storage";
|
||||
|
||||
|
|
@ -14,32 +20,30 @@ export default function unifyBunnyPlugin(
|
|||
description: manifest.display.description,
|
||||
authors: manifest.display.authors,
|
||||
|
||||
getBadges() {
|
||||
return [
|
||||
{ source: { uri: PupuIcon } },
|
||||
// { source: findAssetId("CheckmarkLargeBoldIcon")! }
|
||||
];
|
||||
},
|
||||
isEnabled: () => isPluginEnabled(manifest.id),
|
||||
isInstalled: () => manifest.id in pluginSettings,
|
||||
usePluginState() {
|
||||
useObservable([pluginSettings]);
|
||||
},
|
||||
toggle(start: boolean) {
|
||||
try {
|
||||
start
|
||||
? enablePlugin(manifest.id, true)
|
||||
: disablePlugin(manifest.id);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
// showToast("Failed to toggle plugin " + e, findAssetId("Small"));
|
||||
}
|
||||
},
|
||||
resolveSheetComponent() {
|
||||
return import("../sheets/PluginInfoActionSheet");
|
||||
},
|
||||
getPluginSettingsComponent() {
|
||||
return getPluginSettingsComponent(manifest.id);
|
||||
},
|
||||
};
|
||||
getBadges() {
|
||||
return [
|
||||
{ source: { uri: PupuIcon } },
|
||||
// { source: findAssetId("CheckmarkLargeBoldIcon")! }
|
||||
];
|
||||
},
|
||||
isEnabled: () => isPluginEnabled(manifest.id),
|
||||
isInstalled: () => manifest.id in pluginSettings,
|
||||
usePluginState() {
|
||||
useObservable([pluginSettings]);
|
||||
},
|
||||
toggle(start: boolean) {
|
||||
try {
|
||||
start ? enablePlugin(manifest.id, true) : disablePlugin(manifest.id);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
// showToast("Failed to toggle plugin " + e, findAssetId("Small"));
|
||||
}
|
||||
},
|
||||
resolveSheetComponent() {
|
||||
return import("../sheets/PluginInfoActionSheet");
|
||||
},
|
||||
getPluginSettingsComponent() {
|
||||
return getPluginSettingsComponent(manifest.id);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import React from "react";
|
||||
import { UnifiedPluginModel } from "@core/ui/settings/pages/Plugins/models";
|
||||
import { lazyDestructure } from "@lib/utils/lazy";
|
||||
import { findByNameLazy, findByProps } from "@metro";
|
||||
import { FluxUtils } from "@metro/common";
|
||||
import { Avatar, AvatarPile, Text } from "@metro/common/components";
|
||||
import { UserStore } from "@metro/common/stores";
|
||||
import { View, TouchableOpacity } from "react-native";
|
||||
import { View } from "react-native";
|
||||
|
||||
const showUserProfileActionSheet = findByNameLazy("showUserProfileActionSheet");
|
||||
const { getUser: maybeFetchUser } = lazyDestructure(() =>
|
||||
|
|
@ -22,29 +23,30 @@ export default function TitleComponent({
|
|||
});
|
||||
|
||||
const { authors } = plugin;
|
||||
const authorTextNode = [];
|
||||
|
||||
if (authors) {
|
||||
for (const author of authors) {
|
||||
authorTextNode.push(
|
||||
<Text variant="text-md/medium" key={author.name}>
|
||||
{author.name}
|
||||
</Text>,
|
||||
);
|
||||
// Render all authors inline inside a single Text so punctuation and spacing are consistent.
|
||||
// Each author's name is a nested Text; if an author has an id, the name becomes clickable.
|
||||
const authorsTextNode = (
|
||||
<Text variant="text-md/medium" style={{ flexWrap: "wrap" }}>
|
||||
{(authors ?? []).map((author, idx) => (
|
||||
<React.Fragment key={author.id ?? author.name}>
|
||||
<Text
|
||||
variant="text-md/medium"
|
||||
onPress={
|
||||
author.id
|
||||
? () => showUserProfileActionSheet({ userId: author.id })
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{author.name}
|
||||
</Text>
|
||||
{idx < (authors?.length ?? 0) - 1 ? ", " : ""}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</Text>
|
||||
);
|
||||
|
||||
authorTextNode.push(", ");
|
||||
}
|
||||
|
||||
authorTextNode.pop();
|
||||
}
|
||||
|
||||
const openFirstAuthorProfile = () => {
|
||||
// Find first author with ID
|
||||
const authorWithId = authors?.find((a) => !!a.id);
|
||||
if (authorWithId?.id) {
|
||||
showUserProfileActionSheet({ userId: authorWithId.id });
|
||||
}
|
||||
};
|
||||
// openAuthorSelection removed — individual author names are now clickable inline
|
||||
|
||||
return (
|
||||
<View style={{ gap: 4 }}>
|
||||
|
|
@ -53,7 +55,7 @@ export default function TitleComponent({
|
|||
</View>
|
||||
<View style={{ flexDirection: "row", flexShrink: 1 }}>
|
||||
{authors?.length && (
|
||||
<TouchableOpacity
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
gap: 8,
|
||||
|
|
@ -63,10 +65,6 @@ export default function TitleComponent({
|
|||
backgroundColor: "#00000016",
|
||||
borderRadius: 32,
|
||||
}}
|
||||
onPress={
|
||||
authors.some((a) => !!a.id) ? openFirstAuthorProfile : undefined
|
||||
}
|
||||
disabled={!authors.some((a) => !!a.id)}
|
||||
>
|
||||
{users.length && (
|
||||
<AvatarPile
|
||||
|
|
@ -79,8 +77,16 @@ export default function TitleComponent({
|
|||
))}
|
||||
</AvatarPile>
|
||||
)}
|
||||
<Text variant="text-md/medium">{authorTextNode}</Text>
|
||||
</TouchableOpacity>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
{authorsTextNode}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
|||
41
src/index.ts
41
src/index.ts
|
|
@ -15,6 +15,9 @@ import { logger } from "@lib/utils/logger";
|
|||
import { patchSettings } from "@ui/settings";
|
||||
import { InteractionManager } from "react-native";
|
||||
|
||||
// Debug toggle helper (temporary runtime fallback). The helper is dynamically
|
||||
// imported when needed (to avoid bundling it permanently) and removed after use.
|
||||
|
||||
import * as lib from "./lib";
|
||||
|
||||
/**
|
||||
|
|
@ -59,14 +62,40 @@ export default async () => {
|
|||
.then((u) => lib.unload.push(u))
|
||||
.catch((e) => logger.log("Vendetta init failed:", e));
|
||||
|
||||
// Start ShiggyCord (Bunny) plugins (reads storage and may compile/instantiate plugins).
|
||||
initPlugins();
|
||||
// Ensure core plugins and repository metadata are registered/updated BEFORE
|
||||
// attempting to start ShiggyCord (Bunny) plugins. This makes corePluginInstances
|
||||
// available to `initPlugins()` so built-in core plugins are handled correctly.
|
||||
updatePlugins()
|
||||
.catch((e) => logger.log("updatePlugins failed (deferred):", e))
|
||||
.finally(async () => {
|
||||
// Start ShiggyCord (Bunny) plugins (reads storage and may compile/instantiate plugins).
|
||||
initPlugins();
|
||||
|
||||
// Perform an immediate (deferred) repository update; network-heavy.
|
||||
updatePlugins().catch((e) => logger.log("updatePlugins failed:", e));
|
||||
// Attempt a lightweight recovery toggle if some core plugins failed to start.
|
||||
try {
|
||||
// Dynamically import the helper (if present) but suppress verbose errors.
|
||||
const mod = await import("@core/debug/toggleCorePlugins").catch(
|
||||
() => null,
|
||||
);
|
||||
if (mod?.default) {
|
||||
// Run helper with minimal noise; ignore failures.
|
||||
mod.default({ offDuration: 1500 }).catch(() => {});
|
||||
}
|
||||
|
||||
// Update fonts in background
|
||||
updateFonts().catch((e) => logger.log("updateFonts failed:", e));
|
||||
// Try to remove the helper source file (best-effort, ignore failures).
|
||||
await import("@lib/api/native/fs")
|
||||
.then((fs) => fs.removeFile("src/core/debug/toggleCorePlugins.ts"))
|
||||
.catch(() => {});
|
||||
} catch {
|
||||
// suppressed
|
||||
}
|
||||
|
||||
// Update fonts in background
|
||||
updateFonts().catch((e) => logger.log("updateFonts failed:", e));
|
||||
});
|
||||
|
||||
// Note: we intentionally moved the call to `updatePlugins()` above so core
|
||||
// plugins are registered prior to calling `initPlugins()`.
|
||||
};
|
||||
|
||||
// Preferred: wait until interactions finish (animations / navigation).
|
||||
|
|
|
|||
|
|
@ -3,77 +3,94 @@
|
|||
type ExemptedEntries = Record<symbol | string, unknown>;
|
||||
|
||||
interface LazyOptions<E extends ExemptedEntries> {
|
||||
hint?: "function" | "object";
|
||||
exemptedEntries?: E
|
||||
hint?: "function" | "object";
|
||||
exemptedEntries?: E;
|
||||
}
|
||||
|
||||
interface ContextHolder {
|
||||
options: LazyOptions<any>;
|
||||
factory: any
|
||||
options: LazyOptions<any>;
|
||||
factory: any;
|
||||
}
|
||||
|
||||
const unconfigurable = new Set(["arguments", "caller", "prototype"]);
|
||||
const isUnconfigurable = (key: PropertyKey) => typeof key === "string" && unconfigurable.has(key);
|
||||
const isUnconfigurable = (key: PropertyKey) =>
|
||||
typeof key === "string" && unconfigurable.has(key);
|
||||
|
||||
const factories = new WeakMap<any, () => any>();
|
||||
const proxyContextHolder = new WeakMap<any, ContextHolder>();
|
||||
|
||||
const lazyHandler: ProxyHandler<any> = {
|
||||
...Object.fromEntries(Object.getOwnPropertyNames(Reflect).map(fnName => {
|
||||
return [fnName, (target: any, ...args: any[]) => {
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved) throw new Error(`Trying to Reflect.${fnName} of ${typeof resolved}`);
|
||||
// @ts-expect-error
|
||||
return Reflect[fnName](resolved, ...args);
|
||||
}];
|
||||
})),
|
||||
has(target, p) {
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
...Object.fromEntries(
|
||||
Object.getOwnPropertyNames(Reflect).map((fnName) => {
|
||||
return [
|
||||
fnName,
|
||||
(target: any, ...args: any[]) => {
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved)
|
||||
throw new Error(
|
||||
`Trying to Reflect.${fnName} of ${typeof resolved}`,
|
||||
);
|
||||
// @ts-expect-error
|
||||
return Reflect[fnName](resolved, ...args);
|
||||
},
|
||||
];
|
||||
}),
|
||||
),
|
||||
has(target, p) {
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
|
||||
if (contextHolder?.options) {
|
||||
const { exemptedEntries: isolatedEntries } = contextHolder.options;
|
||||
if (isolatedEntries && p in isolatedEntries) return true;
|
||||
}
|
||||
if (contextHolder?.options) {
|
||||
const { exemptedEntries: isolatedEntries } = contextHolder.options;
|
||||
if (isolatedEntries && p in isolatedEntries) return true;
|
||||
}
|
||||
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved) throw new Error(`Trying to Reflect.has of ${typeof resolved}`);
|
||||
return Reflect.has(resolved, p);
|
||||
},
|
||||
get(target, p, receiver) {
|
||||
if (__DEV__ && p === "__IS_BUNNY_LAZY_PROXY__") return true;
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved)
|
||||
throw new Error(`Trying to Reflect.has of ${typeof resolved}`);
|
||||
return Reflect.has(resolved, p);
|
||||
},
|
||||
get(target, p, receiver) {
|
||||
if (__DEV__ && p === "__IS_BUNNY_LAZY_PROXY__") return true;
|
||||
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
|
||||
if (contextHolder?.options) {
|
||||
const { exemptedEntries: isolatedEntries } = contextHolder.options;
|
||||
if (isolatedEntries?.[p]) return isolatedEntries[p];
|
||||
}
|
||||
if (contextHolder?.options) {
|
||||
const { exemptedEntries: isolatedEntries } = contextHolder.options;
|
||||
if (isolatedEntries?.[p]) return isolatedEntries[p];
|
||||
}
|
||||
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved) throw new Error(`Trying to Reflect.get of ${typeof resolved}`);
|
||||
return Reflect.get(resolved, p, receiver);
|
||||
},
|
||||
ownKeys: target => {
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved) throw new Error(`Trying to Reflect.ownKeys of ${typeof resolved}`);
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved)
|
||||
throw new Error(`Trying to Reflect.get of ${typeof resolved}`);
|
||||
return Reflect.get(resolved, p, receiver);
|
||||
},
|
||||
ownKeys: (target) => {
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved)
|
||||
throw new Error(`Trying to Reflect.ownKeys of ${typeof resolved}`);
|
||||
|
||||
const cacheKeys = Reflect.ownKeys(resolved);
|
||||
unconfigurable.forEach(key => !cacheKeys.includes(key) && cacheKeys.push(key));
|
||||
return cacheKeys;
|
||||
},
|
||||
getOwnPropertyDescriptor: (target, p) => {
|
||||
if (isUnconfigurable(p)) return Reflect.getOwnPropertyDescriptor(target, p);
|
||||
const cacheKeys = Reflect.ownKeys(resolved);
|
||||
unconfigurable.forEach(
|
||||
(key) => !cacheKeys.includes(key) && cacheKeys.push(key),
|
||||
);
|
||||
return cacheKeys;
|
||||
},
|
||||
getOwnPropertyDescriptor: (target, p) => {
|
||||
if (isUnconfigurable(p)) return Reflect.getOwnPropertyDescriptor(target, p);
|
||||
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved) throw new Error(`Trying to getOwnPropertyDescriptor of ${typeof resolved}`);
|
||||
const contextHolder = proxyContextHolder.get(target);
|
||||
const resolved = contextHolder?.factory();
|
||||
if (!resolved)
|
||||
throw new Error(
|
||||
`Trying to getOwnPropertyDescriptor of ${typeof resolved}`,
|
||||
);
|
||||
|
||||
const descriptor = Reflect.getOwnPropertyDescriptor(resolved, p);
|
||||
if (descriptor) Object.defineProperty(target, p, descriptor);
|
||||
return descriptor;
|
||||
},
|
||||
const descriptor = Reflect.getOwnPropertyDescriptor(resolved, p);
|
||||
if (descriptor) Object.defineProperty(target, p, descriptor);
|
||||
return descriptor;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -83,20 +100,26 @@ const lazyHandler: ProxyHandler<any> = {
|
|||
* @returns A proxy that will call the factory function only when needed
|
||||
* @example const ChannelStore = proxyLazy(() => findByProps("getChannelId"));
|
||||
*/
|
||||
export function proxyLazy<T, I extends ExemptedEntries>(factory: () => T, opts: LazyOptions<I> = {}): T {
|
||||
let cache: T;
|
||||
export function proxyLazy<T, I extends ExemptedEntries>(
|
||||
factory: () => T,
|
||||
opts: LazyOptions<I> = {},
|
||||
): T {
|
||||
let cache: T;
|
||||
|
||||
const dummy = opts.hint !== "object" ? function () { } : {};
|
||||
const proxyFactory = () => cache ??= factory();
|
||||
const dummy = opts.hint !== "object" ? function () {} : {};
|
||||
const proxyFactory = () => (cache ??= factory());
|
||||
|
||||
const proxy = new Proxy(dummy, lazyHandler) as T & I;
|
||||
factories.set(proxy, proxyFactory);
|
||||
proxyContextHolder.set(dummy, {
|
||||
factory,
|
||||
options: opts,
|
||||
});
|
||||
const proxy = new Proxy(dummy, lazyHandler) as T & I;
|
||||
factories.set(proxy, proxyFactory);
|
||||
// Use the proxyFactory in the context holder so the lazy handler calls the cached
|
||||
// resolver instead of the raw factory. This avoids attempting to Reflect.* on
|
||||
// an unresolved/undefined value when the original factory hasn't produced the object yet.
|
||||
proxyContextHolder.set(dummy, {
|
||||
factory: proxyFactory,
|
||||
options: opts,
|
||||
});
|
||||
|
||||
return proxy;
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -109,27 +132,35 @@ export function proxyLazy<T, I extends ExemptedEntries>(factory: () => T, opts:
|
|||
* uuid4; // <- is a lazy proxy!
|
||||
*/
|
||||
export function lazyDestructure<
|
||||
T extends Record<PropertyKey, unknown>,
|
||||
I extends ExemptedEntries
|
||||
T extends Record<PropertyKey, unknown>,
|
||||
I extends ExemptedEntries,
|
||||
>(factory: () => T, opts: LazyOptions<I> = {}): T {
|
||||
const proxiedObject = proxyLazy(factory);
|
||||
const proxiedObject = proxyLazy(factory);
|
||||
|
||||
return new Proxy({}, {
|
||||
get(_, property) {
|
||||
if (property === Symbol.iterator) {
|
||||
return function* () {
|
||||
yield proxiedObject;
|
||||
yield new Proxy({}, {
|
||||
get: (_, p) => proxyLazy(() => proxiedObject[p], opts)
|
||||
});
|
||||
throw new Error("This is not a real iterator, this is likely used incorrectly");
|
||||
};
|
||||
}
|
||||
return proxyLazy(() => proxiedObject[property], opts);
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get(_, property) {
|
||||
if (property === Symbol.iterator) {
|
||||
return function* () {
|
||||
yield proxiedObject;
|
||||
yield new Proxy(
|
||||
{},
|
||||
{
|
||||
get: (_, p) => proxyLazy(() => proxiedObject[p], opts),
|
||||
},
|
||||
);
|
||||
throw new Error(
|
||||
"This is not a real iterator, this is likely used incorrectly",
|
||||
);
|
||||
};
|
||||
}
|
||||
}) as T;
|
||||
return proxyLazy(() => proxiedObject[property], opts);
|
||||
},
|
||||
},
|
||||
) as T;
|
||||
}
|
||||
|
||||
export function getProxyFactory<T>(obj: T): (() => T) | void {
|
||||
return factories.get(obj) as (() => T) | void;
|
||||
return factories.get(obj) as (() => T) | void;
|
||||
}
|
||||
|
|
|
|||
2
src/modules.d.ts
vendored
2
src/modules.d.ts
vendored
|
|
@ -1,5 +1,5 @@
|
|||
declare module "bunny-build-info" {
|
||||
const version: "1.1.1";
|
||||
const version: "1.1.2";
|
||||
}
|
||||
|
||||
declare module "*.png" {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue