@objectstack/runtime 7.7.0 → 7.9.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.d.cts CHANGED
@@ -1959,6 +1959,26 @@ declare class FileArtifactApiClient {
1959
1959
  private defaultLocalSqliteRuntime;
1960
1960
  }
1961
1961
 
1962
+ /**
1963
+ * createObjectOSStack
1964
+ *
1965
+ * ObjectOS pure-runtime stack — no control-plane database, no auth /
1966
+ * security / audit / tenant plugins. The host kernel registers:
1967
+ *
1968
+ * - A minimal engine triplet (ObjectQL + in-memory DriverPlugin +
1969
+ * MetadataPlugin) so CLI auto-injected plugins (Setup, Studio,
1970
+ * Dispatcher, REST) and the runtime can boot. The host kernel itself
1971
+ * never reads or writes business data — every record query is routed
1972
+ * to a per-project kernel built from a remote artifact.
1973
+ * - The `env-registry` and `kernel-manager` services, so the runtime's
1974
+ * HTTP dispatcher can resolve hostnames and dispatch every request
1975
+ * to the matching project kernel.
1976
+ *
1977
+ * Invoked by `createRuntimeStack()` whenever `OS_CLOUD_URL`
1978
+ * (or `config.controlPlaneUrl`) is set. The same plugin shape is returned
1979
+ * as `createCloudStack()` so host configs can swap stacks transparently.
1980
+ */
1981
+
1962
1982
  interface ObjectOSStackConfig {
1963
1983
  /**
1964
1984
  * Control-plane base URL (HTTP) or a sentinel of `'file'` for the
@@ -1992,6 +2012,30 @@ interface ObjectOSStackConfig {
1992
2012
  artifactCacheTtlMs?: number;
1993
2013
  /** API prefix (carried for parity with cloud-stack). Default: /api/v1. */
1994
2014
  apiPrefix?: string;
2015
+ /**
2016
+ * Host-supplied runtime plugins appended to the stack's default plugin
2017
+ * list. This is the official seam for a host (e.g. the ObjectStack Cloud
2018
+ * repo) to add **product/policy** plugins — marketplace install, cloud-
2019
+ * account binding, set-initial-password — to the otherwise-neutral
2020
+ * framework runtime, WITHOUT a framework release and without reaching into
2021
+ * the returned array by hand.
2022
+ *
2023
+ * They are appended last, so they mount their routes after the framework
2024
+ * plugins and can override/augment behaviour (e.g. supply a credentialled
2025
+ * install path that the browse-only MarketplaceProxyPlugin deliberately
2026
+ * does not). See docs/design/cloud-account-binding-marketplace-install.md
2027
+ * (ADR §5.2 — "framework exposes seams; cloud supplies metadata + policy").
2028
+ */
2029
+ extraPlugins?: Plugin[];
2030
+ /**
2031
+ * Capability tokens force-mounted on EVERY per-environment kernel, in
2032
+ * addition to whatever the app artifact declares in `requires`. Merged and
2033
+ * de-duped with `bundle.requires` before the capability loader runs. This
2034
+ * is the host seam for a cloud operator to make a capability ubiquitous
2035
+ * across all tenants without editing each app — e.g. `['ai','aiStudio']`
2036
+ * so every cloud environment supports AI-driven online development.
2037
+ */
2038
+ defaultRequires?: string[];
1995
2039
  }
