vona-core 5.1.55 → 5.1.57

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
@@ -4,7 +4,7 @@ import { combineApiPathControllerAndActionRaw, combineApiPathControllerAndAction
4
4
  import { toLowerCaseFirstChar, splitWords } from '@cabloy/word-utils';
5
5
  import path from 'node:path';
6
6
  import fse from 'fs-extra';
7
- import crypto, { createHash as createHash$1, randomBytes, timingSafeEqual } from 'node:crypto';
7
+ import crypto, { createHash as createHash$1, randomBytes, timingSafeEqual, randomUUID } from 'node:crypto';
8
8
  import fs, { lstatSync, existsSync, readFileSync, constants } from 'node:fs';
9
9
  import { compose as compose$1 } from '@cabloy/compose';
10
10
  import { extend } from '@cabloy/extend';
@@ -26,10 +26,11 @@ import chalk from 'chalk';
26
26
  import * as Winston from 'winston';
27
27
  import DailyRotateFile from 'winston-daily-rotate-file';
28
28
  import { MESSAGE, LEVEL } from 'triple-beam';
29
+ import cluster from 'node:cluster';
30
+ import { isMainThread } from 'node:worker_threads';
29
31
  import { createServer } from 'node:http';
30
32
  import { mkdir, open, rename, unlink, lstat, readdir } from 'node:fs/promises';
31
33
  import { execFileSync, execFile } from 'node:child_process';
32
- import cluster from 'node:cluster';
33
34
  import React from 'react';
34
35
  import { extendZodWithOpenApi } from '@cabloy/zod-to-openapi';
35
36
  import { z } from 'zod';
@@ -2734,7 +2735,7 @@ class VonaAsyncLocalStorage extends AsyncLocalStorage {
2734
2735
  }
2735
2736
  }
2736
2737
 
2737
- const owners = new WeakMap();
2738
+ const owners$1 = new WeakMap();
2738
2739
  const capabilities = new WeakMap();
2739
2740
  const captures = new WeakSet();
2740
2741
  const pins = new WeakMap();
@@ -2752,13 +2753,13 @@ function createCompletedReadiness(appIdentity) {
2752
2753
  application: state.application
2753
2754
  })
2754
2755
  });
2755
- owners.set(facade, state);
2756
+ owners$1.set(facade, state);
2756
2757
  return facade;
2757
2758
  }
2758
2759
 
2759
2760
  // Internal framework integration only. None of the issuance/provisioning helpers are barrel exports.
