@portel/photon 1.34.2 → 1.35.0
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 +1 -0
- package/dist/a2a/card-generator.js +1 -1
- package/dist/auto-ui/beam/external-mcp.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-browse.js +1 -1
- package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.js +27 -8
- package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
- package/dist/auto-ui/beam/subscription.d.ts.map +1 -1
- package/dist/auto-ui/beam/subscription.js +4 -1
- package/dist/auto-ui/beam/subscription.js.map +1 -1
- package/dist/auto-ui/beam.d.ts +2 -0
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +60 -3
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/bridge/renderers.d.ts.map +1 -1
- package/dist/auto-ui/bridge/renderers.js +44 -1
- package/dist/auto-ui/bridge/renderers.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +1 -1
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/beam.bundle.js +81 -83
- package/dist/beam.bundle.js.map +3 -3
- package/dist/cli/commands/info.d.ts.map +1 -1
- package/dist/cli/commands/info.js +3 -1
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/ps.d.ts +2 -4
- package/dist/cli/commands/ps.d.ts.map +1 -1
- package/dist/cli/commands/ps.js +5 -11
- package/dist/cli/commands/ps.js.map +1 -1
- package/dist/cli-alias.js +1 -0
- package/dist/cli-alias.js.map +1 -1
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +31 -19
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.d.ts.map +1 -1
- package/dist/daemon/manager.js +9 -0
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/registry-keys.d.ts +6 -0
- package/dist/daemon/registry-keys.d.ts.map +1 -1
- package/dist/daemon/registry-keys.js +9 -0
- package/dist/daemon/registry-keys.js.map +1 -1
- package/dist/daemon/server.js +154 -30
- package/dist/daemon/server.js.map +1 -1
- package/dist/deploy/cloudflare.js.map +1 -1
- package/dist/formats/format-registry.d.ts +32 -0
- package/dist/formats/format-registry.d.ts.map +1 -0
- package/dist/formats/format-registry.js +67 -0
- package/dist/formats/format-registry.js.map +1 -0
- package/dist/loader.d.ts +6 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +121 -30
- package/dist/loader.js.map +1 -1
- package/dist/marketplace-manager.js +1 -1
- package/dist/marketplace-manager.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +1 -0
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/serv/middleware/tenant.d.ts.map +1 -1
- package/dist/serv/middleware/tenant.js +1 -0
- package/dist/serv/middleware/tenant.js.map +1 -1
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +158 -153
- package/dist/server.js.map +1 -1
- package/dist/settings-persistence.d.ts +10 -0
- package/dist/settings-persistence.d.ts.map +1 -1
- package/dist/settings-persistence.js +25 -4
- package/dist/settings-persistence.js.map +1 -1
- package/dist/shared/audit.d.ts.map +1 -1
- package/dist/shared/audit.js +2 -1
- package/dist/shared/audit.js.map +1 -1
- package/dist/shared/identity.d.ts +50 -0
- package/dist/shared/identity.d.ts.map +1 -0
- package/dist/shared/identity.js +61 -0
- package/dist/shared/identity.js.map +1 -0
- package/dist/shared/memory-sqlite.d.ts.map +1 -1
- package/dist/shared/memory-sqlite.js +1 -0
- package/dist/shared/memory-sqlite.js.map +1 -1
- package/dist/shared/security.d.ts.map +1 -1
- package/dist/shared/security.js +7 -1
- package/dist/shared/security.js.map +1 -1
- package/dist/shared-utils.d.ts.map +1 -1
- package/dist/shared-utils.js +2 -2
- package/dist/shared-utils.js.map +1 -1
- package/dist/tasks/store.d.ts.map +1 -1
- package/dist/tasks/store.js +2 -1
- package/dist/tasks/store.js.map +1 -1
- package/dist/telemetry/context.d.ts.map +1 -1
- package/dist/telemetry/context.js +8 -2
- package/dist/telemetry/context.js.map +1 -1
- package/dist/types/server-types.d.ts +12 -0
- package/dist/types/server-types.d.ts.map +1 -1
- package/dist/version-notify.d.ts.map +1 -1
- package/dist/version-notify.js +2 -1
- package/dist/version-notify.js.map +1 -1
- package/package.json +4 -3
- package/templates/cloudflare/worker.ts.template +182 -4
- package/dist/photons/canvas/ui/canvas.photon.html +0 -1493
- package/dist/photons/canvas.photon.d.ts +0 -400
- package/dist/photons/canvas.photon.d.ts.map +0 -1
- package/dist/photons/canvas.photon.js +0 -662
- package/dist/photons/canvas.photon.js.map +0 -1
- package/dist/photons/canvas.photon.ts +0 -814
- package/dist/photons/ui/canvas.photon.html +0 -624
package/dist/loader.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import * as fs from 'fs/promises';
|
|
7
7
|
import { realpathSync, existsSync, mkdirSync, symlinkSync, readFileSync, statSync, } from 'fs';
|
|
8
8
|
import { readText, readJSON, writeText, writeJSON } from './shared/io.js';
|
|
9
|
+
import { qualifyChannel, circuitKey, preloadedCacheKey, instanceCacheKey, } from './shared/identity.js';
|
|
9
10
|
import { parseCfBindings } from './cf-bindings-parser.js';
|
|
10
11
|
import { CFLocalRuntime, mergeBindings } from './runtime/cf-local.js';
|
|
11
12
|
import { scanCfUsage } from './cf-usage-scanner.js';
|
|
@@ -43,7 +44,7 @@ executionContext,
|
|
|
43
44
|
// Lock helper
|
|
44
45
|
withLock as withLockHelper,
|
|
45
46
|
// Middleware system
|
|
46
|
-
builtinRegistry, MiddlewareRegistry, buildMiddlewareChain, getCacheDir, } from '@portel/photon-core';
|
|
47
|
+
builtinRegistry, MiddlewareRegistry, buildMiddlewareChain, getCacheDir, getPhotonDataDir, } from '@portel/photon-core';
|
|
47
48
|
import { getDefaultContext } from './context.js';
|
|
48
49
|
import { getInstanceStatePath } from './context-store.js';
|
|
49
50
|
import { ContextRegistry, RepeatDetector, assembleSampleParams, } from './sample-augmenter.js';
|
|
@@ -235,10 +236,14 @@ function injectEmitHelpers(instance) {
|
|
|
235
236
|
instance.log = (message, opts = {}) => emit({ emit: 'log', message, level: opts.level ?? 'info', data: opts.data });
|
|
236
237
|
}
|
|
237
238
|
if (!('status' in instance)) {
|
|
238
|
-
instance.status = (message) => emit(
|
|
239
|
+
instance.status = (message, value) => emit(typeof message === 'string'
|
|
240
|
+
? { emit: 'status', message, ...(value !== undefined && { value }) }
|
|
241
|
+
: { emit: 'status', ...message });
|
|
239
242
|
}
|
|
240
243
|
if (!('progress' in instance)) {
|
|
241
|
-
instance.progress = (value, message) => emit(
|
|
244
|
+
instance.progress = (value, message, meta) => emit(typeof value === 'number'
|
|
245
|
+
? { emit: 'progress', value, ...(message && { message }), ...(meta && { meta }) }
|
|
246
|
+
: { emit: 'progress', ...value });
|
|
242
247
|
}
|
|
243
248
|
if (!('thinking' in instance)) {
|
|
244
249
|
instance.thinking = (active = true) => emit({ emit: 'thinking', active });
|
|
@@ -389,6 +394,28 @@ function injectResourceNotifier(instance, notifier) {
|
|
|
389
394
|
}
|
|
390
395
|
};
|
|
391
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* Formats @portel/cli's formatOutput can render directly. Anything else
|
|
399
|
+
* (gauge, stack, chart:*, ...) would hit formatDataWithHint's switch with
|
|
400
|
+
* no matching case and silently drop the data — fall back to auto-detect
|
|
401
|
+
* instead so the value always stays visible.
|
|
402
|
+
*/
|
|
403
|
+
const CLI_BASE_FORMATS = new Set([
|
|
404
|
+
'primitive',
|
|
405
|
+
'list',
|
|
406
|
+
'table',
|
|
407
|
+
'tree',
|
|
408
|
+
'card',
|
|
409
|
+
'tabs',
|
|
410
|
+
'accordion',
|
|
411
|
+
'none',
|
|
412
|
+
'json',
|
|
413
|
+
'markdown',
|
|
414
|
+
'yaml',
|
|
415
|
+
'xml',
|
|
416
|
+
'html',
|
|
417
|
+
'code',
|
|
418
|
+
]);
|
|
392
419
|
/**
|
|
393
420
|
* Render a formatted value in the CLI using @portel/cli's formatOutput.
|
|
394
421
|
* Uses clear-and-replace semantics — each call overwrites the previous render.
|
|
@@ -406,9 +433,10 @@ function renderCLIFormat(format, value) {
|
|
|
406
433
|
}
|
|
407
434
|
return;
|
|
408
435
|
}
|
|
436
|
+
const safeFormat = CLI_BASE_FORMATS.has(format) || format.startsWith('code:') ? format : undefined;
|
|
409
437
|
// Use the eagerly-imported formatter — synchronous, so line counting works
|
|
410
438
|
cliRenderZone.render(() => {
|
|
411
|
-
cliFormatOutput(value,
|
|
439
|
+
cliFormatOutput(value, safeFormat);
|
|
412
440
|
});
|
|
413
441
|
}
|
|
414
442
|
catch {
|
|
@@ -1234,7 +1262,7 @@ export class PhotonLoader {
|
|
|
1234
1262
|
if (caps.size > 0) {
|
|
1235
1263
|
this.log(`🔍 Detected capabilities for ${name}: ${[...caps].join(', ')}`);
|
|
1236
1264
|
}
|
|
1237
|
-
this.injectPathHelpers(instance
|
|
1265
|
+
this.injectPathHelpers(instance);
|
|
1238
1266
|
// Always-inject emit + its helpers (render/toast/log/status/progress/
|
|
1239
1267
|
// thinking). The injection is a pure closure — zero cost if unused.
|
|
1240
1268
|
// Dropping the capability-detection gate means typed-access patterns
|
|
@@ -1254,7 +1282,7 @@ export class PhotonLoader {
|
|
|
1254
1282
|
// Also publish to channel broker if channel is specified
|
|
1255
1283
|
if (data && typeof data.channel === 'string') {
|
|
1256
1284
|
// Auto-prefix channel with photon name if not already namespaced
|
|
1257
|
-
const channel =
|
|
1285
|
+
const channel = qualifyChannel(name, data.channel);
|
|
1258
1286
|
import('@portel/photon-core')
|
|
1259
1287
|
.then(({ getBroker }) => {
|
|
1260
1288
|
const broker = getBroker();
|
|
@@ -1862,10 +1890,7 @@ export class PhotonLoader {
|
|
|
1862
1890
|
}
|
|
1863
1891
|
// Detect and inject capabilities for plain classes
|
|
1864
1892
|
if (tsContent && typeof instance.executeTool !== 'function') {
|
|
1865
|
-
|
|
1866
|
-
if (detectEmitHelperUsage(tsContent))
|
|
1867
|
-
caps.add('emit');
|
|
1868
|
-
this.injectPathHelpers(instance, tsContent);
|
|
1893
|
+
this.injectPathHelpers(instance);
|
|
1869
1894
|
// Always-inject emit (see primary path). User-defined wins.
|
|
1870
1895
|
if (!instance.emit) {
|
|
1871
1896
|
instance.emit = (data) => {
|
|
@@ -1878,7 +1903,7 @@ export class PhotonLoader {
|
|
|
1878
1903
|
if (handler)
|
|
1879
1904
|
handler(emitData);
|
|
1880
1905
|
if (data && typeof data.channel === 'string') {
|
|
1881
|
-
const channel =
|
|
1906
|
+
const channel = qualifyChannel(name, data.channel);
|
|
1882
1907
|
import('@portel/photon-core')
|
|
1883
1908
|
.then(({ getBroker }) => {
|
|
1884
1909
|
getBroker()
|
|
@@ -2129,12 +2154,28 @@ export class PhotonLoader {
|
|
|
2129
2154
|
return explicitScopes;
|
|
2130
2155
|
return [`${tool.name}:${tool.readOnlyHint ? 'read' : 'write'}`];
|
|
2131
2156
|
}
|
|
2157
|
+
/**
|
|
2158
|
+
* Drop circuit-breaker state for every instance/tool of a photon.
|
|
2159
|
+
* Called on hot reload so the reloaded code starts with closed circuits
|
|
2160
|
+
* and long-running daemons don't accumulate entries for retired versions.
|
|
2161
|
+
*/
|
|
2162
|
+
clearCircuitState(photonName) {
|
|
2163
|
+
const prefix = `${photonName}:`;
|
|
2164
|
+
for (const key of this.circuitHealthTracker.keys()) {
|
|
2165
|
+
if (key.startsWith(prefix))
|
|
2166
|
+
this.circuitHealthTracker.delete(key);
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2132
2169
|
/**
|
|
2133
2170
|
* Reload a Photon MCP file (for hot reload)
|
|
2134
2171
|
*/
|
|
2135
2172
|
async reloadFile(filePath, options) {
|
|
2136
2173
|
// Invalidate the cache for this file
|
|
2137
2174
|
const absolutePath = path.resolve(filePath);
|
|
2175
|
+
this.clearCircuitState(path
|
|
2176
|
+
.basename(absolutePath)
|
|
2177
|
+
.replace(/\.photon\.(ts|js|mjs)$/, '')
|
|
2178
|
+
.replace(/\.(ts|js|mjs)$/, ''));
|
|
2138
2179
|
if (absolutePath.endsWith('.ts')) {
|
|
2139
2180
|
// Clear the compiled cache
|
|
2140
2181
|
const tsContent = await readText(absolutePath);
|
|
@@ -2807,9 +2848,7 @@ export class PhotonLoader {
|
|
|
2807
2848
|
this.log(` ⚠️ Skipping stub dependency: ${dep.name} (module failed to load)`);
|
|
2808
2849
|
return undefined;
|
|
2809
2850
|
}
|
|
2810
|
-
const cacheKey = dep.instanceName
|
|
2811
|
-
? `preloaded:${dep.name}::${dep.instanceName}`
|
|
2812
|
-
: `preloaded:${dep.name}`;
|
|
2851
|
+
const cacheKey = preloadedCacheKey(dep.name, dep.instanceName);
|
|
2813
2852
|
if (this.loadedPhotons.has(cacheKey)) {
|
|
2814
2853
|
return this.loadedPhotons.get(cacheKey).instance;
|
|
2815
2854
|
}
|
|
@@ -2823,7 +2862,7 @@ export class PhotonLoader {
|
|
|
2823
2862
|
const resolvedPath = await this.resolvePhotonPath(dep, currentPhotonPath);
|
|
2824
2863
|
await this.materializeSiblingDependencySymlink(dep, currentPhotonPath, resolvedPath);
|
|
2825
2864
|
// Cache key includes instance name to allow multiple instances of the same photon
|
|
2826
|
-
const cacheKey =
|
|
2865
|
+
const cacheKey = instanceCacheKey(resolvedPath, dep.instanceName);
|
|
2827
2866
|
// Check cache
|
|
2828
2867
|
if (this.loadedPhotons.has(cacheKey)) {
|
|
2829
2868
|
return this.loadedPhotons.get(cacheKey).instance;
|
|
@@ -3368,7 +3407,7 @@ Run: photon mcp ${mcpName} --config
|
|
|
3368
3407
|
handlerOverrides.set('circuitBreaker', (config, _state) => {
|
|
3369
3408
|
const tracker = this.circuitHealthTracker;
|
|
3370
3409
|
return async (ctx, next) => {
|
|
3371
|
-
const key =
|
|
3410
|
+
const key = circuitKey(ctx.photon, ctx.instance, ctx.tool);
|
|
3372
3411
|
let circuit = tracker.get(key);
|
|
3373
3412
|
if (!circuit) {
|
|
3374
3413
|
circuit = { failures: 0, state: 'closed', openedAt: 0 };
|
|
@@ -3399,7 +3438,7 @@ Run: photon mcp ${mcpName} --config
|
|
|
3399
3438
|
channel: `${ctx.photon}:circuits`,
|
|
3400
3439
|
event: 'state-change',
|
|
3401
3440
|
data: {
|
|
3402
|
-
key:
|
|
3441
|
+
key: circuitKey(ctx.photon, ctx.instance, ctx.tool),
|
|
3403
3442
|
from,
|
|
3404
3443
|
to,
|
|
3405
3444
|
timestamp: Date.now(),
|
|
@@ -4030,6 +4069,7 @@ Run: photon mcp ${mcpName} --config
|
|
|
4030
4069
|
*/
|
|
4031
4070
|
createInputProvider() {
|
|
4032
4071
|
return async (ask) => {
|
|
4072
|
+
this.progressRenderer.done();
|
|
4033
4073
|
switch (ask.ask) {
|
|
4034
4074
|
case 'text':
|
|
4035
4075
|
case 'password':
|
|
@@ -4037,9 +4077,52 @@ Run: photon mcp ${mcpName} --config
|
|
|
4037
4077
|
case 'confirm':
|
|
4038
4078
|
return await elicitConfirm(ask.message);
|
|
4039
4079
|
case 'select': {
|
|
4040
|
-
const options = (ask.options || []).map((o) =>
|
|
4041
|
-
|
|
4042
|
-
|
|
4080
|
+
const options = (ask.options || []).map((o) => {
|
|
4081
|
+
if (typeof o === 'string')
|
|
4082
|
+
return { value: o, label: o };
|
|
4083
|
+
return { value: o.value ?? o.label, label: o.label };
|
|
4084
|
+
});
|
|
4085
|
+
// Print choices clearly as a numbered list
|
|
4086
|
+
let msg = `${ask.message}\n`;
|
|
4087
|
+
options.forEach((opt, idx) => {
|
|
4088
|
+
msg += ` [${idx + 1}] ${opt.label}\n`;
|
|
4089
|
+
});
|
|
4090
|
+
msg += ask.multi
|
|
4091
|
+
? `Select option(s) (comma-separated numbers or names): `
|
|
4092
|
+
: `Select an option (number or name): `;
|
|
4093
|
+
const result = await elicitPrompt(msg);
|
|
4094
|
+
if (!result)
|
|
4095
|
+
return ask.multi ? [] : null;
|
|
4096
|
+
// Parse and match the user selection
|
|
4097
|
+
if (ask.multi) {
|
|
4098
|
+
const parts = result.split(',').map((s) => s.trim().toLowerCase());
|
|
4099
|
+
const selected = [];
|
|
4100
|
+
for (const part of parts) {
|
|
4101
|
+
const idx = parseInt(part, 10) - 1;
|
|
4102
|
+
if (idx >= 0 && idx < options.length) {
|
|
4103
|
+
selected.push(options[idx].value);
|
|
4104
|
+
}
|
|
4105
|
+
else {
|
|
4106
|
+
const match = options.find((o) => o.label.toLowerCase() === part ||
|
|
4107
|
+
o.value.toString().toLowerCase() === part ||
|
|
4108
|
+
o.label.toLowerCase().includes(part));
|
|
4109
|
+
if (match)
|
|
4110
|
+
selected.push(match.value);
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
return selected;
|
|
4114
|
+
}
|
|
4115
|
+
else {
|
|
4116
|
+
const part = result.trim().toLowerCase();
|
|
4117
|
+
const idx = parseInt(part, 10) - 1;
|
|
4118
|
+
if (idx >= 0 && idx < options.length) {
|
|
4119
|
+
return options[idx].value;
|
|
4120
|
+
}
|
|
4121
|
+
const match = options.find((o) => o.label.toLowerCase() === part ||
|
|
4122
|
+
o.value.toString().toLowerCase() === part ||
|
|
4123
|
+
o.label.toLowerCase().includes(part));
|
|
4124
|
+
return match ? match.value : result;
|
|
4125
|
+
}
|
|
4043
4126
|
}
|
|
4044
4127
|
case 'number': {
|
|
4045
4128
|
const result = await elicitPrompt(ask.message, ask.default?.toString());
|
|
@@ -4483,24 +4566,32 @@ Run: photon mcp ${mcpName} --config
|
|
|
4483
4566
|
/**
|
|
4484
4567
|
* Inject Photon path helpers for plain classes that use them without extending Photon.
|
|
4485
4568
|
*/
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4569
|
+
// Always inject; never gate on source regexes. Regex detection misses
|
|
4570
|
+
// TS-cast call shapes like `(this as any).storage(...)` and silently
|
|
4571
|
+
// leaves the helper undefined — the same blind spot that caused the
|
|
4572
|
+
// memory-injection data-loss bug. Every helper is a lazy closure (zero
|
|
4573
|
+
// cost unless called) and user-defined methods always win.
|
|
4574
|
+
injectPathHelpers(instance) {
|
|
4575
|
+
if (typeof instance.storage !== 'function') {
|
|
4576
|
+
// Mirror Photon.storage() in photon-core base.ts exactly: documented
|
|
4577
|
+
// contract is the data dir (getPhotonDataDir), never next to source.
|
|
4578
|
+
// The previous source-adjacent resolution was copied from assets()
|
|
4579
|
+
// (where source-adjacent is correct) and contradicted every doc.
|
|
4580
|
+
const storageBaseDir = this.baseDir;
|
|
4491
4581
|
instance.storage = (subpath) => {
|
|
4492
4582
|
if (!instance._photonFilePath || typeof instance._photonFilePath !== 'string') {
|
|
4493
4583
|
throw new Error('storage() requires _photonFilePath to be set by the runtime loader. ' +
|
|
4494
4584
|
'Ensure this photon is loaded through the standard runtime.');
|
|
4495
4585
|
}
|
|
4496
|
-
const
|
|
4497
|
-
|
|
4498
|
-
const
|
|
4586
|
+
const name = (typeof instance._photonName === 'string' && instance._photonName) ||
|
|
4587
|
+
path.basename(instance._photonFilePath).replace(/\.photon\.(ts|js)$/, '');
|
|
4588
|
+
const ns = (typeof instance._photonNamespace === 'string' && instance._photonNamespace) || 'local';
|
|
4589
|
+
const target = path.join(getPhotonDataDir(ns, name, storageBaseDir), subpath);
|
|
4499
4590
|
mkdirSync(target, { recursive: true });
|
|
4500
4591
|
return target;
|
|
4501
4592
|
};
|
|
4502
4593
|
}
|
|
4503
|
-
if (
|
|
4594
|
+
if (typeof instance.assets !== 'function') {
|
|
4504
4595
|
instance.assets = (subpath, options) => {
|
|
4505
4596
|
const normalized = typeof options === 'boolean' ? { load: options } : (options ?? {});
|
|
4506
4597
|
if (!instance._photonFilePath || typeof instance._photonFilePath !== 'string') {
|
|
@@ -4523,7 +4614,7 @@ Run: photon mcp ${mcpName} --config
|
|
|
4523
4614
|
return readFileSync(assetPath, normalized.encoding ?? 'utf-8');
|
|
4524
4615
|
};
|
|
4525
4616
|
}
|
|
4526
|
-
if (
|
|
4617
|
+
if (typeof instance.assetUrl !== 'function') {
|
|
4527
4618
|
instance.assetUrl = (subpath) => {
|
|
4528
4619
|
const name = (typeof instance._photonName === 'string' && instance._photonName
|
|
4529
4620
|
? instance._photonName
|