@odoo/owl 3.0.0-alpha.22 → 3.0.0-alpha.23

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.
Binary file
package/dist/owl.cjs.js CHANGED
@@ -2002,51 +2002,11 @@ function untrack(fn) {
2002
2002
  // Maps fibers to thrown errors
2003
2003
  const fibersInError = new WeakMap();
2004
2004
  const nodeErrorHandlers = new WeakMap();
2005
- function destroyApp(app, error) {
2006
- try {
2007
- app.destroy();
2008
- }
2009
- catch (e) {
2010
- // mute all errors here because we are in a corrupted state anyway
2011
- }
2012
- const e = Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
2013
- cause: error,
2014
- });
2015
- return e;
2016
- }
2017
- function _handleError(node, error) {
2018
- if (!node) {
2019
- return false;
2020
- }
2021
- const fiber = node.fiber;
2022
- if (fiber) {
2023
- fibersInError.set(fiber, error);
2024
- }
2025
- const errorHandlers = nodeErrorHandlers.get(node);
2026
- if (errorHandlers) {
2027
- let handled = false;
2028
- // execute in the opposite order
2029
- const finalize = () => destroyApp(node.app, error);
2030
- for (let i = errorHandlers.length - 1; i >= 0; i--) {
2031
- try {
2032
- errorHandlers[i](error, finalize);
2033
- handled = true;
2034
- break;
2035
- }
2036
- catch (e) {
2037
- error = e;
2038
- }
2039
- }
2040
- if (handled) {
2041
- return true;
2042
- }
2043
- }
2044
- return _handleError(node.parent, error);
2045
- }
2046
2005
  function handleError(params) {
2047
2006
  let { error } = params;
2048
- const node = "node" in params ? params.node : params.fiber.node;
2007
+ let node = "node" in params ? params.node : params.fiber.node;
2049
2008
  const fiber = "fiber" in params ? params.fiber : node.fiber;
2009
+ const app = node.app;
2050
2010
  if (fiber) {
2051
2011
  // resets the fibers on components if possible. This is important so that
2052
2012
  // new renderings can be properly included in the initial one, if any.
@@ -2058,10 +2018,43 @@ function handleError(params) {
2058
2018
  } while (current);
2059
2019
  fibersInError.set(fiber.root, error);
2060
2020
  }
2061
- const handled = _handleError(node, error);
2062
- if (!handled) {
2063
- throw destroyApp(node.app, error);
2021
+ const finalize = () => {
2022
+ try {
2023
+ app.destroy();
2024
+ }
2025
+ catch (e) {
2026
+ // mute all errors here because we are in a corrupted state anyway
2027
+ }
2028
+ return Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
2029
+ cause: error,
2030
+ });
2031
+ };
2032
+ // Walk up the component tree looking for error handlers
2033
+ while (node) {
2034
+ const nodeFiber = node.fiber;
2035
+ if (nodeFiber) {
2036
+ fibersInError.set(nodeFiber, error);
2037
+ }
2038
+ const errorHandlers = nodeErrorHandlers.get(node);
2039
+ if (errorHandlers) {
2040
+ // execute in the opposite order
2041
+ for (let i = errorHandlers.length - 1; i >= 0; i--) {
2042
+ try {
2043
+ errorHandlers[i](error, finalize);
2044
+ return; // handled
2045
+ }
2046
+ catch (e) {
2047
+ error = e;
2048
+ }
2049
+ }
2050
+ }
2051
+ node = node.parent;
2064
2052
  }
2053
+ // No handler found — create the OwlError, then let the app handle it.
2054
+ // app._handleError is called after error creation, so it doesn't appear
2055
+ // in the error's .stack property.
2056
+ const owlError = finalize();
2057
+ app._handleError(owlError);
2065
2058
  }
2066
2059
 
