@objectstack/runtime 12.1.0 → 12.2.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 CHANGED
@@ -901,10 +901,11 @@ function collectBundleFunctions(bundle) {
901
901
  merge(bundle?.manifest?.functions);
902
902
  return out;
903
903
  }
904
- var import_types, AppPlugin;
904
+ var import_core2, import_types, AppPlugin;
905
905
  var init_app_plugin = __esm({
906
906
  "src/app-plugin.ts"() {
907
907
  "use strict";
908
+ import_core2 = require("@objectstack/core");
908
909
  import_types = require("@objectstack/types");
909
910
  init_seed_loader();
910
911
  init_package_state_store();
@@ -917,6 +918,8 @@ var init_app_plugin = __esm({
917
918
  this.empty = false;
918
919
  this.init = async (ctx) => {
919
920
  this.installDefaultHookBodyRunner(ctx);
921
+ this.installDefaultActionBodyRunner(ctx);
922
+ (0, import_core2.wireAuthoredTranslationSync)(ctx);
920
923
  if (this.empty) {
921
924
  ctx.logger.debug("[AppPlugin] empty env \u2014 no app payload, skipping init", {
922
925
  pluginName: this.name
@@ -1479,6 +1482,43 @@ var init_app_plugin = __esm({
1479
1482
  }));
1480
1483
  ctx.logger.info("[AppPlugin] Installed default hook body runner (runtime-authored hooks can execute)");
1481
1484
  }
1485
+ /**
1486
+ * Install the engine's DEFAULT action body runner (`engine.setDefaultActionRunner`).
1487
+ *
1488
+ * The exact action-path parallel of {@link installDefaultHookBodyRunner}
1489
+ * (#2605 item 1): actions authored at runtime (Studio → `action` metadata →
1490
+ * publish) are registered by ObjectQLPlugin's authored-action re-sync,
1491
+ * which lives in `objectql` and therefore has no sandbox of its own. This
1492
+ * boot point hands it the same QuickJS-sandboxed runner that
1493
+ * `defineStack({ actions })` bundles already execute through, so an
1494
+ * authored `body` becomes a real `executeAction` handler instead of a
1495
+ * silent "Action not found".
1496
+ *
1497
+ * `OS_DISABLE_AUTHORED_ACTIONS=1` opts out for deployments that want
1498
+ * runtime-authored (DB-stored, non-code-reviewed) action bodies to stay
1499
+ * inert; code-shipped actions are unaffected (AppPlugin registers those
1500
+ * itself with its own runner).
1501
+ */
1502
+ installDefaultActionBodyRunner(ctx) {
1503
+ if (process.env.OS_DISABLE_AUTHORED_ACTIONS === "1") {
1504
+ ctx.logger.info("[AppPlugin] OS_DISABLE_AUTHORED_ACTIONS=1 \u2014 runtime-authored action bodies will not execute");
1505
+ return;
1506
+ }
1507
+ let ql;
1508
+ try {
1509
+ ql = ctx.getService("objectql");
1510
+ } catch {
1511
+ return;
1512
+ }
1513
+ if (!ql || typeof ql.setDefaultActionRunner !== "function") return;
1514
+ if (ql._defaultActionRunner) return;
1515
+ ql.setDefaultActionRunner(actionBodyRunnerFactory(new QuickJSScriptRunner(), {
1516
+ ql,
1517
+ logger: ctx.logger,
1518
+ appId: "runtime-authored"
1519
+ }));
1520
+ ctx.logger.info("[AppPlugin] Installed default action body runner (runtime-authored actions can execute)");
1521
+ }
1482
1522
  /**
1483
1523
  * Emit a kernel hook so the control-plane `AppCatalogService` can
1484
1524
  * upsert / delete the corresponding `sys_app` row. Silently no-ops
@@ -1793,7 +1833,7 @@ __export(index_exports, {
1793
1833
  NoopMetricsRegistry: () => import_observability.NoopMetricsRegistry,
1794
1834
  OBSERVABILITY_ERRORS_SERVICE: () => import_observability3.OBSERVABILITY_ERRORS_SERVICE,
1795
1835
  OBSERVABILITY_METRICS_SERVICE: () => import_observability3.OBSERVABILITY_METRICS_SERVICE,
1796
- ObjectKernel: () => import_core5.ObjectKernel,
1836
+ ObjectKernel: () => import_core6.ObjectKernel,
1797
1837
  ObservabilityServicePlugin: () => ObservabilityServicePlugin,
1798
1838
  QuickJSScriptRunner: () => QuickJSScriptRunner,
1799
1839
  RUNTIME_METRICS: () => import_observability.RUNTIME_METRICS,
@@ -1835,7 +1875,7 @@ __export(index_exports, {
1835
1875
  resolveRequestId: () => resolveRequestId
1836
1876
  });
1837
1877
  module.exports = __toCommonJS(index_exports);
1838
- var import_core5 = require("@objectstack/core");
1878
+ var import_core6 = require("@objectstack/core");
1839
1879
 
1840
1880
  // src/runtime.ts
1841
1881
  var import_core = require("@objectstack/core");
@@ -2107,7 +2147,7 @@ function safeGet(ctx, name) {
2107
2147
  }
2108
2148
 
2109
2149
  // src/http-dispatcher.ts
2110
- var import_core4 = require("@objectstack/core");
2150
+ var import_core5 = require("@objectstack/core");
2111
2151
  var import_system = require("@objectstack/spec/system");
2112
2152
  var import_shared2 = require("@objectstack/spec/shared");
2113
2153
  init_package_state_store();
@@ -2142,7 +2182,7 @@ function checkApiExposure(def, action) {
2142
2182
  }
2143
2183
 
2144
2184
  // src/security/resolve-execution-context.ts
2145
- var import_core2 = require("@objectstack/core");
2185
+ var import_core3 = require("@objectstack/core");
2146
2186
  function toHeaders(input) {
2147
2187
  if (!input) return new Headers();
2148
2188
  if (typeof Headers !== "undefined" && input instanceof Headers) return input;
@@ -2171,7 +2211,7 @@ async function resolveExecutionContext(opts) {
2171
2211
  return void 0;
2172
2212
  }
2173
2213
  };
2174
- const authz = await (0, import_core2.resolveAuthzContext)({ ql, headers, getSession });
2214
+ const authz = await (0, import_core3.resolveAuthzContext)({ ql, headers, getSession });
2175
2215
  const ctx = {
2176
2216
  roles: authz.roles,
2177
2217
  permissions: authz.permissions,
@@ -2186,7 +2226,7 @@ async function resolveExecutionContext(opts) {
2186
2226
  ctx.org_user_ids = authz.org_user_ids;
2187
2227
  if (authz.userId) {
2188
2228
  const settings = await Promise.resolve(opts.getService("settings")).catch(() => void 0);
2189
- const localization = await (0, import_core2.resolveLocalizationContext)({
2229
+ const localization = await (0, import_core3.resolveLocalizationContext)({
2190
2230
  ql,
2191
2231
  settings,
2192
2232
  tenantId: authz.tenantId,
@@ -2205,7 +2245,7 @@ function isPermissionDeniedError(e) {
2205
2245
  }
2206
2246
 
2207
2247
  // src/security/api-key.ts
2208
- var import_core3 = require("@objectstack/core");
2248
+ var import_core4 = require("@objectstack/core");
2209
2249
 
2210
2250
  // src/http-dispatcher.ts
2211
2251
  function randomUUID() {
@@ -2897,7 +2937,7 @@ var _HttpDispatcher = class _HttpDispatcher {
2897
2937
  if (!ql || typeof ql.insert !== "function") {
2898
2938
  return { handled: true, response: this.error("Data service not available", 503) };
2899
2939
  }
2900
- const generated = (0, import_core3.generateApiKey)();
2940
+ const generated = (0, import_core4.generateApiKey)();
2901
2941
  const row = {
2902
2942
  name,
2903
2943
  key: generated.hash,
@@ -2990,7 +3030,7 @@ var _HttpDispatcher = class _HttpDispatcher {
2990
3030
  */
2991
3031
  async enforceAuthGate(context, cleanPath) {
2992
3032
  try {
2993
- if ((0, import_core4.isAuthGateAllowlisted)(cleanPath)) return null;
3033
+ if ((0, import_core5.isAuthGateAllowlisted)(cleanPath)) return null;
2994
3034
  const authService = await this.resolveService("auth", context.environmentId);
2995
3035
  if (!authService || typeof authService.isAuthGateActive !== "function" || !authService.isAuthGateActive()) {
2996
3036
  return null;
@@ -3012,7 +3052,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3012
3052
  return null;
3013
3053
  }
3014
3054
  const session = await api.getSession({ headers }).catch(() => void 0);
3015
- const gate = (0, import_core4.evaluateAuthGate)(session?.user, cleanPath);
3055
+ const gate = (0, import_core5.evaluateAuthGate)(session?.user, cleanPath);
3016
3056
  if (!gate) return null;
3017
3057
  return this.error(gate.message, 403, { code: gate.code });
3018
3058
  } catch {
@@ -3176,7 +3216,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3176
3216
  return {
3177
3217
  name: "ObjectOS",
3178
3218
  version: "1.0.0",
3179
- environment: (0, import_core4.getEnv)("NODE_ENV", "development"),
3219
+ environment: (0, import_core5.getEnv)("NODE_ENV", "development"),
3180
3220
  routes,
3181
3221
  endpoints: routes,
3182
3222
  // Alias for backward compatibility with some clients
@@ -3681,7 +3721,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3681
3721
  let translations = i18nService.getTranslations(locale);
3682
3722
  if (Object.keys(translations).length === 0) {
3683
3723
  const availableLocales = typeof i18nService.getLocales === "function" ? i18nService.getLocales() : [];
3684
- const resolved = (0, import_core4.resolveLocale)(locale, availableLocales);
3724
+ const resolved = (0, import_core5.resolveLocale)(locale, availableLocales);
3685
3725
  if (resolved && resolved !== locale) {
3686
3726
  translations = i18nService.getTranslations(resolved);
3687
3727
  return { handled: true, response: this.success({ locale: resolved, requestedLocale: locale, translations }) };
@@ -3694,7 +3734,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3694
3734
  let locale = parts[2] ? decodeURIComponent(parts[2]) : query?.locale;
3695
3735
  if (!locale) return { handled: true, response: this.error("Missing locale parameter", 400) };
3696
3736
  const availableLocales = typeof i18nService.getLocales === "function" ? i18nService.getLocales() : [];
3697
- const resolved = (0, import_core4.resolveLocale)(locale, availableLocales);
3737
+ const resolved = (0, import_core5.resolveLocale)(locale, availableLocales);
3698
3738
  if (resolved) locale = resolved;
3699
3739
  if (typeof i18nService.getFieldLabels === "function") {
3700
3740
  const labels2 = i18nService.getFieldLabels(objectName, locale);
@@ -4670,6 +4710,9 @@ var _HttpDispatcher = class _HttpDispatcher {
4670
4710
  } catch {
4671
4711
  }
4672
4712
  if (!aiService) {
4713
+ if (method === "GET" && subPath === "/ai/agents") {
4714
+ return { handled: true, response: { status: 200, body: { agents: [] } } };
4715
+ }
4673
4716
  return {
4674
4717
  handled: true,
4675
4718
  response: {