2760
2761
  function beginCompletedApplication(owner) {
2761
- const state = owners.get(owner);
2762
+ const state = owners$1.get(owner);
2762
2763
  state.publications.clear();
2763
2764
  state.attempts.clear();
2764
2765
  state.applicationAttempt = Object.freeze({});
@@ -2766,27 +2767,27 @@ function beginCompletedApplication(owner) {
2766
2767
  return state.applicationAttempt;
2767
2768
  }
2768
2769
  function finishCompletedApplication(owner, attempt, success) {
2769
- const state = owners.get(owner);
2770
+ const state = owners$1.get(owner);
2770
2771
  if (state.application === 'closing' || state.applicationAttempt !== attempt) return;
2771
2772
  state.application = success ? 'ready' : 'failed';
2772
2773
  if (!success) state.publications.clear();
2773
2774
  }
2774
2775
  function closeCompletedReadiness(owner) {
2775
- const state = owners.get(owner);
2776
+ const state = owners$1.get(owner);
2776
2777
  state.application = 'closing';
2777
2778
  state.publications.clear();
2778
2779
  state.attempts.clear();
2779
2780
  }
2780
2781
  function invalidateCompletedInstance(owner, name) {
2781
2782
  if (!owner) return;
2782
- const state = owners.get(owner);
2783
+ const state = owners$1.get(owner);
2783
2784
  state.attempts.set(name, Object.freeze({}));
2784
2785
  state.publications.delete(name);
2785
2786
  }
2786
2787
  function beginCompletedInstance(owner, name) {
2787
2788
  if (!owner) return;
2788
2789
  invalidateCompletedInstance(owner, name);
2789
- return owners.get(owner).attempts.get(name);
2790
+ return owners$1.get(owner).attempts.get(name);
2790
2791
  }
2791
2792
  function rowCopy(value) {
2792
2793
  if (!value || typeof value !== 'object') return;
@@ -2847,7 +2848,7 @@ function detach(value, functions, active = new Set(), depth = 0, budget = {
2847
2848
  }
2848
2849
  function captureCompletedInstance(owner, name, attempt, row, config) {
2849
2850
  if (!owner || !attempt) return;
2850
- const state = owners.get(owner);
2851
+ const state = owners$1.get(owner);
2851
2852
  const provision = state.provisions.get(name);
2852
2853
  if (!provision || state.application === 'closing' || state.attempts.get(name) !== attempt) return;
2853
2854
  try {
@@ -2869,7 +2870,7 @@ function captureCompletedInstance(owner, name, attempt, row, config) {
2869
2870
  }
2870
2871
  function finishCompletedInstance(owner, name, attempt, captured) {
2871
2872
  if (!owner || !attempt || !captured || !captures.has(captured)) return;
2872
- const state = owners.get(owner);
2873
+ const state = owners$1.get(owner);
2873
2874
  const publication = captured;
2874
2875
  if (state.application !== 'closing' && state.application !== 'failed' && state.attempts.get(name) === attempt && publication.attempt === attempt && state.provisions.get(name) === publication.provision) {
2875
2876
  state.publications.set(name, publication);
@@ -2877,7 +2878,7 @@ function finishCompletedInstance(owner, name, attempt, captured) {
2877
2878
  }
2878
2879
  function resolveExistingReadyCapability(owner, capability, app) {
2879
2880
  const issued = capabilities.get(capability),
2880
- state = owners.get(owner);
2881
+ state = owners$1.get(owner);
2881
2882
  if (!issued || issued.owner !== owner || !state || state.application !== 'ready' || app && app !== state.app) {
2882
2883
  return;
2883
2884
  }
@@ -4758,6 +4759,184 @@ function assertTestClaimRedisClient(app, clientName, options) {
4758
4759
  if (plan.kind === 'client' ? options.keyPrefix !== plan.prefix : options.keyPrefix !== undefined) throw new Error('Unregistered managed Redis key prefix');
4759
4760
  }
4760
4761
 
4762
+ const owners = new WeakMap();
4763
+ const ownerStorage = new AsyncLocalStorage();
4764
+ class TestAsyncCompletion {
4765
+ constructor(app, options) {
4766
+ this.id = randomUUID();
4767
+ this.instanceName = void 0;
4768
+ this.clientName = void 0;
4769
+ this.app = void 0;
4770
+ this.databaseIdentity = void 0;
4771
+ this.pending = new Map();
4772
+ this.failures = [];
4773
+ this.waiters = new Set();
4774
+ this.version = 0;
4775
+ this.closed = false;
4776
+ if (!app.meta.isTest || !app.meta.appReady || !cluster.isPrimary || !isMainThread || process.env.NODE_UNIQUE_ID !== undefined || useApp() !== app) {
4777
+ throw new Error('Test async completion requires the ready in-process test application');
4778
+ }
4779
+ const env = app.meta.env;
4780
+ const runId = assertTestAppIdentity('test', env.VONA_TEST_RUN_ID, app.name);
4781
+ if (!runId || env.META_MODE !== 'test' || process.env.VONA_TEST_RUN_ID !== runId || !hasTestClaimTransport()) {
4782
+ throw new Error('Test async completion requires a managed test run');
4783
+ }
4784
+ const paths = resolveVonaLocalPaths(app.projectPath, 'test', runId);
4785
+ assertTestRunOwner(paths.dataRoot, runId);
4786
+ assertTestRunOwner(paths.generatedRoot, runId);
4787
+ if (!options.instanceName || !options.clientName || options.clientName.includes(':')) {
4788
+ throw new Error('Test async completion requires an instance and a database client name');
4789
+ }
4790
+ this.app = app;
4791
+ this.instanceName = options.instanceName;
4792
+ this.clientName = options.clientName;
4793
+ this.databaseIdentity = getDatabaseIdentity(app, this.clientName);
4794
+ let registry = owners.get(app);
4795
+ if (!registry) {
4796
+ registry = new Map();
4797
+ owners.set(app, registry);
4798
+ }
4799
+ registry.set(this.id, this);
4800
+ }
4801
+ async run(fn) {
4802
+ const ticket = this.reserve('run');
4803
+ try {
4804
+ return await this.bind(fn);
4805
+ } finally {
4806
+ ticket.complete();
4807
+ }
4808
+ }
4809
+ reserve(label) {
4810
+ this.assertOpen();
4811
+ const key = Symbol(label);
4812
+ this.pending.set(key, label);
4813
+ this.version++;
4814
+ return {
4815
+ complete: error => {
4816
+ if (!this.pending.delete(key)) return;
4817
+ if (error !== undefined) this.failures.push(error);
4818
+ this.version++;
4819
+ for (const wake of this.waiters) wake();
4820
+ this.waiters.clear();
4821
+ }
4822
+ };
4823
+ }
4824
+ track(label, fn) {
4825
+ const ticket = this.reserve(label);
4826
+ const result = this.bind(async () => {
4827
+ try {
4828
+ return await fn();
4829
+ } catch (error) {
4830
+ ticket.complete(error === undefined ? new Error(`Test async operation rejected: ${label}`) : error);
4831
+ throw error;
4832
+ } finally {
4833
+ ticket.complete();
4834
+ }
4835
+ });
4836
+ void result.catch(() => {});
4837
+ return result;
4838
+ }
4839
+ bind(fn) {
4840
+ this.assertOpen();
4841
+ return ownerStorage.run(this, fn);
4842
+ }
4843
+ async settle({
4844
+ timeout = 30_000
4845
+ } = {}) {
4846
+ if (ownerStorage.getStore()) {
4847
+ throw new Error('Test async completion cannot settle from an active owner context');
4848
+ }
4849
+ if (!Number.isFinite(timeout) || timeout < 0 || timeout > 2_147_483_647) {
4850
+ throw new Error('Test async completion timeout must be a valid nonnegative timer duration');
4851
+ }
4852
+ let timedOut = false;
4853
+ let wake;
4854
+ const timer = setTimeout(() => {
4855
+ timedOut = true;
4856
+ wake?.();
4857
+ }, timeout);
4858
+ try {
4859
+ while (true) {
4860
+ if (timedOut) {
4861
+ throw new Error(`Test async completion timed out; pending: ${[...this.pending.values()].join(', ')}`);
4862
+ }
4863
+ if (this.pending.size) {
4864
+ await new Promise(resolve => {
4865
+ wake = resolve;
4866
+ this.waiters.add(resolve);
4867
+ });
4868
+ continue;
4869
+ }
4870
+ const version = this.version;
4871
+ await Promise.resolve();
4872
+ if (this.pending.size || this.version !== version) continue;
4873
+ this.assertSettled();
4874
+ return;
4875
+ }
4876
+ } finally {
4877
+ clearTimeout(timer);
4878
+ if (wake) this.waiters.delete(wake);
4879
+ }
4880
+ }
4881
+ assertSettled() {
4882
+ if (this.pending.size) {
4883
+ throw new Error(`Test async completion is pending: ${[...this.pending.values()].join(', ')}`);
4884
+ }
4885
+ if (this.failures.length) {
4886
+ throw new AggregateError(this.failures, 'Test async completion failed');
4887
+ }
4888
+ }
4889
+ assertScope(options) {
4890
+ this.assertOpen();
4891
+ if (options?.instanceName !== this.instanceName && options?.instanceName !== null || options?.dbInfo?.clientName !== this.clientName) {
4892
+ throw new Error('Test async completion scope does not match its owner');
4893
+ }
4894
+ if (!isDeepStrictEqual(this.databaseIdentity, getDatabaseIdentity(this.app, this.clientName))) {
4895
+ throw new Error('Test async completion database identity changed');
4896
+ }
4897
+ }
4898
+ close() {
4899
+ this.assertSettled();
4900
+ owners.get(this.app)?.delete(this.id);
4901
+ this.closed = true;
4902
+ }
4903
+ assertOpen() {
4904
+ if (this.closed) throw new Error('Test async completion is closed');
4905
+ }
4906
+ }
4907
+ function createTestAsyncCompletion(app, options) {
4908
+ return new TestAsyncCompletion(app, options);
4909
+ }
4910
+ function getTestAsyncCompletion(app) {
4911
+ const owner = ownerStorage.getStore();
4912
+ return owner && owners.get(app)?.get(owner.id) === owner ? owner : undefined;
4913
+ }
4914
+ function withoutTestAsyncCompletion(fn) {
4915
+ return ownerStorage.exit(fn);
4916
+ }
4917
+ function findTestAsyncCompletion(app, id) {
4918
+ return owners.get(app)?.get(id);
4919
+ }
4920
+ function getDatabaseIdentity(app, clientName) {
4921
+ const bean = app.bean;
4922
+ const client = bean.database.getClient(clientName);
4923
+ if (client.clientName !== clientName) {
4924
+ throw new Error('Test async completion requires a resolved database client name');
4925
+ }
4926
+ const config = client.clientConfig;
4927
+ assertIsolatedTestDatabaseClient(app, clientName, config);
4928
+ assertTestClaimDatabaseClient(app, clientName, config);
4929
+ const connection = config.connection;
4930
+ return {
4931
+ name: client.getDatabaseName(),
4932
+ client: config.client,
4933
+ host: connection.host,
4934
+ port: connection.port,
4935
+ database: connection.database,
4936
+ filename: connection.filename
4937
+ };
4938
+ }
4939
+
4761
4940
  const freshApps = new WeakSet();
4762
4941
  function assertFreshTestResourcesReady(app) {
4763
4942
  if (!requiresFreshTestResources()) return;
@@ -5536,5 +5715,5 @@ async function retry(options, fn) {
5536
5715
 
5537
5716
  zodExtendOpenApi();
5538
5717
 
5539
- export { $Class, $localeScope, $makeLocaleMagic, $protocolKey, AppHmr, AppHmrDeps, AppLocale, AppLogger, AppMeta, AppMetadata, AppResource, AppUtil, BeanAopBase, BeanAopMethodBase, BeanBase, BeanBaseSimple, BeanContainer, BeanInfo, BeanScopeBase, BeanScopeContainer, BeanScopeError, BeanScopeErrorImpl, BeanScopeLocale, BeanScopeScene, BeanScopeUtil, BeanSimple, EnumAppEvent, ErrorClass, Global, LocaleModuleNameSeparator, PickClassInner, ProxyDisable, SymbolBeanContainerInstances, SymbolBeanFullName, SymbolBeanInstanceKey, SymbolBeanInstancePropsLazy, SymbolCacheAopChains, SymbolCacheAopChainsKey, SymbolDecoratorBeanFullName, SymbolDecoratorBeanInfo, SymbolDecoratorGlobal, SymbolDecoratorProxyDisable, SymbolDecoratorUse, SymbolDecoratorVirtual, SymbolHmrStateLoad, SymbolHmrStateSave, SymbolMappedClassMetadataKeys, SymbolModuleBelong, SymbolModuleName, TEST_CLAIM_DIRECTORY, TEST_CLAIM_TOKEN_ENV, TEST_CLAIM_URL_ENV, TEST_CLAIM_WINDOWS_GUARDIAN_ENV, TEST_REQUIRE_FRESH_RESOURCES_ENV, TEST_RUN_ID_ENV, TEST_RUN_OWNER_FILE, Use, Virtual, VonaApplication, __prepareInjectSelectorInfo, appHmrDeps, appMetadata, appResource, assertDisposableDatabaseName, assertFreshTestResources, assertFreshTestResourcesReady, assertIsolatedTestConfig, assertIsolatedTestDatabaseClient, assertIsolatedTestPath, assertTestAppIdentity, assertTestClaimDatabaseClient, assertTestClaimRedisClient, assertTestClaimSafePath, assertTestClaimWindowsJob, assertTestRunOwner, beanFullNameFromOnionName, beginCompletedInstance, bootstrap, buildTestClaimResourceInventory, canonicalizeLocale, captureCompletedInstance, captureRequestBoundary, cast, closeApp, closeProcessWorker, combineConfigDefault, combineFilePathSafe, compose, copyAddon, copyMetadataOfClasses, copyProperties, copyPropertiesOfClasses, createApp, createAppMaster, createBeanDecorator, createCompletedReadiness, createDiagnosticLogger, createFreshnessDependencies, createGeneralApp, createHash, createRequestBoundary, createTestClaim, deepExtend, disposeInstance, errorsInternal, filterHeaders, finishCompletedInstance, formatLoggerAxiosError, formatLoggerBoundary, formatLoggerConsole, formatLoggerCtx, formatLoggerDummy, formatLoggerErrors, formatLoggerFilter, functionNoop, getDatabaseTestPrefix, getHomeVonaAppDir, getLoggerPathPhysicalRoot, getMappedClassMetadataKeys, getPlatformArch, getPublicPathPhysicalRoot, getRequestBoundary, getRuntimePathPhysicalRoot, getSqlite3DatabaseNameDefault, getSuppressedDiagnosticLogger, getTestAppName, getTestClaimCreatedAt, getTestClaimPaths, getTestClaimRedisPrefix, getTestRunIdFromEnv, hasFreshnessDatabase, hasFreshnessRedis, hasTestClaimTransport, instanceDesp, invalidateCompletedInstance, isExistingReadyContext, isLocaleMagic, loadJSONFile, loadTestClaim, mergeTestClaimDatabaseOptions, mergeTestClaimRedisOptions, normalizeTestClaimDatabaseEndpoint, normalizeTestClaimRedisEndpoint, onionNameFromBeanFullName, pathToHref, pinExistingReadyContext, polyfillDispose, prepareEnv, registerMappedClassMetadataKey, registerTestClaimDatabaseCreation, registerTestClaimResourceInventory, registerTestClaimWindowsJobVerifier, requireAddon, requireDynamic, requiresFreshTestResources, resolveAddon, resolveEnabledLocale, resolveExistingReadyCapability, resolveLocale, resolveTestRunId, resolveVonaLocalPaths, resolverSharp, resolverSharpLibvips, resolverSqlite3, retry, runWithRequestBoundary, runWithZodQueryCoercion, saveJSONFile, sendTestClaimEvent, setMappedClassMetadataKeys, startTestClaimBroker, text$1 as text, useApp, usePrepareArg, usePrepareArgs, uuidv4, validateLocaleConfig, validateTestClaim, withIsolatedTestDatabaseDiscovery, writeTestClaim };
5718
+ export { $Class, $localeScope, $makeLocaleMagic, $protocolKey, AppHmr, AppHmrDeps, AppLocale, AppLogger, AppMeta, AppMetadata, AppResource, AppUtil, BeanAopBase, BeanAopMethodBase, BeanBase, BeanBaseSimple, BeanContainer, BeanInfo, BeanScopeBase, BeanScopeContainer, BeanScopeError, BeanScopeErrorImpl, BeanScopeLocale, BeanScopeScene, BeanScopeUtil, BeanSimple, EnumAppEvent, ErrorClass, Global, LocaleModuleNameSeparator, PickClassInner, ProxyDisable, SymbolBeanContainerInstances, SymbolBeanFullName, SymbolBeanInstanceKey, SymbolBeanInstancePropsLazy, SymbolCacheAopChains, SymbolCacheAopChainsKey, SymbolDecoratorBeanFullName, SymbolDecoratorBeanInfo, SymbolDecoratorGlobal, SymbolDecoratorProxyDisable, SymbolDecoratorUse, SymbolDecoratorVirtual, SymbolHmrStateLoad, SymbolHmrStateSave, SymbolMappedClassMetadataKeys, SymbolModuleBelong, SymbolModuleName, TEST_CLAIM_DIRECTORY, TEST_CLAIM_TOKEN_ENV, TEST_CLAIM_URL_ENV, TEST_CLAIM_WINDOWS_GUARDIAN_ENV, TEST_REQUIRE_FRESH_RESOURCES_ENV, TEST_RUN_ID_ENV, TEST_RUN_OWNER_FILE, TestAsyncCompletion, Use, Virtual, VonaApplication, __prepareInjectSelectorInfo, appHmrDeps, appMetadata, appResource, assertDisposableDatabaseName, assertFreshTestResources, assertFreshTestResourcesReady, assertIsolatedTestConfig, assertIsolatedTestDatabaseClient, assertIsolatedTestPath, assertTestAppIdentity, assertTestClaimDatabaseClient, assertTestClaimRedisClient, assertTestClaimSafePath, assertTestClaimWindowsJob, assertTestRunOwner, beanFullNameFromOnionName, beginCompletedInstance, bootstrap, buildTestClaimResourceInventory, canonicalizeLocale, captureCompletedInstance, captureRequestBoundary, cast, closeApp, closeProcessWorker, combineConfigDefault, combineFilePathSafe, compose, copyAddon, copyMetadataOfClasses, copyProperties, copyPropertiesOfClasses, createApp, createAppMaster, createBeanDecorator, createCompletedReadiness, createDiagnosticLogger, createFreshnessDependencies, createGeneralApp, createHash, createRequestBoundary, createTestAsyncCompletion, createTestClaim, deepExtend, disposeInstance, errorsInternal, filterHeaders, findTestAsyncCompletion, finishCompletedInstance, formatLoggerAxiosError, formatLoggerBoundary, formatLoggerConsole, formatLoggerCtx, formatLoggerDummy, formatLoggerErrors, formatLoggerFilter, functionNoop, getDatabaseTestPrefix, getHomeVonaAppDir, getLoggerPathPhysicalRoot, getMappedClassMetadataKeys, getPlatformArch, getPublicPathPhysicalRoot, getRequestBoundary, getRuntimePathPhysicalRoot, getSqlite3DatabaseNameDefault, getSuppressedDiagnosticLogger, getTestAppName, getTestAsyncCompletion, getTestClaimCreatedAt, getTestClaimPaths, getTestClaimRedisPrefix, getTestRunIdFromEnv, hasFreshnessDatabase, hasFreshnessRedis, hasTestClaimTransport, instanceDesp, invalidateCompletedInstance, isExistingReadyContext, isLocaleMagic, loadJSONFile, loadTestClaim, mergeTestClaimDatabaseOptions, mergeTestClaimRedisOptions, normalizeTestClaimDatabaseEndpoint, normalizeTestClaimRedisEndpoint, onionNameFromBeanFullName, pathToHref, pinExistingReadyContext, polyfillDispose, prepareEnv, registerMappedClassMetadataKey, registerTestClaimDatabaseCreation, registerTestClaimResourceInventory, registerTestClaimWindowsJobVerifier, requireAddon, requireDynamic, requiresFreshTestResources, resolveAddon, resolveEnabledLocale, resolveExistingReadyCapability, resolveLocale, resolveTestRunId, resolveVonaLocalPaths, resolverSharp, resolverSharpLibvips, resolverSqlite3, retry, runWithRequestBoundary, runWithZodQueryCoercion, saveJSONFile, sendTestClaimEvent, setMappedClassMetadataKeys, startTestClaimBroker, text$1 as text, useApp, usePrepareArg, usePrepareArgs, uuidv4, validateLocaleConfig, validateTestClaim, withIsolatedTestDatabaseDiscovery, withoutTestAsyncCompletion, writeTestClaim };
5540
5719
  //# sourceMappingURL=index.js.map