2067
2060
  function makeChildFiber(node, parent) {
@@ -2197,7 +2190,7 @@ class Fiber {
2197
2190
  this.bdom = node.renderFn();
2198
2191
  }
2199
2192
  catch (e) {
2200
- node.app.handleError({ node, error: e });
2193
+ handleError({ node, error: e });
2201
2194
  }
2202
2195
  setComputation(c);
2203
2196
  root.setCounter(root.counter - 1);
@@ -2267,7 +2260,7 @@ class RootFiber extends Fiber {
2267
2260
  fiber.node.willUnmount = [];
2268
2261
  }
2269
2262
  this.locked = false;
2270
- node.app.handleError({ fiber: current || this, error: e });
2263
+ handleError({ fiber: current || this, error: e });
2271
2264
  }
2272
2265
  }
2273
2266
  setCounter(newValue) {
@@ -2323,7 +2316,7 @@ class MountFiber extends RootFiber {
2323
2316
  }
2324
2317
  }
2325
2318
  catch (e) {
2326
- this.node.app.handleError({ fiber: current, error: e });
2319
+ handleError({ fiber: current, error: e });
2327
2320
  }
2328
2321
  }
2329
2322
  }
@@ -2401,7 +2394,7 @@ class ComponentNode {
2401
2394
  await Promise.all(promises);
2402
2395
  }
2403
2396
  catch (e) {
2404
- this.app.handleError({ node: this, error: e });
2397
+ handleError({ node: this, error: e });
2405
2398
  return;
2406
2399
  }
2407
2400
  if (this.status === 0 /* STATUS.NEW */ && this.fiber === fiber) {
@@ -2491,7 +2484,7 @@ class ComponentNode {
2491
2484
  }
2492
2485
  }
2493
2486
  catch (e) {
2494
- this.app.handleError({ error: e, node: this });
2487
+ handleError({ error: e, node: this });
2495
2488
  }
2496
2489
  }
