@objectstack/runtime 4.1.0 → 4.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.js CHANGED
@@ -1173,9 +1173,12 @@ function buildSandboxApi(engineCtx, ql, errLabel) {
1173
1173
  }
1174
1174
  function buildSandboxContext(engineCtx, ql) {
1175
1175
  const inputSnapshot = unwrapProxyToPlain(engineCtx?.input ?? engineCtx?.doc);
1176
+ const previousRaw = engineCtx?.previous ?? engineCtx?.previousDoc;
1176
1177
  return {
1177
- input: inputSnapshot,
1178
- previous: unwrapProxyToPlain(engineCtx?.previous ?? engineCtx?.previousDoc),
1178
+ input: inputSnapshot ?? {},
1179
+ // Preserve `undefined` for `previous` on insert events so hooks can
1180
+ // reliably distinguish create (`!ctx.previous`) from update/delete.
1181
+ previous: unwrapProxyToPlain(previousRaw),
1179
1182
  user: engineCtx?.user ?? engineCtx?.session?.user,
1180
1183
  session: engineCtx?.session,
1181
1184
  event: typeof engineCtx?.event === "string" ? engineCtx.event : void 0,
@@ -1202,12 +1205,13 @@ function buildActionSandboxContext(actionCtx, ql) {
1202
1205
  };
1203
1206
  }
1204
1207
  function unwrapProxyToPlain(v) {
1205
- if (!v || typeof v !== "object") return {};
1206
- if (Array.isArray(v)) return {};
1208
+ if (v === void 0 || v === null) return void 0;
1209
+ if (typeof v !== "object") return void 0;
1210
+ if (Array.isArray(v)) return void 0;
1207
1211
  try {
1208
1212
  return Object.fromEntries(Object.entries(v));
1209
1213
  } catch {
1210
- return {};
1214
+ return void 0;
1211
1215
  }
1212
1216
  }
1213
1217
  var init_body_runner = __esm({
@@ -1468,7 +1472,7 @@ var init_app_plugin = __esm({
1468
1472
  ctx.logger.error("[AppPlugin] Failed to schedule approval-process registration", err, { appId });
1469
1473
  }
1470
1474
  this.emitCatalogEvent(ctx, "app:registered", sys);
1471
- this.loadTranslations(ctx, appId);
1475
+ await this.loadTranslations(ctx, appId);
1472
1476
  const seedDatasets = [];
1473
1477
  if (Array.isArray(this.bundle.data)) {
1474
1478
  seedDatasets.push(...this.bundle.data);
@@ -1643,7 +1647,7 @@ var init_app_plugin = __esm({
1643
1647
  * Gracefully skips when the i18n service is not registered —
1644
1648
  * this keeps AppPlugin resilient across server/dev/mock environments.
1645
1649
  */
1646
- loadTranslations(ctx, appId) {
1650
+ async loadTranslations(ctx, appId) {
1647
1651
  let i18nService;
1648
1652
  try {
1649
1653
  i18nService = ctx.getService("i18n");
@@ -1659,13 +1663,33 @@ var init_app_plugin = __esm({
1659
1663
  }
1660
1664
  if (!i18nService) {
1661
1665
  if (bundles.length > 0) {
1662
- ctx.logger.warn(
1663
- `[i18n] App "${appId}" has ${bundles.length} translation bundle(s) but no i18n service is registered. Translations will not be served via REST API. Register I18nServicePlugin from @objectstack/service-i18n, or use DevPlugin which auto-detects translations and registers the i18n service automatically.`
1664
- );
1666
+ try {
1667
+ const mod = await import("@objectstack/core");
1668
+ const createMemoryI18n = mod.createMemoryI18n;
1669
+ if (typeof createMemoryI18n === "function") {
1670
+ const fallback = createMemoryI18n();
1671
+ ctx.registerService("i18n", fallback);
1672
+ i18nService = fallback;
1673
+ ctx.logger.info(
1674
+ `[i18n] Auto-registered in-memory i18n fallback for "${appId}" (${bundles.length} bundle(s) detected). Install I18nServicePlugin from @objectstack/service-i18n for file-based / production use.`
1675
+ );
1676
+ }
1677
+ } catch (err) {
1678
+ ctx.logger.warn(
1679
+ `[i18n] App "${appId}" has ${bundles.length} translation bundle(s) but auto-fallback failed: ${err?.message ?? err}.`
1680
+ );
1681
+ return;
1682
+ }
1683
+ if (!i18nService) {
1684
+ ctx.logger.warn(
1685
+ `[i18n] App "${appId}" has ${bundles.length} translation bundle(s) but no i18n service is registered.`
1686
+ );
1687
+ return;
1688
+ }
1665
1689
  } else {
1666
1690
  ctx.logger.debug("[i18n] No i18n service registered; skipping translation loading", { appId });
1691
+ return;
1667
1692
  }
1668
- return;
1669
1693
  }
1670
1694
  const i18nConfig = this.bundle.i18n || (this.bundle.manifest || this.bundle)?.i18n;
1671
1695
  if (i18nConfig?.defaultLocale && typeof i18nService.setDefaultLocale === "function") {