@objectstack/runtime 6.5.1 → 6.6.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/dist/index.cjs +276 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -1
- package/dist/index.d.ts +59 -1
- package/dist/index.js +279 -18
- package/dist/index.js.map +1 -1
- package/package.json +18 -18
package/dist/index.d.cts
CHANGED
|
@@ -71,6 +71,20 @@ declare class Runtime {
|
|
|
71
71
|
getKernel(): ObjectKernel;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the ObjectStack home directory used to store cwd-independent
|
|
76
|
+
* runtime data (default sqlite database, downloaded marketplace apps,
|
|
77
|
+
* installed plugin cache).
|
|
78
|
+
*
|
|
79
|
+
* Resolution order:
|
|
80
|
+
* 1. `OS_HOME` env var (absolute path; `~` expanded)
|
|
81
|
+
* 2. `~/.objectstack` (cross-platform user-home default)
|
|
82
|
+
*
|
|
83
|
+
* The directory is created lazily by callers that actually write to it
|
|
84
|
+
* (e.g. the sqlite driver's `mkdirSync(...)`); this helper does not
|
|
85
|
+
* touch the filesystem.
|
|
86
|
+
*/
|
|
87
|
+
declare function resolveObjectStackHome(): string;
|
|
74
88
|
declare const StandaloneStackConfigSchema: z.ZodObject<{
|
|
75
89
|
databaseUrl: z.ZodOptional<z.ZodString>;
|
|
76
90
|
databaseAuthToken: z.ZodOptional<z.ZodString>;
|
|
@@ -820,6 +834,30 @@ interface KernelManagerConfig {
|
|
|
820
834
|
warn?: (...a: any[]) => void;
|
|
821
835
|
error?: (...a: any[]) => void;
|
|
822
836
|
};
|
|
837
|
+
/**
|
|
838
|
+
* Optional upstream-change detector. When set, every cache hit older
|
|
839
|
+
* than `staleCheckIntervalMs` triggers this probe before returning the
|
|
840
|
+
* cached kernel. Returning `true` evicts the kernel and forces a
|
|
841
|
+
* rebuild, so changes to the control-plane state that don't reach
|
|
842
|
+
* this process via push (marketplace installs, artifact republish,
|
|
843
|
+
* etc.) become visible without waiting for the LRU TTL to expire.
|
|
844
|
+
*
|
|
845
|
+
* The probe should be cheap (single small GET). Errors thrown here
|
|
846
|
+
* are caught and treated as "still fresh" so a brief upstream
|
|
847
|
+
* outage doesn't churn every cached kernel — the worst case is
|
|
848
|
+
* stale-by-`ttlMs`, which is what we had before adding the probe.
|
|
849
|
+
*
|
|
850
|
+
* `builtAtMs` is the kernel's `createdAt` time so the probe can
|
|
851
|
+
* compare against an upstream "last changed at" timestamp.
|
|
852
|
+
*/
|
|
853
|
+
freshnessProbe?: (environmentId: string, builtAtMs: number) => Promise<boolean>;
|
|
854
|
+
/**
|
|
855
|
+
* Minimum gap between successive freshness probes for the same env.
|
|
856
|
+
* Defaults to 10 seconds — enough to avoid hammering the control
|
|
857
|
+
* plane on tight render loops while still keeping the user's
|
|
858
|
+
* post-install refresh perceived as immediate.
|
|
859
|
+
*/
|
|
860
|
+
staleCheckIntervalMs?: number;
|
|
823
861
|
}
|
|
824
862
|
/**
|
|
825
863
|
* LRU + TTL cache of per-project {@link ObjectKernel} instances.
|
|
@@ -837,6 +875,8 @@ declare class KernelManager {
|
|
|
837
875
|
private readonly logger;
|
|
838
876
|
private readonly cache;
|
|
839
877
|
private readonly pending;
|
|
878
|
+
private readonly freshnessProbe?;
|
|
879
|
+
private readonly staleCheckIntervalMs;
|
|
840
880
|
constructor(config: KernelManagerConfig);
|
|
841
881
|
/** Returns the currently cached environmentIds (ordered by insertion). */
|
|
842
882
|
keys(): string[];
|
|
@@ -1716,6 +1756,24 @@ declare class ArtifactApiClient {
|
|
|
1716
1756
|
commitId: string;
|
|
1717
1757
|
publishedAt?: string | null;
|
|
1718
1758
|
} | null>;
|
|
1759
|
+
/**
|
|
1760
|
+
* Cheap freshness probe — returns the env's `last_published_at`
|
|
1761
|
+
* (and best-effort current commit) without rebuilding the artifact.
|
|
1762
|
+
* Used by `KernelManager` on cache hits to detect when a per-env
|
|
1763
|
+
* kernel has been invalidated by an upstream change (marketplace
|
|
1764
|
+
* install/uninstall, artifact publish) so it can be rebuilt
|
|
1765
|
+
* without waiting for the 15-minute LRU TTL to expire.
|
|
1766
|
+
*
|
|
1767
|
+
* Returns `null` on definitive 404 / unknown env. Errors propagate
|
|
1768
|
+
* (caller decides whether to treat unreachable cloud as fresh or
|
|
1769
|
+
* stale — typically fresh, so a brief outage doesn't churn every
|
|
1770
|
+
* cached kernel).
|
|
1771
|
+
*/
|
|
1772
|
+
getFreshness(environmentId: string): Promise<{
|
|
1773
|
+
environmentId: string;
|
|
1774
|
+
lastPublishedAt: string | null;
|
|
1775
|
+
commitId: string | null;
|
|
1776
|
+
} | null>;
|
|
1719
1777
|
/** Drop cached entries for a project (and any matching hostname). */
|
|
1720
1778
|
invalidate(environmentId: string): void;
|
|
1721
1779
|
/** Drop everything. Used on shutdown / hot-reload. */
|
|
@@ -2521,4 +2579,4 @@ declare function actionBodyRunnerFactory(runner: ScriptRunner, opts: FactoryOpti
|
|
|
2521
2579
|
timeoutMs?: number;
|
|
2522
2580
|
}) => ((actionCtx: any) => Promise<unknown>) | undefined;
|
|
2523
2581
|
|
|
2524
|
-
export { AppPlugin, ArtifactApiClient, type ArtifactApiClientConfig, ArtifactEnvironmentRegistry, type ArtifactEnvironmentRegistryConfig, ArtifactKernelFactory, type ArtifactKernelFactoryConfig, AuthProxyPlugin, type BackfillPlatformSsoClientsOptions, DEFAULT_CLOUD_URL, DEFAULT_RATE_LIMITS, type DefaultHostConfigOptions, type DefaultHostConfigResult, type DispatcherPluginConfig, DriverPlugin, type EnvironmentArtifactResponse, type EnvironmentDriverRegistry, type EnvironmentKernelFactory, type EnvironmentRuntimeConfig, FileArtifactApiClient, type FileArtifactApiClientConfig, HttpDispatcher, type HttpDispatcherResult, type HttpProtocolContext, HttpServer, KernelManager, type KernelManagerConfig, type LoadArtifactBundleOptions, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, MiddlewareManager, type ObjectOSStackConfig, type ObjectOSStackResult, ObservabilityServicePlugin, type ObservabilityServicePluginOptions, PLATFORM_SSO_PROVIDER_ID, QuickJSScriptRunner, type QuickJSScriptRunnerOptions, type RateLimitBucketConfig, type RateLimitDecision, type RateLimitDefaults, type RateLimitStore, RateLimiter, type ResolvedHostname, Runtime, type RuntimeConfig, RuntimeConfigPlugin, type RuntimeConfigPluginConfig, SYSTEM_ENVIRONMENT_ID, SandboxError, type ScriptContext, type ScriptOrigin, type ScriptResult, type ScriptRunOptions, type ScriptRunner, type SecurityHeadersOptions, SeedLoaderService, type SeedPlatformSsoClientOptions, type StandaloneStackConfig, type StandaloneStackResult, type SystemEnvironmentPluginConfig, type TraceContext, UnimplementedScriptRunner, actionBodyRunnerFactory, backfillPlatformSsoClients, buildPlatformSsoRedirectUri, buildSecurityHeaders, collectBundleActions, collectBundleFunctions, collectBundleHooks, createDefaultHostConfig, createDispatcherPlugin, createObjectOSStack, createStandaloneStack, createSystemEnvironmentPlugin, derivePlatformSsoClientId, derivePlatformSsoClientSecret, extractRequestId, formatTraceparent, generateRequestId, hookBodyRunnerFactory, isHttpUrl, loadArtifactBundle, mergeRuntimeModule, parseTraceparent, readArtifactSource, resolveCloudUrl, resolveDefaultArtifactPath, resolveErrorReporter, resolveMetrics, resolveRequestId, seedPlatformSsoClient };
|
|
2582
|
+
export { AppPlugin, ArtifactApiClient, type ArtifactApiClientConfig, ArtifactEnvironmentRegistry, type ArtifactEnvironmentRegistryConfig, ArtifactKernelFactory, type ArtifactKernelFactoryConfig, AuthProxyPlugin, type BackfillPlatformSsoClientsOptions, DEFAULT_CLOUD_URL, DEFAULT_RATE_LIMITS, type DefaultHostConfigOptions, type DefaultHostConfigResult, type DispatcherPluginConfig, DriverPlugin, type EnvironmentArtifactResponse, type EnvironmentDriverRegistry, type EnvironmentKernelFactory, type EnvironmentRuntimeConfig, FileArtifactApiClient, type FileArtifactApiClientConfig, HttpDispatcher, type HttpDispatcherResult, type HttpProtocolContext, HttpServer, KernelManager, type KernelManagerConfig, type LoadArtifactBundleOptions, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, MiddlewareManager, type ObjectOSStackConfig, type ObjectOSStackResult, ObservabilityServicePlugin, type ObservabilityServicePluginOptions, PLATFORM_SSO_PROVIDER_ID, QuickJSScriptRunner, type QuickJSScriptRunnerOptions, type RateLimitBucketConfig, type RateLimitDecision, type RateLimitDefaults, type RateLimitStore, RateLimiter, type ResolvedHostname, Runtime, type RuntimeConfig, RuntimeConfigPlugin, type RuntimeConfigPluginConfig, SYSTEM_ENVIRONMENT_ID, SandboxError, type ScriptContext, type ScriptOrigin, type ScriptResult, type ScriptRunOptions, type ScriptRunner, type SecurityHeadersOptions, SeedLoaderService, type SeedPlatformSsoClientOptions, type StandaloneStackConfig, type StandaloneStackResult, type SystemEnvironmentPluginConfig, type TraceContext, UnimplementedScriptRunner, actionBodyRunnerFactory, backfillPlatformSsoClients, buildPlatformSsoRedirectUri, buildSecurityHeaders, collectBundleActions, collectBundleFunctions, collectBundleHooks, createDefaultHostConfig, createDispatcherPlugin, createObjectOSStack, createStandaloneStack, createSystemEnvironmentPlugin, derivePlatformSsoClientId, derivePlatformSsoClientSecret, extractRequestId, formatTraceparent, generateRequestId, hookBodyRunnerFactory, isHttpUrl, loadArtifactBundle, mergeRuntimeModule, parseTraceparent, readArtifactSource, resolveCloudUrl, resolveDefaultArtifactPath, resolveErrorReporter, resolveMetrics, resolveObjectStackHome, resolveRequestId, seedPlatformSsoClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -71,6 +71,20 @@ declare class Runtime {
|
|
|
71
71
|
getKernel(): ObjectKernel;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the ObjectStack home directory used to store cwd-independent
|
|
76
|
+
* runtime data (default sqlite database, downloaded marketplace apps,
|
|
77
|
+
* installed plugin cache).
|
|
78
|
+
*
|
|
79
|
+
* Resolution order:
|
|
80
|
+
* 1. `OS_HOME` env var (absolute path; `~` expanded)
|
|
81
|
+
* 2. `~/.objectstack` (cross-platform user-home default)
|
|
82
|
+
*
|
|
83
|
+
* The directory is created lazily by callers that actually write to it
|
|
84
|
+
* (e.g. the sqlite driver's `mkdirSync(...)`); this helper does not
|
|
85
|
+
* touch the filesystem.
|
|
86
|
+
*/
|
|
87
|
+
declare function resolveObjectStackHome(): string;
|
|
74
88
|
declare const StandaloneStackConfigSchema: z.ZodObject<{
|
|
75
89
|
databaseUrl: z.ZodOptional<z.ZodString>;
|
|
76
90
|
databaseAuthToken: z.ZodOptional<z.ZodString>;
|
|
@@ -820,6 +834,30 @@ interface KernelManagerConfig {
|
|
|
820
834
|
warn?: (...a: any[]) => void;
|
|
821
835
|
error?: (...a: any[]) => void;
|
|
822
836
|
};
|
|
837
|
+
/**
|
|
838
|
+
* Optional upstream-change detector. When set, every cache hit older
|
|
839
|
+
* than `staleCheckIntervalMs` triggers this probe before returning the
|
|
840
|
+
* cached kernel. Returning `true` evicts the kernel and forces a
|
|
841
|
+
* rebuild, so changes to the control-plane state that don't reach
|
|
842
|
+
* this process via push (marketplace installs, artifact republish,
|
|
843
|
+
* etc.) become visible without waiting for the LRU TTL to expire.
|
|
844
|
+
*
|
|
845
|
+
* The probe should be cheap (single small GET). Errors thrown here
|
|
846
|
+
* are caught and treated as "still fresh" so a brief upstream
|
|
847
|
+
* outage doesn't churn every cached kernel — the worst case is
|
|
848
|
+
* stale-by-`ttlMs`, which is what we had before adding the probe.
|
|
849
|
+
*
|
|
850
|
+
* `builtAtMs` is the kernel's `createdAt` time so the probe can
|
|
851
|
+
* compare against an upstream "last changed at" timestamp.
|
|
852
|
+
*/
|
|
853
|
+
freshnessProbe?: (environmentId: string, builtAtMs: number) => Promise<boolean>;
|
|
854
|
+
/**
|
|
855
|
+
* Minimum gap between successive freshness probes for the same env.
|
|
856
|
+
* Defaults to 10 seconds — enough to avoid hammering the control
|
|
857
|
+
* plane on tight render loops while still keeping the user's
|
|
858
|
+
* post-install refresh perceived as immediate.
|
|
859
|
+
*/
|
|
860
|
+
staleCheckIntervalMs?: number;
|
|
823
861
|
}
|
|
824
862
|
/**
|
|
825
863
|
* LRU + TTL cache of per-project {@link ObjectKernel} instances.
|
|
@@ -837,6 +875,8 @@ declare class KernelManager {
|
|
|
837
875
|
private readonly logger;
|
|
838
876
|
private readonly cache;
|
|
839
877
|
private readonly pending;
|
|
878
|
+
private readonly freshnessProbe?;
|
|
879
|
+
private readonly staleCheckIntervalMs;
|
|
840
880
|
constructor(config: KernelManagerConfig);
|
|
841
881
|
/** Returns the currently cached environmentIds (ordered by insertion). */
|
|
842
882
|
keys(): string[];
|
|
@@ -1716,6 +1756,24 @@ declare class ArtifactApiClient {
|
|
|
1716
1756
|
commitId: string;
|
|
1717
1757
|
publishedAt?: string | null;
|
|
1718
1758
|
} | null>;
|
|
1759
|
+
/**
|
|
1760
|
+
* Cheap freshness probe — returns the env's `last_published_at`
|
|
1761
|
+
* (and best-effort current commit) without rebuilding the artifact.
|
|
1762
|
+
* Used by `KernelManager` on cache hits to detect when a per-env
|
|
1763
|
+
* kernel has been invalidated by an upstream change (marketplace
|
|
1764
|
+
* install/uninstall, artifact publish) so it can be rebuilt
|
|
1765
|
+
* without waiting for the 15-minute LRU TTL to expire.
|
|
1766
|
+
*
|
|
1767
|
+
* Returns `null` on definitive 404 / unknown env. Errors propagate
|
|
1768
|
+
* (caller decides whether to treat unreachable cloud as fresh or
|
|
1769
|
+
* stale — typically fresh, so a brief outage doesn't churn every
|
|
1770
|
+
* cached kernel).
|
|
1771
|
+
*/
|
|
1772
|
+
getFreshness(environmentId: string): Promise<{
|
|
1773
|
+
environmentId: string;
|
|
1774
|
+
lastPublishedAt: string | null;
|
|
1775
|
+
commitId: string | null;
|
|
1776
|
+
} | null>;
|
|
1719
1777
|
/** Drop cached entries for a project (and any matching hostname). */
|
|
1720
1778
|
invalidate(environmentId: string): void;
|
|
1721
1779
|
/** Drop everything. Used on shutdown / hot-reload. */
|
|
@@ -2521,4 +2579,4 @@ declare function actionBodyRunnerFactory(runner: ScriptRunner, opts: FactoryOpti
|
|
|
2521
2579
|
timeoutMs?: number;
|
|
2522
2580
|
}) => ((actionCtx: any) => Promise<unknown>) | undefined;
|
|
2523
2581
|
|
|
2524
|
-
export { AppPlugin, ArtifactApiClient, type ArtifactApiClientConfig, ArtifactEnvironmentRegistry, type ArtifactEnvironmentRegistryConfig, ArtifactKernelFactory, type ArtifactKernelFactoryConfig, AuthProxyPlugin, type BackfillPlatformSsoClientsOptions, DEFAULT_CLOUD_URL, DEFAULT_RATE_LIMITS, type DefaultHostConfigOptions, type DefaultHostConfigResult, type DispatcherPluginConfig, DriverPlugin, type EnvironmentArtifactResponse, type EnvironmentDriverRegistry, type EnvironmentKernelFactory, type EnvironmentRuntimeConfig, FileArtifactApiClient, type FileArtifactApiClientConfig, HttpDispatcher, type HttpDispatcherResult, type HttpProtocolContext, HttpServer, KernelManager, type KernelManagerConfig, type LoadArtifactBundleOptions, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, MiddlewareManager, type ObjectOSStackConfig, type ObjectOSStackResult, ObservabilityServicePlugin, type ObservabilityServicePluginOptions, PLATFORM_SSO_PROVIDER_ID, QuickJSScriptRunner, type QuickJSScriptRunnerOptions, type RateLimitBucketConfig, type RateLimitDecision, type RateLimitDefaults, type RateLimitStore, RateLimiter, type ResolvedHostname, Runtime, type RuntimeConfig, RuntimeConfigPlugin, type RuntimeConfigPluginConfig, SYSTEM_ENVIRONMENT_ID, SandboxError, type ScriptContext, type ScriptOrigin, type ScriptResult, type ScriptRunOptions, type ScriptRunner, type SecurityHeadersOptions, SeedLoaderService, type SeedPlatformSsoClientOptions, type StandaloneStackConfig, type StandaloneStackResult, type SystemEnvironmentPluginConfig, type TraceContext, UnimplementedScriptRunner, actionBodyRunnerFactory, backfillPlatformSsoClients, buildPlatformSsoRedirectUri, buildSecurityHeaders, collectBundleActions, collectBundleFunctions, collectBundleHooks, createDefaultHostConfig, createDispatcherPlugin, createObjectOSStack, createStandaloneStack, createSystemEnvironmentPlugin, derivePlatformSsoClientId, derivePlatformSsoClientSecret, extractRequestId, formatTraceparent, generateRequestId, hookBodyRunnerFactory, isHttpUrl, loadArtifactBundle, mergeRuntimeModule, parseTraceparent, readArtifactSource, resolveCloudUrl, resolveDefaultArtifactPath, resolveErrorReporter, resolveMetrics, resolveRequestId, seedPlatformSsoClient };
|
|
2582
|
+
export { AppPlugin, ArtifactApiClient, type ArtifactApiClientConfig, ArtifactEnvironmentRegistry, type ArtifactEnvironmentRegistryConfig, ArtifactKernelFactory, type ArtifactKernelFactoryConfig, AuthProxyPlugin, type BackfillPlatformSsoClientsOptions, DEFAULT_CLOUD_URL, DEFAULT_RATE_LIMITS, type DefaultHostConfigOptions, type DefaultHostConfigResult, type DispatcherPluginConfig, DriverPlugin, type EnvironmentArtifactResponse, type EnvironmentDriverRegistry, type EnvironmentKernelFactory, type EnvironmentRuntimeConfig, FileArtifactApiClient, type FileArtifactApiClientConfig, HttpDispatcher, type HttpDispatcherResult, type HttpProtocolContext, HttpServer, KernelManager, type KernelManagerConfig, type LoadArtifactBundleOptions, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, MiddlewareManager, type ObjectOSStackConfig, type ObjectOSStackResult, ObservabilityServicePlugin, type ObservabilityServicePluginOptions, PLATFORM_SSO_PROVIDER_ID, QuickJSScriptRunner, type QuickJSScriptRunnerOptions, type RateLimitBucketConfig, type RateLimitDecision, type RateLimitDefaults, type RateLimitStore, RateLimiter, type ResolvedHostname, Runtime, type RuntimeConfig, RuntimeConfigPlugin, type RuntimeConfigPluginConfig, SYSTEM_ENVIRONMENT_ID, SandboxError, type ScriptContext, type ScriptOrigin, type ScriptResult, type ScriptRunOptions, type ScriptRunner, type SecurityHeadersOptions, SeedLoaderService, type SeedPlatformSsoClientOptions, type StandaloneStackConfig, type StandaloneStackResult, type SystemEnvironmentPluginConfig, type TraceContext, UnimplementedScriptRunner, actionBodyRunnerFactory, backfillPlatformSsoClients, buildPlatformSsoRedirectUri, buildSecurityHeaders, collectBundleActions, collectBundleFunctions, collectBundleHooks, createDefaultHostConfig, createDispatcherPlugin, createObjectOSStack, createStandaloneStack, createSystemEnvironmentPlugin, derivePlatformSsoClientId, derivePlatformSsoClientSecret, extractRequestId, formatTraceparent, generateRequestId, hookBodyRunnerFactory, isHttpUrl, loadArtifactBundle, mergeRuntimeModule, parseTraceparent, readArtifactSource, resolveCloudUrl, resolveDefaultArtifactPath, resolveErrorReporter, resolveMetrics, resolveObjectStackHome, resolveRequestId, seedPlatformSsoClient };
|
package/dist/index.js
CHANGED
|
@@ -2107,7 +2107,16 @@ var Runtime = class {
|
|
|
2107
2107
|
init_load_artifact_bundle();
|
|
2108
2108
|
import { resolve as resolvePath2 } from "path";
|
|
2109
2109
|
import { mkdirSync } from "fs";
|
|
2110
|
+
import { homedir } from "os";
|
|
2110
2111
|
import { z } from "zod";
|
|
2112
|
+
function resolveObjectStackHome() {
|
|
2113
|
+
const raw = process.env.OS_HOME?.trim();
|
|
2114
|
+
if (raw && raw.length > 0) {
|
|
2115
|
+
if (raw.startsWith("~")) return resolvePath2(homedir(), raw.slice(1).replace(/^[/\\]/, ""));
|
|
2116
|
+
return resolvePath2(raw);
|
|
2117
|
+
}
|
|
2118
|
+
return resolvePath2(homedir(), ".objectstack");
|
|
2119
|
+
}
|
|
2111
2120
|
var StandaloneStackConfigSchema = z.object({
|
|
2112
2121
|
databaseUrl: z.string().optional(),
|
|
2113
2122
|
databaseAuthToken: z.string().optional(),
|
|
@@ -2138,7 +2147,7 @@ async function createStandaloneStack(config) {
|
|
|
2138
2147
|
const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
|
|
2139
2148
|
const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? resolvePath2(cwd, "dist/objectstack.json");
|
|
2140
2149
|
const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : resolvePath2(cwd, artifactPathInput);
|
|
2141
|
-
const dbUrl = cfg.databaseUrl ?? process.env.OS_DATABASE_URL?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? `file:${resolvePath2(
|
|
2150
|
+
const dbUrl = cfg.databaseUrl ?? process.env.OS_DATABASE_URL?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? `file:${resolvePath2(resolveObjectStackHome(), "data/standalone.db")}`;
|
|
2142
2151
|
const dbAuthToken = cfg.databaseAuthToken ?? process.env.OS_DATABASE_AUTH_TOKEN?.trim() ?? process.env.TURSO_AUTH_TOKEN?.trim();
|
|
2143
2152
|
const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
|
|
2144
2153
|
const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
|
|
@@ -2248,7 +2257,7 @@ async function createStandaloneStack(config) {
|
|
|
2248
2257
|
|
|
2249
2258
|
// src/default-host.ts
|
|
2250
2259
|
import { resolve as resolvePath3 } from "path";
|
|
2251
|
-
import { existsSync } from "fs";
|
|
2260
|
+
import { existsSync, mkdirSync as mkdirSync2, writeFileSync } from "fs";
|
|
2252
2261
|
init_load_artifact_bundle();
|
|
2253
2262
|
function resolveDefaultArtifactPath(explicitPath, cwd = process.cwd()) {
|
|
2254
2263
|
const candidate = explicitPath ?? process.env.OS_ARTIFACT_PATH ?? resolvePath3(cwd, "dist/objectstack.json");
|
|
@@ -2258,12 +2267,42 @@ function resolveDefaultArtifactPath(explicitPath, cwd = process.cwd()) {
|
|
|
2258
2267
|
}
|
|
2259
2268
|
async function createDefaultHostConfig(options = {}) {
|
|
2260
2269
|
const { requireArtifact = true, ...standaloneOpts } = options;
|
|
2261
|
-
|
|
2270
|
+
let resolvedArtifact = resolveDefaultArtifactPath(standaloneOpts.artifactPath);
|
|
2262
2271
|
if (!resolvedArtifact && requireArtifact) {
|
|
2263
2272
|
throw new Error(
|
|
2264
2273
|
"[createDefaultHostConfig] No artifact source available. Set OS_ARTIFACT_PATH (file path or http(s):// URL), place the artifact at <cwd>/dist/objectstack.json, or pass `{ artifactPath: ... }` explicitly. To boot an empty kernel anyway, pass `{ requireArtifact: false }`."
|
|
2265
2274
|
);
|
|
2266
2275
|
}
|
|
2276
|
+
if (!resolvedArtifact && !requireArtifact) {
|
|
2277
|
+
const home = resolveObjectStackHome();
|
|
2278
|
+
const stubPath = resolvePath3(home, "dist/objectstack.json");
|
|
2279
|
+
if (!existsSync(stubPath)) {
|
|
2280
|
+
mkdirSync2(resolvePath3(stubPath, ".."), { recursive: true });
|
|
2281
|
+
writeFileSync(
|
|
2282
|
+
stubPath,
|
|
2283
|
+
JSON.stringify(
|
|
2284
|
+
{
|
|
2285
|
+
manifest: {
|
|
2286
|
+
id: "com.objectstack.empty",
|
|
2287
|
+
name: "empty",
|
|
2288
|
+
version: "0.0.0",
|
|
2289
|
+
type: "app",
|
|
2290
|
+
description: "Empty starter kernel \u2014 install apps via the Studio marketplace."
|
|
2291
|
+
},
|
|
2292
|
+
objects: [],
|
|
2293
|
+
views: [],
|
|
2294
|
+
apps: [],
|
|
2295
|
+
flows: [],
|
|
2296
|
+
requires: []
|
|
2297
|
+
},
|
|
2298
|
+
null,
|
|
2299
|
+
2
|
|
2300
|
+
),
|
|
2301
|
+
"utf8"
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
resolvedArtifact = stubPath;
|
|
2305
|
+
}
|
|
2267
2306
|
return createStandaloneStack({
|
|
2268
2307
|
...standaloneOpts,
|
|
2269
2308
|
artifactPath: resolvedArtifact
|
|
@@ -6821,6 +6860,8 @@ var KernelManager = class {
|
|
|
6821
6860
|
this.maxSize = config.maxSize ?? 32;
|
|
6822
6861
|
this.ttlMs = config.ttlMs ?? 15 * 60 * 1e3;
|
|
6823
6862
|
this.logger = config.logger ?? console;
|
|
6863
|
+
this.freshnessProbe = config.freshnessProbe;
|
|
6864
|
+
this.staleCheckIntervalMs = config.staleCheckIntervalMs ?? 1e4;
|
|
6824
6865
|
}
|
|
6825
6866
|
/** Returns the currently cached environmentIds (ordered by insertion). */
|
|
6826
6867
|
keys() {
|
|
@@ -6843,8 +6884,31 @@ var KernelManager = class {
|
|
|
6843
6884
|
if (this.ttlMs > 0 && Date.now() - existing.lastAccess > this.ttlMs) {
|
|
6844
6885
|
await this.evict(environmentId);
|
|
6845
6886
|
} else {
|
|
6846
|
-
|
|
6847
|
-
|
|
6887
|
+
if (this.freshnessProbe) {
|
|
6888
|
+
const now = Date.now();
|
|
6889
|
+
if (now - existing.lastStaleCheckAt >= this.staleCheckIntervalMs) {
|
|
6890
|
+
existing.lastStaleCheckAt = now;
|
|
6891
|
+
let stale = false;
|
|
6892
|
+
try {
|
|
6893
|
+
stale = await this.freshnessProbe(environmentId, existing.createdAt);
|
|
6894
|
+
} catch (err) {
|
|
6895
|
+
this.logger.warn?.("[KernelManager] freshness probe failed", { environmentId, err });
|
|
6896
|
+
}
|
|
6897
|
+
if (stale) {
|
|
6898
|
+
this.logger.info?.("[KernelManager] kernel evicted by freshness probe", { environmentId });
|
|
6899
|
+
await this.evict(environmentId);
|
|
6900
|
+
} else {
|
|
6901
|
+
existing.lastAccess = Date.now();
|
|
6902
|
+
return existing.kernel;
|
|
6903
|
+
}
|
|
6904
|
+
} else {
|
|
6905
|
+
existing.lastAccess = Date.now();
|
|
6906
|
+
return existing.kernel;
|
|
6907
|
+
}
|
|
6908
|
+
} else {
|
|
6909
|
+
existing.lastAccess = Date.now();
|
|
6910
|
+
return existing.kernel;
|
|
6911
|
+
}
|
|
6848
6912
|
}
|
|
6849
6913
|
}
|
|
6850
6914
|
const inflight = this.pending.get(environmentId);
|
|
@@ -6852,7 +6916,7 @@ var KernelManager = class {
|
|
|
6852
6916
|
const promise = (async () => {
|
|
6853
6917
|
const kernel = await this.factory.create(environmentId);
|
|
6854
6918
|
const now = Date.now();
|
|
6855
|
-
this.cache.set(environmentId, { kernel, createdAt: now, lastAccess: now });
|
|
6919
|
+
this.cache.set(environmentId, { kernel, createdAt: now, lastAccess: now, lastStaleCheckAt: now });
|
|
6856
6920
|
await this.enforceMaxSize();
|
|
6857
6921
|
return kernel;
|
|
6858
6922
|
})();
|
|
@@ -7020,6 +7084,30 @@ var ArtifactApiClient = class {
|
|
|
7020
7084
|
if (!found?.headCommitId) return null;
|
|
7021
7085
|
return { commitId: String(found.headCommitId), publishedAt: found.headPublishedAt ?? null };
|
|
7022
7086
|
}
|
|
7087
|
+
/**
|
|
7088
|
+
* Cheap freshness probe — returns the env's `last_published_at`
|
|
7089
|
+
* (and best-effort current commit) without rebuilding the artifact.
|
|
7090
|
+
* Used by `KernelManager` on cache hits to detect when a per-env
|
|
7091
|
+
* kernel has been invalidated by an upstream change (marketplace
|
|
7092
|
+
* install/uninstall, artifact publish) so it can be rebuilt
|
|
7093
|
+
* without waiting for the 15-minute LRU TTL to expire.
|
|
7094
|
+
*
|
|
7095
|
+
* Returns `null` on definitive 404 / unknown env. Errors propagate
|
|
7096
|
+
* (caller decides whether to treat unreachable cloud as fresh or
|
|
7097
|
+
* stale — typically fresh, so a brief outage doesn't churn every
|
|
7098
|
+
* cached kernel).
|
|
7099
|
+
*/
|
|
7100
|
+
async getFreshness(environmentId) {
|
|
7101
|
+
const url = `${this.base}/api/v1/cloud/environments/${encodeURIComponent(environmentId)}/freshness`;
|
|
7102
|
+
const res = await this.request(url);
|
|
7103
|
+
if (res === null) return null;
|
|
7104
|
+
const body = res.success === false ? null : res.data ?? res;
|
|
7105
|
+
if (!body || typeof body !== "object") return null;
|
|
7106
|
+
const envId = typeof body.environmentId === "string" ? body.environmentId : environmentId;
|
|
7107
|
+
const lastPublishedAt = typeof body.lastPublishedAt === "string" ? body.lastPublishedAt : null;
|
|
7108
|
+
const commitId = typeof body.commitId === "string" ? body.commitId : null;
|
|
7109
|
+
return { environmentId: envId, lastPublishedAt, commitId };
|
|
7110
|
+
}
|
|
7023
7111
|
/** Drop cached entries for a project (and any matching hostname). */
|
|
7024
7112
|
invalidate(environmentId) {
|
|
7025
7113
|
this.artifactCache.delete(environmentId);
|
|
@@ -7771,7 +7859,30 @@ var ArtifactKernelFactory = class {
|
|
|
7771
7859
|
};
|
|
7772
7860
|
|
|
7773
7861
|
// src/cloud/auth-proxy-plugin.ts
|
|
7862
|
+
import { createHmac as createHmac3, randomUUID as randomUUID2 } from "crypto";
|
|
7774
7863
|
var AUTH_PREFIX = "/api/v1/auth";
|
|
7864
|
+
function signSessionCookieValue(rawToken, secret) {
|
|
7865
|
+
const signature = createHmac3("sha256", secret).update(rawToken).digest("base64");
|
|
7866
|
+
return encodeURIComponent(`${rawToken}.${signature}`);
|
|
7867
|
+
}
|
|
7868
|
+
function buildSetCookieHeader(name, encodedValue, attrs, maxAgeSec) {
|
|
7869
|
+
const parts = [`${name}=${encodedValue}`];
|
|
7870
|
+
const a = attrs ?? {};
|
|
7871
|
+
if (a.path) parts.push(`Path=${a.path}`);
|
|
7872
|
+
else parts.push("Path=/");
|
|
7873
|
+
if (Number.isFinite(maxAgeSec) && maxAgeSec > 0) parts.push(`Max-Age=${Math.floor(maxAgeSec)}`);
|
|
7874
|
+
if (a.domain) parts.push(`Domain=${a.domain}`);
|
|
7875
|
+
if (a.sameSite) {
|
|
7876
|
+
const ss = String(a.sameSite);
|
|
7877
|
+
parts.push(`SameSite=${ss.charAt(0).toUpperCase() + ss.slice(1)}`);
|
|
7878
|
+
} else {
|
|
7879
|
+
parts.push("SameSite=Lax");
|
|
7880
|
+
}
|
|
7881
|
+
if (a.secure) parts.push("Secure");
|
|
7882
|
+
if (a.httpOnly !== false) parts.push("HttpOnly");
|
|
7883
|
+
if (a.partitioned) parts.push("Partitioned");
|
|
7884
|
+
return parts.join("; ");
|
|
7885
|
+
}
|
|
7775
7886
|
function pickHandler(svc) {
|
|
7776
7887
|
if (!svc) return void 0;
|
|
7777
7888
|
if (typeof svc.handleRequest === "function") return svc.handleRequest.bind(svc);
|
|
@@ -7865,6 +7976,115 @@ var AuthProxyPlugin = class {
|
|
|
7865
7976
|
return c.json({ hasOwner: true });
|
|
7866
7977
|
}
|
|
7867
7978
|
}
|
|
7979
|
+
if (c.req.method === "POST" && subPath === "sso-handoff-issue") {
|
|
7980
|
+
try {
|
|
7981
|
+
const expected = (process.env.OS_CLOUD_API_KEY ?? "").trim();
|
|
7982
|
+
if (!expected) {
|
|
7983
|
+
return c.json({ error: "sso_handoff_disabled", reason: "OS_CLOUD_API_KEY unset on env runtime" }, 503);
|
|
7984
|
+
}
|
|
7985
|
+
const authz = c.req.header("authorization") ?? "";
|
|
7986
|
+
const provided = authz.toLowerCase().startsWith("bearer ") ? authz.slice(7).trim() : "";
|
|
7987
|
+
if (!provided || provided !== expected) {
|
|
7988
|
+
return c.json({ error: "unauthorized" }, 401);
|
|
7989
|
+
}
|
|
7990
|
+
if (typeof authSvc?.getAuthContext !== "function") {
|
|
7991
|
+
return c.json({ error: "auth_service_unavailable" }, 503);
|
|
7992
|
+
}
|
|
7993
|
+
const handoffAuthCtx = await authSvc.getAuthContext();
|
|
7994
|
+
const internal = handoffAuthCtx?.internalAdapter;
|
|
7995
|
+
if (!internal?.createVerificationValue) {
|
|
7996
|
+
return c.json({ error: "verification_api_unavailable" }, 503);
|
|
7997
|
+
}
|
|
7998
|
+
let body = {};
|
|
7999
|
+
try {
|
|
8000
|
+
body = await c.req.json();
|
|
8001
|
+
} catch {
|
|
8002
|
+
body = {};
|
|
8003
|
+
}
|
|
8004
|
+
const email = String(body?.email ?? "").toLowerCase().trim();
|
|
8005
|
+
if (!email) return c.json({ error: "email_required" }, 400);
|
|
8006
|
+
const name = body?.name == null ? null : String(body.name);
|
|
8007
|
+
const by = body?.by == null ? "service" : String(body.by);
|
|
8008
|
+
const envIdInBody = body?.envId == null ? null : String(body.envId);
|
|
8009
|
+
const handoff = randomUUID2().replace(/-/g, "") + randomUUID2().replace(/-/g, "");
|
|
8010
|
+
const ttlSec = 60;
|
|
8011
|
+
const expiresAt = new Date(Date.now() + ttlSec * 1e3);
|
|
8012
|
+
await internal.createVerificationValue({
|
|
8013
|
+
identifier: `sso-handoff:${handoff}`,
|
|
8014
|
+
value: JSON.stringify({ email, name, by, envId: envIdInBody ?? environmentId }),
|
|
8015
|
+
expiresAt
|
|
8016
|
+
});
|
|
8017
|
+
return c.json({
|
|
8018
|
+
token: handoff,
|
|
8019
|
+
expiresAt: expiresAt.toISOString(),
|
|
8020
|
+
ttlSec
|
|
8021
|
+
});
|
|
8022
|
+
} catch (err) {
|
|
8023
|
+
ctx.logger?.error?.("[AuthProxyPlugin] sso-handoff-issue failed", err instanceof Error ? err : new Error(String(err)));
|
|
8024
|
+
return c.json({ error: "sso_handoff_issue_failed", message: String(err?.message ?? err) }, 500);
|
|
8025
|
+
}
|
|
8026
|
+
}
|
|
8027
|
+
if (c.req.method === "GET" && subPath === "sso-exchange") {
|
|
8028
|
+
try {
|
|
8029
|
+
const token = (url.searchParams.get("token") ?? "").trim();
|
|
8030
|
+
const nextRaw = url.searchParams.get("next") ?? "/";
|
|
8031
|
+
const next = nextRaw.startsWith("/") ? nextRaw : "/";
|
|
8032
|
+
if (!token) return c.text("missing token", 400);
|
|
8033
|
+
if (typeof authSvc?.getAuthContext !== "function") {
|
|
8034
|
+
return c.text("auth service unavailable", 503);
|
|
8035
|
+
}
|
|
8036
|
+
const authCtx = await authSvc.getAuthContext();
|
|
8037
|
+
const internal = authCtx?.internalAdapter;
|
|
8038
|
+
if (!internal?.consumeVerificationValue) {
|
|
8039
|
+
return c.text("verification API unavailable", 503);
|
|
8040
|
+
}
|
|
8041
|
+
const consumed = await internal.consumeVerificationValue(`sso-handoff:${token}`);
|
|
8042
|
+
if (!consumed) return c.text("invalid or expired token", 401);
|
|
8043
|
+
const expiresAt = consumed?.expiresAt ? new Date(consumed.expiresAt).getTime() : 0;
|
|
8044
|
+
if (!expiresAt || expiresAt < Date.now()) return c.text("expired token", 401);
|
|
8045
|
+
let payload = {};
|
|
8046
|
+
try {
|
|
8047
|
+
payload = JSON.parse(String(consumed.value));
|
|
8048
|
+
} catch {
|
|
8049
|
+
payload = { email: String(consumed.value) };
|
|
8050
|
+
}
|
|
8051
|
+
const email = String(payload.email ?? "").toLowerCase().trim();
|
|
8052
|
+
if (!email) return c.text("handoff missing email", 400);
|
|
8053
|
+
const found = await internal.findUserByEmail(email, { includeAccounts: true });
|
|
8054
|
+
let userId = found?.user?.id;
|
|
8055
|
+
let hasCredentialAccount = (found?.accounts ?? []).some((a) => a.providerId === "credential" && a.password);
|
|
8056
|
+
if (!userId) {
|
|
8057
|
+
const created = await internal.createUser({
|
|
8058
|
+
email,
|
|
8059
|
+
name: payload.name ?? email,
|
|
8060
|
+
emailVerified: true
|
|
8061
|
+
});
|
|
8062
|
+
userId = created?.id;
|
|
8063
|
+
hasCredentialAccount = false;
|
|
8064
|
+
}
|
|
8065
|
+
if (!userId) return c.text("failed to provision user", 500);
|
|
8066
|
+
const session = await internal.createSession(userId, false);
|
|
8067
|
+
const rawToken = session?.token;
|
|
8068
|
+
const sessionExpiresAt = session?.expiresAt ? new Date(session.expiresAt) : new Date(Date.now() + 7 * 24 * 3600 * 1e3);
|
|
8069
|
+
if (!rawToken) return c.text("failed to mint session", 500);
|
|
8070
|
+
const secret = authCtx?.secret ?? "";
|
|
8071
|
+
if (!secret) return c.text("auth secret unavailable", 503);
|
|
8072
|
+
const cookieName = authCtx?.authCookies?.sessionToken?.name ?? "better-auth.session_token";
|
|
8073
|
+
const cookieAttrs = authCtx?.authCookies?.sessionToken?.attributes ?? {};
|
|
8074
|
+
const encoded = signSessionCookieValue(rawToken, secret);
|
|
8075
|
+
const maxAgeSec = Math.max(60, Math.floor((sessionExpiresAt.getTime() - Date.now()) / 1e3));
|
|
8076
|
+
const setCookie = buildSetCookieHeader(cookieName, encoded, cookieAttrs, maxAgeSec);
|
|
8077
|
+
const finalNext = hasCredentialAccount ? next : `/_console/system/profile?recovery_needed=true&next=${encodeURIComponent(next)}`;
|
|
8078
|
+
const headers = new Headers();
|
|
8079
|
+
headers.set("Set-Cookie", setCookie);
|
|
8080
|
+
headers.set("Location", finalNext);
|
|
8081
|
+
headers.set("Cache-Control", "no-store");
|
|
8082
|
+
return new Response(null, { status: 302, headers });
|
|
8083
|
+
} catch (err) {
|
|
8084
|
+
ctx.logger?.error?.("[AuthProxyPlugin] sso-exchange failed", err instanceof Error ? err : new Error(String(err)));
|
|
8085
|
+
return c.text(`sso-exchange failed: ${err?.message ?? String(err)}`, 500);
|
|
8086
|
+
}
|
|
8087
|
+
}
|
|
7868
8088
|
const fn = await resolveAuthHandler(authSvc);
|
|
7869
8089
|
if (!fn) {
|
|
7870
8090
|
return c.json({ error: "auth_service_unavailable", environmentId }, 503);
|
|
@@ -8047,20 +8267,46 @@ var RuntimeConfigPlugin = class {
|
|
|
8047
8267
|
return;
|
|
8048
8268
|
}
|
|
8049
8269
|
const rawApp = httpServer.getRawApp();
|
|
8050
|
-
const
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8270
|
+
const features = {
|
|
8271
|
+
installLocal: this.installLocal,
|
|
8272
|
+
marketplace: true
|
|
8273
|
+
};
|
|
8274
|
+
let envRegistry = null;
|
|
8275
|
+
try {
|
|
8276
|
+
envRegistry = ctx.getService("env-registry");
|
|
8277
|
+
} catch {
|
|
8278
|
+
}
|
|
8279
|
+
const handler = async (c) => {
|
|
8280
|
+
const rawHost = c.req.header("host") ?? "";
|
|
8281
|
+
const host = rawHost.split(":")[0].toLowerCase().trim();
|
|
8282
|
+
let defaultEnvironmentId;
|
|
8283
|
+
let defaultOrgId;
|
|
8284
|
+
let resolvedSingleEnv = this.singleEnvironment;
|
|
8285
|
+
if (envRegistry && host && typeof envRegistry.resolveHostname === "function") {
|
|
8286
|
+
try {
|
|
8287
|
+
const resolved = await envRegistry.resolveHostname(host);
|
|
8288
|
+
if (resolved?.environmentId) {
|
|
8289
|
+
defaultEnvironmentId = resolved.environmentId;
|
|
8290
|
+
if (resolved.organizationId) defaultOrgId = String(resolved.organizationId);
|
|
8291
|
+
resolvedSingleEnv = true;
|
|
8292
|
+
}
|
|
8293
|
+
} catch {
|
|
8294
|
+
}
|
|
8056
8295
|
}
|
|
8296
|
+
return c.json({
|
|
8297
|
+
cloudUrl: this.cloudUrl,
|
|
8298
|
+
singleEnvironment: resolvedSingleEnv,
|
|
8299
|
+
defaultOrgId,
|
|
8300
|
+
defaultEnvironmentId,
|
|
8301
|
+
features
|
|
8302
|
+
});
|
|
8057
8303
|
};
|
|
8058
|
-
const handler = (c) => c.json(payload);
|
|
8059
8304
|
rawApp.get("/api/v1/runtime/config", handler);
|
|
8060
8305
|
rawApp.get("/api/v1/studio/runtime-config", handler);
|
|
8061
8306
|
ctx.logger?.info?.("[RuntimeConfigPlugin] mounted /api/v1/runtime/config", {
|
|
8062
8307
|
cloudUrl: this.cloudUrl || "(empty)",
|
|
8063
|
-
installLocal: this.installLocal
|
|
8308
|
+
installLocal: this.installLocal,
|
|
8309
|
+
perHostEnvResolution: !!envRegistry
|
|
8064
8310
|
});
|
|
8065
8311
|
});
|
|
8066
8312
|
};
|
|
@@ -8261,7 +8507,21 @@ var ObjectOSEnvironmentPlugin = class {
|
|
|
8261
8507
|
factory,
|
|
8262
8508
|
maxSize: this.config.kernelCacheSize,
|
|
8263
8509
|
ttlMs: this.config.kernelTtlMs,
|
|
8264
|
-
logger: ctx.logger
|
|
8510
|
+
logger: ctx.logger,
|
|
8511
|
+
// Only the HTTP client exposes /freshness; file-mode (CLI dev)
|
|
8512
|
+
// has no upstream to probe.
|
|
8513
|
+
freshnessProbe: this.config.controlPlaneUrl === "file" ? void 0 : async (envId, builtAtMs) => {
|
|
8514
|
+
const fresh = await client.getFreshness(envId);
|
|
8515
|
+
if (!fresh) return false;
|
|
8516
|
+
const t = fresh.lastPublishedAt ? Date.parse(fresh.lastPublishedAt) : NaN;
|
|
8517
|
+
if (!Number.isFinite(t)) return false;
|
|
8518
|
+
if (t <= builtAtMs) return false;
|
|
8519
|
+
try {
|
|
8520
|
+
client.invalidate(envId);
|
|
8521
|
+
} catch {
|
|
8522
|
+
}
|
|
8523
|
+
return true;
|
|
8524
|
+
}
|
|
8265
8525
|
});
|
|
8266
8526
|
this.kernelManager = kernelManager;
|
|
8267
8527
|
ctx.registerService("env-registry", envRegistry);
|
|
@@ -8313,7 +8573,7 @@ async function createObjectOSStack(config) {
|
|
|
8313
8573
|
}
|
|
8314
8574
|
|
|
8315
8575
|
// src/cloud/marketplace-install-local-plugin.ts
|
|
8316
|
-
import { existsSync as existsSync2, mkdirSync as
|
|
8576
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
8317
8577
|
import { join, resolve } from "path";
|
|
8318
8578
|
var ROUTE_BASE = "/api/v1/marketplace/install-local";
|
|
8319
8579
|
var DEFAULT_DIR = ".objectstack/installed-packages";
|
|
@@ -8446,8 +8706,8 @@ var MarketplaceInstallLocalPlugin = class {
|
|
|
8446
8706
|
installedBy: userId
|
|
8447
8707
|
};
|
|
8448
8708
|
try {
|
|
8449
|
-
|
|
8450
|
-
|
|
8709
|
+
mkdirSync3(this.storageDir, { recursive: true });
|
|
8710
|
+
writeFileSync2(join(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
|
|
8451
8711
|
} catch (err) {
|
|
8452
8712
|
return c.json({
|
|
8453
8713
|
success: false,
|
|
@@ -8866,6 +9126,7 @@ export {
|
|
|
8866
9126
|
resolveDefaultArtifactPath,
|
|
8867
9127
|
resolveErrorReporter,
|
|
8868
9128
|
resolveMetrics,
|
|
9129
|
+
resolveObjectStackHome,
|
|
8869
9130
|
resolveRequestId,
|
|
8870
9131
|
seedPlatformSsoClient
|
|
8871
9132
|
};
|