2497
2490
  for (const computation of this.computations) {
@@ -5674,7 +5667,7 @@ function compile(template, options = {
5674
5667
  }
5675
5668
 
5676
5669
  // do not modify manually. This file is generated by the release script.
5677
- const version = "3.0.0-alpha.22";
5670
+ const version = "3.0.0-alpha.23";
5678
5671
 
5679
5672
  function effect(fn) {
5680
5673
  const computation = createComputation(() => {
@@ -5872,8 +5865,33 @@ class Scheduler {
5872
5865
  node._destroy();
5873
5866
  }
5874
5867
  this.cancelledNodes.clear();
5875
- for (let task of this.tasks) {
5876
- this.processFiber(task);
5868
+ for (let fiber of this.tasks) {
5869
+ if (fiber.root !== fiber) {
5870
+ this.tasks.delete(fiber);
5871
+ continue;
5872
+ }
5873
+ const hasError = fibersInError.has(fiber);
5874
+ if (hasError && fiber.counter !== 0) {
5875
+ this.tasks.delete(fiber);
5876
+ continue;
5877
+ }
5878
+ if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
5879
+ this.tasks.delete(fiber);
5880
+ continue;
5881
+ }
5882
+ if (fiber.counter === 0) {
5883
+ if (!hasError) {
5884
+ fiber.complete();
5885
+ }
5886
+ // at this point, the fiber should have been applied to the DOM, so we can
5887
+ // remove it from the task list. If it is not the case, it means that there
5888
+ // was an error and an error handler triggered a new rendering that recycled
5889
+ // the fiber, so in that case, we actually want to keep the fiber around,
5890
+ // otherwise it will just be ignored.
5891
+ if (fiber.appliedToDom) {
5892
+ this.tasks.delete(fiber);
5893
+ }
5894
+ }
5877
5895
  }
5878
5896
  for (let task of this.tasks) {
5879
5897
  if (task.node.status === 3 /* STATUS.DESTROYED */) {
@@ -5882,34 +5900,6 @@ class Scheduler {
5882
5900
  }
5883
5901
  this.processing = false;
5884
5902
  }
5885
- processFiber(fiber) {
5886
- if (fiber.root !== fiber) {
5887
- this.tasks.delete(fiber);
5888
- return;
5889
- }
5890
- const hasError = fibersInError.has(fiber);
5891
- if (hasError && fiber.counter !== 0) {
5892
- this.tasks.delete(fiber);
5893
- return;
5894
- }
5895
- if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
5896
- this.tasks.delete(fiber);
5897
- return;
5898
- }
5899
- if (fiber.counter === 0) {
5900
- if (!hasError) {
5901
- fiber.complete();
5902
- }
5903
- // at this point, the fiber should have been applied to the DOM, so we can
5904
- // remove it from the task list. If it is not the case, it means that there
5905
- // was an error and an error handler triggered a new rendering that recycled
5906
- // the fiber, so in that case, we actually want to keep the fiber around,
5907
- // otherwise it will just be ignored.
5908
- if (fiber.appliedToDom) {
5909
- this.tasks.delete(fiber);
5910
- }
5911
- }
5912
- }
5913
5903
  }
5914
5904
 
5915
5905
  let hasBeenLogged = false;
@@ -6009,8 +5999,8 @@ class App extends TemplateSet {
6009
5999
  this.scheduler.processTasks();
6010
6000
  apps.delete(this);
6011
6001
  }
6012
- handleError(...args) {
6013
- return handleError(...args);
6002
+ _handleError(error) {
6003
+ throw error;
6014
6004
  }
6015
6005
  }
6016
6006
  async function mount(C, target, config = {}) {
@@ -6068,14 +6058,20 @@ const mainEventHandler = (data, ev, currentTarget) => {
6068
6058
  // hooks
6069
6059
  // -----------------------------------------------------------------------------
6070
6060
  function decorate(node, f, hookName) {
6071
- const result = f.bind(node.component);
6072
6061
  if (node.app.dev) {
6073
- const suffix = f.name ? ` <${f.name}>` : "";
6074
- Reflect.defineProperty(result, "name", {
6075
- value: hookName + suffix,
6076
- });
6062
+ const component = node.component;
6063
+ const componentName = component ? component.constructor.name : "Component";
6064
+ const name = `${componentName}.${hookName}`;
6065
+ // Create a named wrapper so the name appears in stack traces.
6066
+ // V8 uses computed property keys as inferred function names.
6067
+ const wrapper = {
6068
+ [name]() {
6069
+ return f.call(component);
6070
+ },
6071
+ };
6072
+ return wrapper[name];
6077
6073
  }
6078
- return result;
6074
+ return f.bind(node.component);
6079
6075
  }
6080
6076
  function onWillStart(fn) {
6081
6077
  const { node } = getContext("component");
@@ -6333,22 +6329,30 @@ class Registry {
6333
6329
  }
6334
6330
  }
6335
6331
 
6336
- const anyType = function validateAny() { };
6337
- const booleanType = function validateBoolean(context) {
6338
- if (typeof context.value !== "boolean") {
6339
- context.addIssue({ message: "value is not a boolean" });
6340
- }
6341
- };
6342
- const numberType = function validateNumber(context) {
6343
- if (typeof context.value !== "number") {
6344
- context.addIssue({ message: "value is not a number" });
6345
- }
6346
- };
6347
- const stringType = function validateString(context) {
6348
- if (typeof context.value !== "string") {
6349
- context.addIssue({ message: "value is not a string" });
6350
- }
6351
- };
6332
+ function anyType() {
6333
+ return function validateAny() { };
6334
+ }
6335
+ function booleanType() {
6336
+ return function validateBoolean(context) {
6337
+ if (typeof context.value !== "boolean") {
6338
+ context.addIssue({ message: "value is not a boolean" });
6339
+ }
6340
+ };
6341
+ }
6342
+ function numberType() {
6343
+ return function validateNumber(context) {
6344
+ if (typeof context.value !== "number") {
6345
+ context.addIssue({ message: "value is not a number" });
6346
+ }
6347
+ };
6348
+ }
6349
+ function stringType() {
6350
+ return function validateString(context) {
6351
+ if (typeof context.value !== "string") {
6352
+ context.addIssue({ message: "value is not a string" });
6353
+ }
6354
+ };
6355
+ }
6352
6356
  function arrayType(elementType) {
6353
6357
  return function validateArray(context) {
6354
6358
  if (!Array.isArray(context.value)) {
@@ -6539,6 +6543,9 @@ function reactiveValueType(type) {
6539
6543
  }
6540
6544
  };
6541
6545
  }
6546
+ function componentType() {
6547
+ return constructorType(Component);
6548
+ }
6542
6549
  function ref(type) {
6543
6550
  return union([literalType(null), instanceType(type)]);
6544
6551
  }
@@ -6547,6 +6554,7 @@ const types = {
6547
6554
  any: anyType,
6548
6555
  array: arrayType,
6549
6556
  boolean: booleanType,
6557
+ component: componentType,
6550
6558
  constructor: constructorType,
6551
6559
  customValidator: customValidator,
6552
6560
  function: functionType,
@@ -6815,6 +6823,6 @@ exports.whenReady = whenReady;
6815
6823
  exports.xml = xml;
6816
6824
 
6817
6825
 
6818
- __info__.date = '2026-04-08T13:31:02.500Z';
6819
- __info__.hash = '2e9164e';
6826
+ __info__.date = '2026-04-10T07:28:23.029Z';
6827
+ __info__.hash = 'e5e6d92';
6820
6828
  __info__.url = 'https://github.com/odoo/owl';
package/dist/owl.es.js CHANGED
@@ -2000,51 +2000,11 @@ function untrack(fn) {
2000
2000
  // Maps fibers to thrown errors
2001
2001
  const fibersInError = new WeakMap();
2002
2002
  const nodeErrorHandlers = new WeakMap();
2003
- function destroyApp(app, error) {
2004
- try {
2005
- app.destroy();
2006
- }
2007
- catch (e) {
2008
- // mute all errors here because we are in a corrupted state anyway
2009
- }
2010
- const e = Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
2011
- cause: error,
2012
- });
2013
- return e;
2014
- }
2015
- function _handleError(node, error) {
2016
- if (!node) {
2017
- return false;
2018
- }
2019
- const fiber = node.fiber;
2020
- if (fiber) {
2021
- fibersInError.set(fiber, error);
2022
- }
2023
- const errorHandlers = nodeErrorHandlers.get(node);
2024
- if (errorHandlers) {
2025
- let handled = false;
2026
- // execute in the opposite order
2027
- const finalize = () => destroyApp(node.app, error);
2028
- for (let i = errorHandlers.length - 1; i >= 0; i--) {
2029
- try {
2030
- errorHandlers[i](error, finalize);
2031
- handled = true;
2032
- break;
2033
- }
2034
- catch (e) {
2035
- error = e;
2036
- }
2037
- }
2038
- if (handled) {
2039
- return true;
2040
- }
2041
- }
2042
- return _handleError(node.parent, error);
2043
- }
2044
2003
  function handleError(params) {
2045
2004
  let { error } = params;
2046
- const node = "node" in params ? params.node : params.fiber.node;
2005
+ let node = "node" in params ? params.node : params.fiber.node;
2047
2006
  const fiber = "fiber" in params ? params.fiber : node.fiber;
2007
+ const app = node.app;
2048
2008
  if (fiber) {
2049
2009
  // resets the fibers on components if possible. This is important so that
2050
2010
  // new renderings can be properly included in the initial one, if any.
@@ -2056,10 +2016,43 @@ function handleError(params) {
2056
2016
  } while (current);
2057
2017
  fibersInError.set(fiber.root, error);
2058
2018
  }
2059
- const handled = _handleError(node, error);
2060
- if (!handled) {
2061
- throw destroyApp(node.app, error);
2019
+ const finalize = () => {
2020
+ try {
2021
+ app.destroy();
2022
+ }
2023
+ catch (e) {
2024
+ // mute all errors here because we are in a corrupted state anyway
2025
+ }
2026
+ return Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
2027
+ cause: error,
2028
+ });
2029
+ };
2030
+ // Walk up the component tree looking for error handlers
2031
+ while (node) {
2032
+ const nodeFiber = node.fiber;
2033
+ if (nodeFiber) {
2034
+ fibersInError.set(nodeFiber, error);
2035
+ }
2036
+ const errorHandlers = nodeErrorHandlers.get(node);
2037
+ if (errorHandlers) {
2038
+ // execute in the opposite order
2039
+ for (let i = errorHandlers.length - 1; i >= 0; i--) {
2040
+ try {
2041
+ errorHandlers[i](error, finalize);
2042
+ return; // handled
2043
+ }
2044
+ catch (e) {
2045
+ error = e;
2046
+ }
2047
+ }
2048
+ }
2049
+ node = node.parent;
2062
2050
  }
2051
+ // No handler found — create the OwlError, then let the app handle it.
2052
+ // app._handleError is called after error creation, so it doesn't appear
2053
+ // in the error's .stack property.
2054
+ const owlError = finalize();
2055
+ app._handleError(owlError);
2063
2056
  }
2064
2057
 
2065
2058
  function makeChildFiber(node, parent) {
@@ -2195,7 +2188,7 @@ class Fiber {
2195
2188
  this.bdom = node.renderFn();
2196
2189
  }
2197
2190
  catch (e) {
2198
- node.app.handleError({ node, error: e });
2191
+ handleError({ node, error: e });
2199
2192
  }
2200
2193
  setComputation(c);
2201
2194
  root.setCounter(root.counter - 1);
@@ -2265,7 +2258,7 @@ class RootFiber extends Fiber {
2265
2258
  fiber.node.willUnmount = [];
2266
2259
  }
2267
2260
  this.locked = false;
2268
- node.app.handleError({ fiber: current || this, error: e });
2261
+ handleError({ fiber: current || this, error: e });
2269
2262
  }
2270
2263
  }
2271
2264
  setCounter(newValue) {
@@ -2321,7 +2314,7 @@ class MountFiber extends RootFiber {
2321
2314
  }
2322
2315
  }
2323
2316
  catch (e) {
2324
- this.node.app.handleError({ fiber: current, error: e });
2317
+ handleError({ fiber: current, error: e });
2325
2318
  }
2326
2319
  }
2327
2320
  }
@@ -2399,7 +2392,7 @@ class ComponentNode {
2399
2392
  await Promise.all(promises);
2400
2393
  }
2401
2394
  catch (e) {
2402
- this.app.handleError({ node: this, error: e });
2395
+ handleError({ node: this, error: e });
2403
2396
  return;
2404
2397
  }
2405
2398
  if (this.status === 0 /* STATUS.NEW */ && this.fiber === fiber) {
@@ -2489,7 +2482,7 @@ class ComponentNode {
2489
2482
  }
2490
2483
  }
2491
2484
  catch (e) {
2492
- this.app.handleError({ error: e, node: this });
2485
+ handleError({ error: e, node: this });
2493
2486
  }
2494
2487
  }
2495
2488
  for (const computation of this.computations) {
@@ -5672,7 +5665,7 @@ function compile(template, options = {
5672
5665
  }
5673
5666
 
5674
5667
  // do not modify manually. This file is generated by the release script.
5675
- const version = "3.0.0-alpha.22";
5668
+ const version = "3.0.0-alpha.23";
5676
5669
 
5677
5670
  function effect(fn) {
5678
5671
  const computation = createComputation(() => {
@@ -5870,8 +5863,33 @@ class Scheduler {
5870
5863
  node._destroy();
5871
5864
  }
5872
5865
  this.cancelledNodes.clear();
5873
- for (let task of this.tasks) {
5874
- this.processFiber(task);
5866
+ for (let fiber of this.tasks) {
5867
+ if (fiber.root !== fiber) {
5868
+ this.tasks.delete(fiber);
5869
+ continue;
5870
+ }
5871
+ const hasError = fibersInError.has(fiber);
5872
+ if (hasError && fiber.counter !== 0) {
5873
+ this.tasks.delete(fiber);
5874
+ continue;
5875
+ }
5876
+ if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
5877
+ this.tasks.delete(fiber);
5878
+ continue;
5879
+ }
5880
+ if (fiber.counter === 0) {
5881
+ if (!hasError) {
5882
+ fiber.complete();
5883
+ }
5884
+ // at this point, the fiber should have been applied to the DOM, so we can
5885
+ // remove it from the task list. If it is not the case, it means that there
5886
+ // was an error and an error handler triggered a new rendering that recycled
5887
+ // the fiber, so in that case, we actually want to keep the fiber around,
5888
+ // otherwise it will just be ignored.
5889
+ if (fiber.appliedToDom) {
5890
+ this.tasks.delete(fiber);
5891
+ }
5892
+ }
5875
5893
  }
5876
5894
  for (let task of this.tasks) {
5877
5895
  if (task.node.status === 3 /* STATUS.DESTROYED */) {
@@ -5880,34 +5898,6 @@ class Scheduler {
5880
5898
  }
5881
5899
  this.processing = false;
5882
5900
  }
5883
- processFiber(fiber) {
5884
- if (fiber.root !== fiber) {
5885
- this.tasks.delete(fiber);
5886
- return;
5887
- }
5888
- const hasError = fibersInError.has(fiber);
5889
- if (hasError && fiber.counter !== 0) {
5890
- this.tasks.delete(fiber);
5891
- return;
5892
- }
5893
- if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
5894
- this.tasks.delete(fiber);
5895
- return;
5896
- }
5897
- if (fiber.counter === 0) {
5898
- if (!hasError) {
5899
- fiber.complete();
5900
- }
5901
- // at this point, the fiber should have been applied to the DOM, so we can
5902
- // remove it from the task list. If it is not the case, it means that there
5903
- // was an error and an error handler triggered a new rendering that recycled
5904
- // the fiber, so in that case, we actually want to keep the fiber around,
5905
- // otherwise it will just be ignored.
5906
- if (fiber.appliedToDom) {
5907
- this.tasks.delete(fiber);
5908
- }
5909
- }
5910
- }
5911
5901
  }
5912
5902
 
5913
5903
  let hasBeenLogged = false;
@@ -6007,8 +5997,8 @@ class App extends TemplateSet {
6007
5997
  this.scheduler.processTasks();
6008
5998
  apps.delete(this);
6009
5999
  }
6010
- handleError(...args) {
6011
- return handleError(...args);
6000
+ _handleError(error) {
6001
+ throw error;
6012
6002
  }
6013
6003
  }
6014
6004
  async function mount(C, target, config = {}) {
@@ -6066,14 +6056,20 @@ const mainEventHandler = (data, ev, currentTarget) => {
6066
6056
  // hooks
6067
6057
  // -----------------------------------------------------------------------------
6068
6058
  function decorate(node, f, hookName) {
6069
- const result = f.bind(node.component);
6070
6059
  if (node.app.dev) {
6071
- const suffix = f.name ? ` <${f.name}>` : "";
6072
- Reflect.defineProperty(result, "name", {
6073
- value: hookName + suffix,
6074
- });
6060
+ const component = node.component;
6061
+ const componentName = component ? component.constructor.name : "Component";
6062
+ const name = `${componentName}.${hookName}`;
6063
+ // Create a named wrapper so the name appears in stack traces.
6064
+ // V8 uses computed property keys as inferred function names.
6065
+ const wrapper = {
6066
+ [name]() {
6067
+ return f.call(component);
6068
+ },
6069
+ };
6070
+ return wrapper[name];
6075
6071
  }
6076
- return result;
6072
+ return f.bind(node.component);
6077
6073
  }
6078
6074
  function onWillStart(fn) {
6079
6075
  const { node } = getContext("component");
@@ -6331,22 +6327,30 @@ class Registry {
6331
6327
  }
6332
6328
  }
6333
6329
 
6334
- const anyType = function validateAny() { };
6335
- const booleanType = function validateBoolean(context) {
6336
- if (typeof context.value !== "boolean") {
6337
- context.addIssue({ message: "value is not a boolean" });
6338
- }
6339
- };
6340
- const numberType = function validateNumber(context) {
6341
- if (typeof context.value !== "number") {
6342
- context.addIssue({ message: "value is not a number" });
6343
- }
6344
- };
6345
- const stringType = function validateString(context) {
6346
- if (typeof context.value !== "string") {
6347
- context.addIssue({ message: "value is not a string" });
6348
- }
6349
- };
6330
+ function anyType() {
6331
+ return function validateAny() { };
6332
+ }
6333
+ function booleanType() {
6334
+ return function validateBoolean(context) {
6335
+ if (typeof context.value !== "boolean") {
6336
+ context.addIssue({ message: "value is not a boolean" });
6337
+ }
6338
+ };
6339
+ }
6340
+ function numberType() {
6341
+ return function validateNumber(context) {
6342
+ if (typeof context.value !== "number") {
6343
+ context.addIssue({ message: "value is not a number" });
6344
+ }
6345
+ };
6346
+ }
6347
+ function stringType() {
6348
+ return function validateString(context) {
6349
+ if (typeof context.value !== "string") {
6350
+ context.addIssue({ message: "value is not a string" });
6351
+ }
6352
+ };
6353
+ }
6350
6354
  function arrayType(elementType) {
6351
6355
  return function validateArray(context) {
6352
6356
  if (!Array.isArray(context.value)) {
@@ -6537,6 +6541,9 @@ function reactiveValueType(type) {
6537
6541
  }
6538
6542
  };
6539
6543
  }
6544
+ function componentType() {
6545
+ return constructorType(Component);
6546
+ }
6540
6547
  function ref(type) {
6541
6548
  return union([literalType(null), instanceType(type)]);
6542
6549
  }
@@ -6545,6 +6552,7 @@ const types = {
6545
6552
  any: anyType,
6546
6553
  array: arrayType,
6547
6554
  boolean: booleanType,
6555
+ component: componentType,
6548
6556
  constructor: constructorType,
6549
6557
  customValidator: customValidator,
6550
6558
  function: functionType,
@@ -6771,6 +6779,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
6771
6779
  export { App, Component, EventBus, OwlError, Plugin, Registry, Resource, __info__, assertType, batched, blockDom, computed, config, effect, htmlEscape, markRaw, markup, mount, onError, onMounted, onPatched, onWillDestroy, onWillPatch, onWillStart, onWillUnmount, onWillUpdateProps, plugin, props, providePlugins, proxy, signal, status, toRaw, types, untrack, useApp, useContext, useEffect, useListener, useResource, validateType, whenReady, xml };
6772
6780
 
6773
6781
 
6774
- __info__.date = '2026-04-08T13:31:02.500Z';
6775
- __info__.hash = '2e9164e';
6782
+ __info__.date = '2026-04-10T07:28:23.029Z';
6783
+ __info__.hash = 'e5e6d92';
6776
6784
  __info__.url = 'https://github.com/odoo/owl';