1996
2040
  interface ObjectOSStackResult {
1997
2041
  plugins: any[];
@@ -2213,6 +2257,14 @@ interface RuntimeConfigPluginConfig {
2213
2257
  controlPlaneUrl?: string;
2214
2258
  /** Override the `features.installLocal` flag. Default: false. */
2215
2259
  installLocal?: boolean;
2260
+ /**
2261
+ * Override the `features.aiStudio` flag — whether the SPA should surface
2262
+ * AI-driven metadata authoring ("online development") affordances. Default:
2263
+ * true (the actual authoring capability is still gated server-side by the
2264
+ * presence of the `metadata_assistant` agent / @objectstack/service-ai-studio
2265
+ * package; set false to force-hide the authoring UI for a tier/deployment).
2266
+ */
2267
+ aiStudio?: boolean;
2216
2268
  /**
2217
2269
  * Report this runtime as a single-environment deployment (CLI
2218
2270
  * `objectstack dev` / `os serve`). Defaults to `false` for
@@ -2234,6 +2286,7 @@ declare class RuntimeConfigPlugin implements Plugin {
2234
2286
  readonly version = "1.0.0";
2235
2287
  private readonly cloudUrl;
2236
2288
  private readonly installLocal;
2289
+ private readonly aiStudio;
2237
2290
  private readonly singleEnvironment;
2238
2291
  private readonly productName;
2239
2292
  private readonly productShortName;
@@ -2365,6 +2418,12 @@ interface ArtifactKernelFactoryConfig {
2365
2418
  * `process.env.OS_AUTH_SECRET` / `AUTH_SECRET` at construction time.
2366
2419
  */
2367
2420
  authBaseSecret?: string;
2421
+ /**
2422
+ * Capability tokens force-mounted on every per-environment kernel, merged
2423
+ * (and de-duped by the loader) with the artifact's own `requires`. Lets a
2424
+ * host make a capability ubiquitous across tenants — e.g. `['ai','aiStudio']`.
2425
+ */
2426
+ defaultRequires?: string[];
2368
2427
  }
2369
2428
  declare class ArtifactKernelFactory implements EnvironmentKernelFactory {
2370
2429
  private readonly client;
@@ -2372,6 +2431,7 @@ declare class ArtifactKernelFactory implements EnvironmentKernelFactory {
2372
2431
  private readonly logger;
2373
2432
  private readonly kernelConfig?;
2374
2433
  private readonly authBaseSecret;
2434
+ private readonly defaultRequires;
2375
2435
  constructor(config: ArtifactKernelFactoryConfig);
2376
2436
  create(environmentId: string): Promise<ObjectKernel>;
2377
2437
  }
package/dist/index.d.ts CHANGED
@@ -1959,6 +1959,26 @@ declare class FileArtifactApiClient {
1959
1959
  private defaultLocalSqliteRuntime;
1960
1960
  }
1961
1961
 
1962
+ /**
1963
+ * createObjectOSStack
1964
+ *
1965
+ * ObjectOS pure-runtime stack — no control-plane database, no auth /
1966
+ * security / audit / tenant plugins. The host kernel registers:
1967
+ *
1968
+ * - A minimal engine triplet (ObjectQL + in-memory DriverPlugin +
1969
+ * MetadataPlugin) so CLI auto-injected plugins (Setup, Studio,
1970
+ * Dispatcher, REST) and the runtime can boot. The host kernel itself
1971
+ * never reads or writes business data — every record query is routed
1972
+ * to a per-project kernel built from a remote artifact.
1973
+ * - The `env-registry` and `kernel-manager` services, so the runtime's
1974
+ * HTTP dispatcher can resolve hostnames and dispatch every request
1975
+ * to the matching project kernel.
1976
+ *
1977
+ * Invoked by `createRuntimeStack()` whenever `OS_CLOUD_URL`
1978
+ * (or `config.controlPlaneUrl`) is set. The same plugin shape is returned
1979
+ * as `createCloudStack()` so host configs can swap stacks transparently.
1980
+ */
1981
+
1962
1982
  interface ObjectOSStackConfig {
1963
1983
  /**
1964
1984
  * Control-plane base URL (HTTP) or a sentinel of `'file'` for the
@@ -1992,6 +2012,30 @@ interface ObjectOSStackConfig {
1992
2012
  artifactCacheTtlMs?: number;
1993
2013
  /** API prefix (carried for parity with cloud-stack). Default: /api/v1. */
1994
2014
  apiPrefix?: string;
2015
+ /**
2016
+ * Host-supplied runtime plugins appended to the stack's default plugin
2017
+ * list. This is the official seam for a host (e.g. the ObjectStack Cloud
2018
+ * repo) to add **product/policy** plugins — marketplace install, cloud-
2019
+ * account binding, set-initial-password — to the otherwise-neutral
2020
+ * framework runtime, WITHOUT a framework release and without reaching into
2021
+ * the returned array by hand.
2022
+ *
2023
+ * They are appended last, so they mount their routes after the framework
2024
+ * plugins and can override/augment behaviour (e.g. supply a credentialled
2025
+ * install path that the browse-only MarketplaceProxyPlugin deliberately
2026
+ * does not). See docs/design/cloud-account-binding-marketplace-install.md
2027
+ * (ADR §5.2 — "framework exposes seams; cloud supplies metadata + policy").
2028
+ */
2029
+ extraPlugins?: Plugin[];
2030
+ /**
2031
+ * Capability tokens force-mounted on EVERY per-environment kernel, in
2032
+ * addition to whatever the app artifact declares in `requires`. Merged and
2033
+ * de-duped with `bundle.requires` before the capability loader runs. This
2034
+ * is the host seam for a cloud operator to make a capability ubiquitous
2035
+ * across all tenants without editing each app — e.g. `['ai','aiStudio']`
2036
+ * so every cloud environment supports AI-driven online development.
2037
+ */
2038
+ defaultRequires?: string[];
1995
2039
  }
1996
2040
  interface ObjectOSStackResult {
1997
2041
  plugins: any[];
@@ -2213,6 +2257,14 @@ interface RuntimeConfigPluginConfig {
2213
2257
  controlPlaneUrl?: string;
2214
2258
  /** Override the `features.installLocal` flag. Default: false. */
2215
2259
  installLocal?: boolean;
2260
+ /**
2261
+ * Override the `features.aiStudio` flag — whether the SPA should surface
2262
+ * AI-driven metadata authoring ("online development") affordances. Default:
2263
+ * true (the actual authoring capability is still gated server-side by the
2264
+ * presence of the `metadata_assistant` agent / @objectstack/service-ai-studio
2265
+ * package; set false to force-hide the authoring UI for a tier/deployment).
2266
+ */
2267
+ aiStudio?: boolean;
2216
2268
  /**
2217
2269
  * Report this runtime as a single-environment deployment (CLI
2218
2270
  * `objectstack dev` / `os serve`). Defaults to `false` for
@@ -2234,6 +2286,7 @@ declare class RuntimeConfigPlugin implements Plugin {
2234
2286
  readonly version = "1.0.0";
2235
2287
  private readonly cloudUrl;
2236
2288
  private readonly installLocal;
2289
+ private readonly aiStudio;
2237
2290
  private readonly singleEnvironment;
2238
2291
  private readonly productName;
2239
2292
  private readonly productShortName;
@@ -2365,6 +2418,12 @@ interface ArtifactKernelFactoryConfig {
2365
2418
  * `process.env.OS_AUTH_SECRET` / `AUTH_SECRET` at construction time.
2366
2419
  */
2367
2420
  authBaseSecret?: string;
2421
+ /**
2422
+ * Capability tokens force-mounted on every per-environment kernel, merged
2423
+ * (and de-duped by the loader) with the artifact's own `requires`. Lets a
2424
+ * host make a capability ubiquitous across tenants — e.g. `['ai','aiStudio']`.
2425
+ */
2426
+ defaultRequires?: string[];
2368
2427
  }
2369
2428
  declare class ArtifactKernelFactory implements EnvironmentKernelFactory {
2370
2429
  private readonly client;
@@ -2372,6 +2431,7 @@ declare class ArtifactKernelFactory implements EnvironmentKernelFactory {
2372
2431
  private readonly logger;
2373
2432
  private readonly kernelConfig?;
2374
2433
  private readonly authBaseSecret;
2434
+ private readonly defaultRequires;
2375
2435
  constructor(config: ArtifactKernelFactoryConfig);
2376
2436
  create(environmentId: string): Promise<ObjectKernel>;
2377
2437
  }
package/dist/index.js CHANGED
@@ -300,6 +300,24 @@ var init_seed_loader = __esm({
300
300
  for (const ref of objectRefs) {
301
301
  const fieldValue = record[ref.field];
302
302
  if (fieldValue === void 0 || fieldValue === null) continue;
303
+ if (typeof fieldValue === "object") {
304
+ const wrapped = fieldValue.externalId;
305
+ const hint = wrapped !== void 0 ? ` Pass the natural key directly: ${ref.field}: ${JSON.stringify(wrapped)}.` : ` Pass the target's ${ref.targetField} value as a plain string.`;
306
+ const error = {
307
+ sourceObject: objectName,
308
+ field: ref.field,
309
+ targetObject: ref.targetObject,
310
+ targetField: ref.targetField,
311
+ attemptedValue: fieldValue,
312
+ recordIndex: i,
313
+ message: `Invalid reference for ${objectName}.${ref.field}: expected a ${ref.targetObject}.${ref.targetField} natural-key string but got an object.${hint}`
314
+ };
315
+ errors.push(error);
316
+ allErrors.push(error);
317
+ this.logger.warn(`[SeedLoader] ${error.message}`, { recordIndex: i });
318
+ record[ref.field] = null;
319
+ continue;
320
+ }
303
321
  if (typeof fieldValue !== "string" || this.looksLikeInternalId(fieldValue)) continue;
304
322
  const targetMap = insertedRecords.get(ref.targetObject);
305
323
  const resolvedId = targetMap?.get(String(fieldValue));
@@ -3496,7 +3514,8 @@ var _HttpDispatcher = class _HttpDispatcher {
3496
3514
  if (protocol && typeof protocol.getMetaItem === "function") {
3497
3515
  try {
3498
3516
  const organizationId = await this.resolveActiveOrganizationId(_context);
3499
- const data = await protocol.getMetaItem({ type: singularType, name, packageId, organizationId });
3517
+ const previewDrafts = query?.preview === "draft";
3518
+ const data = await protocol.getMetaItem({ type: singularType, name, packageId, organizationId, previewDrafts });
3500
3519
  return { handled: true, response: this.success(data) };
3501
3520
  } catch (e) {
3502
3521
  }
@@ -3514,6 +3533,23 @@ var _HttpDispatcher = class _HttpDispatcher {
3514
3533
  return { handled: true, response: this.error(e.message, 404) };
3515
3534
  }
3516
3535
  }
3536
+ if (parts.length === 1 && parts[0] === "_drafts" && (!method || method.toUpperCase() === "GET")) {
3537
+ const protocol = await this.resolveService("protocol");
3538
+ if (protocol && typeof protocol.listDrafts === "function") {
3539
+ try {
3540
+ const organizationId = await this.resolveActiveOrganizationId(_context);
3541
+ const data = await protocol.listDrafts({
3542
+ packageId: query?.packageId || void 0,
3543
+ type: query?.type || void 0,
3544
+ organizationId
3545
+ });
3546
+ return { handled: true, response: this.success(data) };
3547
+ } catch (e) {
3548
+ return { handled: true, response: this.error(e.message, 500) };
3549
+ }
3550
+ }
3551
+ return { handled: true, response: this.error("Draft listing not supported", 501) };
3552
+ }
3517
3553
  if (parts.length === 1) {
3518
3554
  const typeOrName = parts[0];
3519
3555
  const packageId = query?.package || void 0;
@@ -3521,7 +3557,8 @@ var _HttpDispatcher = class _HttpDispatcher {
3521
3557
  if (protocol && typeof protocol.getMetaItems === "function") {
3522
3558
  try {
3523
3559
  const organizationId = await this.resolveActiveOrganizationId(_context);
3524
- const data = await protocol.getMetaItems({ type: typeOrName, packageId, organizationId });
3560
+ const previewDrafts = query?.preview === "draft";
3561
+ const data = await protocol.getMetaItems({ type: typeOrName, packageId, organizationId, previewDrafts });
3525
3562
  if (data && (data.items !== void 0 || Array.isArray(data))) {
3526
3563
  return { handled: true, response: this.success(data) };
3527
3564
  }
@@ -3813,7 +3850,15 @@ var _HttpDispatcher = class _HttpDispatcher {
3813
3850
  return { handled: true, response: this.success({ packages, total: packages.length }) };
3814
3851
  }
3815
3852
  if (parts.length === 0 && m === "POST") {
3816
- const pkg = registry.installPackage(body.manifest || body, body.settings);
3853
+ const manifest = body.manifest || body;
3854
+ let pkg;
3855
+ const protocolSvc = await this.resolveService("protocol").catch(() => null);
3856
+ if (protocolSvc && typeof protocolSvc.installPackage === "function") {
3857
+ const out = await protocolSvc.installPackage({ manifest, settings: body.settings });
3858
+ pkg = out?.package ?? out;
3859
+ } else {
3860
+ pkg = registry.installPackage(manifest, body.settings);
3861
+ }
3817
3862
  const res = this.success(pkg);
3818
3863
  res.status = 201;
3819
3864
  return { handled: true, response: res };
@@ -3849,6 +3894,42 @@ var _HttpDispatcher = class _HttpDispatcher {
3849
3894
  }
3850
3895
  return { handled: true, response: this.error("Metadata service not available", 503) };
3851
3896
  }
3897
+ if (parts.length === 2 && parts[1] === "publish-drafts" && m === "POST") {
3898
+ const id = decodeURIComponent(parts[0]);
3899
+ const protocol = await this.resolveService("protocol");
3900
+ if (protocol && typeof protocol.publishPackageDrafts === "function") {
3901
+ try {
3902
+ const organizationId = await this.resolveActiveOrganizationId(_context);
3903
+ const result = await protocol.publishPackageDrafts({
3904
+ packageId: id,
3905
+ ...organizationId ? { organizationId } : {},
3906
+ ...body?.actor ? { actor: body.actor } : {}
3907
+ });
3908
+ return { handled: true, response: this.success(result) };
3909
+ } catch (e) {
3910
+ return { handled: true, response: this.error(e.message, e.statusCode || 500) };
3911
+ }
3912
+ }
3913
+ return { handled: true, response: this.error("Draft publishing not supported", 501) };
3914
+ }
3915
+ if (parts.length === 2 && parts[1] === "discard-drafts" && m === "POST") {
3916
+ const id = decodeURIComponent(parts[0]);
3917
+ const protocol = await this.resolveService("protocol");
3918
+ if (protocol && typeof protocol.discardPackageDrafts === "function") {
3919
+ try {
3920
+ const organizationId = await this.resolveActiveOrganizationId(_context);
3921
+ const result = await protocol.discardPackageDrafts({
3922
+ packageId: id,
3923
+ ...organizationId ? { organizationId } : {},
3924
+ ...body?.actor ? { actor: body.actor } : {}
3925
+ });
3926
+ return { handled: true, response: this.success(result) };
3927
+ } catch (e) {
3928
+ return { handled: true, response: this.error(e.message, e.statusCode || 500) };
3929
+ }
3930
+ }
3931
+ return { handled: true, response: this.error("Draft discarding not supported", 501) };
3932
+ }
3852
3933
  if (parts.length === 2 && parts[1] === "revert" && m === "POST") {
3853
3934
  const id = decodeURIComponent(parts[0]);
3854
3935
  const metadataService = await this.getService(CoreServiceName.enum.metadata);
@@ -3874,9 +3955,27 @@ var _HttpDispatcher = class _HttpDispatcher {
3874
3955
  }
3875
3956
  if (parts.length === 1 && m === "DELETE") {
3876
3957
  const id = decodeURIComponent(parts[0]);
3877
- const success = registry.uninstallPackage(id);
3878
- if (!success) return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3879
- return { handled: true, response: this.success({ success: true }) };
3958
+ const registryRemoved = registry.uninstallPackage(id);
3959
+ let persisted = void 0;
3960
+ const protocol = await this.resolveService("protocol");
3961
+ if (protocol && typeof protocol.deletePackage === "function") {
3962
+ try {
3963
+ const organizationId = await this.resolveActiveOrganizationId(_context);
3964
+ const keepData = query?.keepData === "true" || query?.keepData === "1";
3965
+ persisted = await protocol.deletePackage({
3966
+ packageId: id,
3967
+ ...organizationId ? { organizationId } : {},
3968
+ ...keepData ? { keepData: true } : {}
3969
+ });
3970
+ } catch (e) {
3971
+ return { handled: true, response: this.error(e.message, e.statusCode || 500) };
3972
+ }
3973
+ }
3974
+ const deletedCount = persisted?.deletedCount ?? 0;
3975
+ if (!registryRemoved && deletedCount === 0) {
3976
+ return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3977
+ }
3978
+ return { handled: true, response: this.success({ success: true, registryRemoved, persisted }) };
3880
3979
  }
3881
3980
  } catch (e) {
3882
3981
  return { handled: true, response: this.error(e.message, e.statusCode || 500) };
@@ -5358,6 +5457,14 @@ function createDispatcherPlugin(config = {}) {
5358
5457
  errorResponse(err, res);
5359
5458
  }
5360
5459
  });
5460
+ server.post(`${prefix}/packages/:id/publish-drafts`, async (req, res) => {
5461
+ try {
5462
+ const result = await dispatcher.handlePackages(`/${req.params.id}/publish-drafts`, "POST", req.body, {}, { request: req });
5463
+ sendResult(result, res);
5464
+ } catch (err) {
5465
+ errorResponse(err, res);
5466
+ }
5467
+ });
5361
5468
  server.post(`${prefix}/packages/:id/revert`, async (req, res) => {
5362
5469
  try {
5363
5470
  const result = await dispatcher.handlePackages(`/${req.params.id}/revert`, "POST", req.body, {}, { request: req });
@@ -6459,6 +6566,16 @@ var CAPABILITY_PROVIDERS = {
6459
6566
  pkg: "@objectstack/service-ai",
6460
6567
  export: "AIServicePlugin"
6461
6568
  },
6569
+ // AI Studio — AI-driven metadata authoring ("online development"). This is
6570
+ // a commercial capability that ships in the private @objectstack/service-ai-studio
6571
+ // package (not part of the open-source framework). The dynamic import below
6572
+ // silently skips when the package isn't installed, so the open-source build
6573
+ // is unaffected; cloud and enterprise installs that ship the package light it
6574
+ // up. Pair with `ai` in `requires` (it attaches via the `ai:ready` hook).
6575
+ aiStudio: {
6576
+ pkg: "@objectstack/service-ai-studio",
6577
+ export: "AIStudioPlugin"
6578
+ },
6462
6579
  analytics: {
6463
6580
  pkg: "@objectstack/service-analytics",
6464
6581
  export: "AnalyticsServicePlugin",
@@ -6785,6 +6902,7 @@ var ArtifactKernelFactory = class {
6785
6902
  this.envRegistry = config.envRegistry;
6786
6903
  this.logger = config.logger ?? console;
6787
6904
  this.kernelConfig = config.kernelConfig;
6905
+ this.defaultRequires = config.defaultRequires ?? [];
6788
6906
  this.authBaseSecret = (config.authBaseSecret ?? readEnvWithDeprecation3("OS_AUTH_SECRET", ["AUTH_SECRET", "BETTER_AUTH_SECRET"]) ?? "").trim();
6789
6907
  }
6790
6908
  async create(environmentId) {
@@ -6951,7 +7069,10 @@ var ArtifactKernelFactory = class {
6951
7069
  });
6952
7070
  }
6953
7071
  const requiresRaw = (Array.isArray(bundle?.requires) ? bundle.requires : null) ?? (Array.isArray(sys?.requires) ? sys.requires : null) ?? [];
6954
- const requires = requiresRaw.filter((x) => typeof x === "string" && x.length > 0);
7072
+ const requires = [
7073
+ ...requiresRaw,
7074
+ ...this.defaultRequires
7075
+ ].filter((x) => typeof x === "string" && x.length > 0);
6955
7076
  if (requires.length > 0) {
6956
7077
  const installed = await loadCapabilities({
6957
7078
  kernel,
@@ -7370,6 +7491,61 @@ var AuthProxyPlugin = class {
7370
7491
  return c.text(`sso-exchange failed: ${err?.message ?? String(err)}`, 500);
7371
7492
  }
7372
7493
  }
7494
+ if (c.req.method === "POST" && subPath === "set-initial-password") {
7495
+ try {
7496
+ let body = {};
7497
+ try {
7498
+ body = await c.req.json();
7499
+ } catch {
7500
+ body = {};
7501
+ }
7502
+ const newPassword = body?.newPassword;
7503
+ if (typeof newPassword !== "string" || newPassword.length === 0) {
7504
+ return c.json({ success: false, error: { code: "invalid_request", message: "newPassword is required" } }, 400);
7505
+ }
7506
+ if (typeof authSvc?.getAuthContext !== "function") {
7507
+ return c.json({ success: false, error: { code: "unavailable", message: "Auth context unavailable" } }, 503);
7508
+ }
7509
+ let userId;
7510
+ try {
7511
+ const api = typeof authSvc.getApi === "function" ? await authSvc.getApi() : null;
7512
+ const session = await api?.getSession?.({ headers: c.req.raw.headers });
7513
+ userId = session?.user?.id ? String(session.user.id) : void 0;
7514
+ } catch {
7515
+ }
7516
+ if (!userId) {
7517
+ return c.json({ success: false, error: { code: "unauthorized", message: "Sign in first" } }, 401);
7518
+ }
7519
+ const setPwCtx = await authSvc.getAuthContext();
7520
+ if (!setPwCtx?.internalAdapter || !setPwCtx?.password) {
7521
+ return c.json({ success: false, error: { code: "unavailable", message: "Auth context unavailable" } }, 503);
7522
+ }
7523
+ const minLen = setPwCtx.password?.config?.minPasswordLength ?? 8;
7524
+ const maxLen = setPwCtx.password?.config?.maxPasswordLength ?? 128;
7525
+ if (newPassword.length < minLen) {
7526
+ return c.json({ success: false, error: { code: "password_too_short", message: `Password must be at least ${minLen} characters` } }, 400);
7527
+ }
7528
+ if (newPassword.length > maxLen) {
7529
+ return c.json({ success: false, error: { code: "password_too_long", message: `Password must be at most ${maxLen} characters` } }, 400);
7530
+ }
7531
+ const accounts = await setPwCtx.internalAdapter.findAccounts(userId);
7532
+ const existingCredential = accounts?.find?.((a) => a.providerId === "credential" && a.password);
7533
+ if (existingCredential) {
7534
+ return c.json({ success: false, error: { code: "credential_account_exists", message: "A local password is already set for this account. Use change-password instead." } }, 409);
7535
+ }
7536
+ const passwordHash = await setPwCtx.password.hash(newPassword);
7537
+ await setPwCtx.internalAdapter.createAccount({
7538
+ userId,
7539
+ providerId: "credential",
7540
+ accountId: userId,
7541
+ password: passwordHash
7542
+ });
7543
+ return c.json({ success: true });
7544
+ } catch (err) {
7545
+ ctx.logger?.error?.("[AuthProxyPlugin] set-initial-password failed", err instanceof Error ? err : new Error(String(err)));
7546
+ return c.json({ success: false, error: { code: "set_password_failed", message: String(err?.message ?? err) } }, 500);
7547
+ }
7548
+ }
7373
7549
  const fn = await resolveAuthHandler(authSvc);
7374
7550
  if (!fn) {
7375
7551
  return c.json({ error: "auth_service_unavailable", environmentId }, 503);
@@ -7555,13 +7731,7 @@ var MarketplaceProxyPlugin = class _MarketplaceProxyPlugin {
7555
7731
  }
7556
7732
  const target = `${cloudUrl}${incomingUrl.pathname}${incomingUrl.search}`;
7557
7733
  if (method !== "GET" && method !== "HEAD") {
7558
- return c.json({
7559
- success: false,
7560
- error: {
7561
- code: "marketplace_method_not_allowed",
7562
- message: `Marketplace proxy only forwards GET/HEAD; install via cloud.`
7563
- }
7564
- }, 405);
7734
+ return next();
7565
7735
  }
7566
7736
  const accept = c.req.header("accept") ?? "application/json";
7567
7737
  const acceptLang = c.req.header("accept-language") ?? "";
@@ -7785,7 +7955,8 @@ var RuntimeConfigPlugin = class {
7785
7955
  const rawApp = httpServer.getRawApp();
7786
7956
  const features = {
7787
7957
  installLocal: this.installLocal,
7788
- marketplace: true
7958
+ marketplace: true,
7959
+ aiStudio: this.aiStudio
7789
7960
  };
7790
7961
  let envRegistry = null;
7791
7962
  try {
@@ -7836,6 +8007,7 @@ var RuntimeConfigPlugin = class {
7836
8007
  };
7837
8008
  this.cloudUrl = config.controlPlaneUrl === "" ? "" : resolveCloudUrl(config.controlPlaneUrl) ?? "";
7838
8009
  this.installLocal = !!config.installLocal;
8010
+ this.aiStudio = config.aiStudio !== false;
7839
8011
  this.singleEnvironment = !!config.singleEnvironment;
7840
8012
  const envName = (typeof process !== "undefined" ? process.env?.OS_PRODUCT_NAME : void 0)?.trim();
7841
8013
  const envShort = (typeof process !== "undefined" ? process.env?.OS_PRODUCT_SHORT_NAME : void 0)?.trim();
@@ -8027,7 +8199,8 @@ var ObjectOSEnvironmentPlugin = class {
8027
8199
  const factory = new ArtifactKernelFactory({
8028
8200
  client,
8029
8201
  envRegistry,
8030
- logger: ctx.logger
8202
+ logger: ctx.logger,
8203
+ defaultRequires: this.config.defaultRequires
8031
8204
  });
8032
8205
  const kernelManager = new KernelManager({
8033
8206
  factory,
@@ -8084,7 +8257,17 @@ async function createObjectOSStack(config) {
8084
8257
  };
8085
8258
  const enginePlugins = await createHostEnginePlugins();
8086
8259
  return {
8087
- plugins: [...enginePlugins, new ObjectOSEnvironmentPlugin(merged), new AuthProxyPlugin(), new MarketplaceProxyPlugin({ controlPlaneUrl: merged.controlPlaneUrl === "file" ? void 0 : merged.controlPlaneUrl }), new RuntimeConfigPlugin({ controlPlaneUrl: merged.controlPlaneUrl === "file" ? void 0 : merged.controlPlaneUrl, installLocal: false })],
8260
+ plugins: [
8261
+ ...enginePlugins,
8262
+ new ObjectOSEnvironmentPlugin(merged),
8263
+ new AuthProxyPlugin(),
8264
+ new MarketplaceProxyPlugin({ controlPlaneUrl: merged.controlPlaneUrl === "file" ? void 0 : merged.controlPlaneUrl }),
8265
+ new RuntimeConfigPlugin({ controlPlaneUrl: merged.controlPlaneUrl === "file" ? void 0 : merged.controlPlaneUrl, installLocal: false }),
8266
+ // Host-supplied product/policy plugins (the official seam — see
8267
+ // ObjectOSStackConfig.extraPlugins). Appended last so they mount
8268
+ // after the framework defaults.
8269
+ ...config.extraPlugins ?? []
8270
+ ],
8088
8271
  api: {
8089
8272
  enableProjectScoping: true,
8090
8273
  projectResolution: "auto",