@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.cjs CHANGED
@@ -1167,9 +1167,12 @@ function buildSandboxApi(engineCtx, ql, errLabel) {
1167
1167
  }
1168
1168
  function buildSandboxContext(engineCtx, ql) {
1169
1169
  const inputSnapshot = unwrapProxyToPlain(engineCtx?.input ?? engineCtx?.doc);
1170
+ const previousRaw = engineCtx?.previous ?? engineCtx?.previousDoc;
1170
1171
  return {
1171
- input: inputSnapshot,
1172
- previous: unwrapProxyToPlain(engineCtx?.previous ?? engineCtx?.previousDoc),
1172
+ input: inputSnapshot ?? {},
1173
+ // Preserve `undefined` for `previous` on insert events so hooks can
1174
+ // reliably distinguish create (`!ctx.previous`) from update/delete.
1175
+ previous: unwrapProxyToPlain(previousRaw),
1173
1176
  user: engineCtx?.user ?? engineCtx?.session?.user,
1174
1177
  session: engineCtx?.session,
1175
1178
  event: typeof engineCtx?.event === "string" ? engineCtx.event : void 0,
@@ -1196,12 +1199,13 @@ function buildActionSandboxContext(actionCtx, ql) {
1196
1199
  };
1197
1200
  }
1198
1201
  function unwrapProxyToPlain(v) {
1199
- if (!v || typeof v !== "object") return {};
1200
- if (Array.isArray(v)) return {};
1202
+ if (v === void 0 || v === null) return void 0;
1203
+ if (typeof v !== "object") return void 0;
1204
+ if (Array.isArray(v)) return void 0;
1201
1205
  try {
1202
1206
  return Object.fromEntries(Object.entries(v));
1203
1207
  } catch {
1204
- return {};
1208
+ return void 0;
1205
1209
  }
1206
1210
  }
1207
1211
  var import_data2;
@@ -1464,7 +1468,7 @@ var init_app_plugin = __esm({
1464
1468
  ctx.logger.error("[AppPlugin] Failed to schedule approval-process registration", err, { appId });
1465
1469
  }
1466
1470
  this.emitCatalogEvent(ctx, "app:registered", sys);
1467
- this.loadTranslations(ctx, appId);
1471
+ await this.loadTranslations(ctx, appId);
1468
1472
  const seedDatasets = [];
1469
1473
  if (Array.isArray(this.bundle.data)) {
1470
1474
  seedDatasets.push(...this.bundle.data);
@@ -1639,7 +1643,7 @@ var init_app_plugin = __esm({
1639
1643
  * Gracefully skips when the i18n service is not registered —
1640
1644
  * this keeps AppPlugin resilient across server/dev/mock environments.
1641
1645
  */
1642
- loadTranslations(ctx, appId) {
1646
+ async loadTranslations(ctx, appId) {
1643
1647
  let i18nService;
1644
1648
  try {
1645
1649
  i18nService = ctx.getService("i18n");
@@ -1655,13 +1659,33 @@ var init_app_plugin = __esm({
1655
1659
  }
1656
1660
  if (!i18nService) {
1657
1661
  if (bundles.length > 0) {
1658
- ctx.logger.warn(
1659
- `[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.`
1660
- );
1662
+ try {
1663
+ const mod = await import("@objectstack/core");
1664
+ const createMemoryI18n = mod.createMemoryI18n;
1665
+ if (typeof createMemoryI18n === "function") {
1666
+ const fallback = createMemoryI18n();
1667
+ ctx.registerService("i18n", fallback);
1668
+ i18nService = fallback;
1669
+ ctx.logger.info(
1670
+ `[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.`
1671
+ );
1672
+ }
1673
+ } catch (err) {
1674
+ ctx.logger.warn(
1675
+ `[i18n] App "${appId}" has ${bundles.length} translation bundle(s) but auto-fallback failed: ${err?.message ?? err}.`
1676
+ );
1677
+ return;
1678
+ }
1679
+ if (!i18nService) {
1680
+ ctx.logger.warn(
1681
+ `[i18n] App "${appId}" has ${bundles.length} translation bundle(s) but no i18n service is registered.`
1682
+ );
1683
+ return;
1684
+ }
1661
1685
  } else {
1662
1686
  ctx.logger.debug("[i18n] No i18n service registered; skipping translation loading", { appId });
1687
+ return;
1663
1688
  }
1664
- return;
1665
1689
  }
1666
1690
  const i18nConfig = this.bundle.i18n || (this.bundle.manifest || this.bundle)?.i18n;
1667
1691
  if (i18nConfig?.defaultLocale && typeof i18nService.setDefaultLocale === "function") {