@wildo-ai/saas-frontend-lib 1.1.3 → 1.1.4
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/esm/companion-exports.d.ts +1 -1
- package/dist/esm/companion-exports.d.ts.map +1 -1
- package/dist/esm/companion-exports.js +1 -1
- package/dist/esm/companion-exports.js.map +1 -1
- package/dist/esm/components/ai-elements/decision/approval.d.ts +13 -1
- package/dist/esm/components/ai-elements/decision/approval.d.ts.map +1 -1
- package/dist/esm/components/ai-elements/decision/approval.js.map +1 -1
- package/dist/esm/components/flows-actors/approval.d.ts.map +1 -1
- package/dist/esm/components/flows-actors/approval.js +12 -7
- package/dist/esm/components/flows-actors/approval.js.map +1 -1
- package/dist/esm/components/flows-actors/approval.labels.d.ts.map +1 -1
- package/dist/esm/components/flows-actors/approval.labels.js +3 -0
- package/dist/esm/components/flows-actors/approval.labels.js.map +1 -1
- package/dist/esm/components/flows-actors/execution-plan.js +1 -1
- package/dist/esm/components/flows-actors/execution-plan.js.map +1 -1
- package/dist/esm/components/flows-actors/task-memory.js +1 -1
- package/dist/esm/components/flows-actors/task-memory.js.map +1 -1
- package/dist/esm/components/form/automated/generated-relationship-field.hooks.d.ts +1 -1
- package/dist/esm/components/form/controls/number/slider.d.ts +1 -1
- package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.d.ts +1 -1
- package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.d.ts.map +1 -1
- package/dist/esm/components/form/fields/form-field-file-provider-constraints.frontend.utils.js.map +1 -1
- package/dist/esm/components/form/fields/form-field-file.d.ts.map +1 -1
- package/dist/esm/components/form/fields/form-field-file.js +66 -17
- package/dist/esm/components/form/fields/form-field-file.js.map +1 -1
- package/dist/esm/components/form/fields/form-field-file.labels.js +2 -2
- package/dist/esm/components/form/fields/form-field-file.labels.js.map +1 -1
- package/dist/esm/components/form/form-field-types.d.ts +20 -0
- package/dist/esm/components/form/form-field-types.d.ts.map +1 -1
- package/dist/esm/components/form/form-field-types.js.map +1 -1
- package/dist/esm/components/navigation/NavigationItemBadge.d.ts +7 -1
- package/dist/esm/components/navigation/NavigationItemBadge.d.ts.map +1 -1
- package/dist/esm/components/navigation/NavigationItemBadge.js +29 -1
- package/dist/esm/components/navigation/NavigationItemBadge.js.map +1 -1
- package/dist/esm/components/navigation/menu-bar.d.ts +1 -1
- package/dist/esm/components/overlays/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/esm/components/overlays/containers/OverlayContainer.js +36 -9
- package/dist/esm/components/overlays/containers/OverlayContainer.js.map +1 -1
- package/dist/esm/components/overlays/floating/context-menu.d.ts +1 -1
- package/dist/esm/components/overlays/floating/dropdown-menu.d.ts +1 -1
- package/dist/esm/components/resources/ResourceLayout_FilterChips.js +1 -1
- package/dist/esm/components/resources/ResourceLayout_FilterChips.js.map +1 -1
- package/dist/esm/components/resources/ResourceListItemRenderer.js +1 -1
- package/dist/esm/components/resources/ResourceListItemRenderer.js.map +1 -1
- package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.d.ts +12 -0
- package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.d.ts.map +1 -1
- package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.js +13 -1
- package/dist/esm/components/resources/skeleton/ResourceHeaderTitle.js.map +1 -1
- package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.d.ts +106 -49
- package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.d.ts.map +1 -1
- package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.js +311 -109
- package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.js.map +1 -1
- package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.d.ts.map +1 -1
- package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.js +32 -2
- package/dist/esm/components/settings/AppPage_ConnectedAccountsSettings.labels.js.map +1 -1
- package/dist/esm/components/settings/SettingsHub.d.ts.map +1 -1
- package/dist/esm/components/settings/SettingsHub.js +30 -6
- package/dist/esm/components/settings/SettingsHub.js.map +1 -1
- package/dist/esm/components/views/onboarding-view/OnboardingView.d.ts.map +1 -1
- package/dist/esm/components/views/onboarding-view/OnboardingView.js +9 -2
- package/dist/esm/components/views/onboarding-view/OnboardingView.js.map +1 -1
- package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.d.ts +16 -0
- package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.d.ts.map +1 -1
- package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.js +17 -0
- package/dist/esm/core/automated-layout/automated-layout.frontend.schemas.js.map +1 -1
- package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.d.ts.map +1 -1
- package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.js +3 -2
- package/dist/esm/core/automated-layout/default-layout-generator.frontend.utils.js.map +1 -1
- package/dist/esm/core/billing/billing-launcher.js +1 -1
- package/dist/esm/core/billing/billing-launcher.js.map +1 -1
- package/dist/esm/core/components-registry/provider-component-registry.frontend.service.d.ts +64 -4
- package/dist/esm/core/components-registry/provider-component-registry.frontend.service.d.ts.map +1 -1
- package/dist/esm/core/components-registry/provider-component-registry.frontend.service.js +76 -4
- package/dist/esm/core/components-registry/provider-component-registry.frontend.service.js.map +1 -1
- package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.d.ts +8 -0
- package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.d.ts.map +1 -1
- package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.js +1 -0
- package/dist/esm/core/components-registry/useProviderComponent.frontend.hooks.js.map +1 -1
- package/dist/esm/core/config/chart-view.frontend.schemas.d.ts +8 -8
- package/dist/esm/core/config/composite-view.schemas.d.ts +4 -4
- package/dist/esm/core/config/engine-settings-destinations.d.ts +0 -69
- package/dist/esm/core/config/engine-settings-destinations.d.ts.map +1 -1
- package/dist/esm/core/config/engine-settings-destinations.js +35 -74
- package/dist/esm/core/config/engine-settings-destinations.js.map +1 -1
- package/dist/esm/core/config/settings-hub.frontend.schemas.d.ts +10 -1
- package/dist/esm/core/config/settings-hub.frontend.schemas.d.ts.map +1 -1
- package/dist/esm/core/config/settings-hub.frontend.schemas.js +9 -0
- package/dist/esm/core/config/settings-hub.frontend.schemas.js.map +1 -1
- package/dist/esm/core/config/useSettingsHubConfig.d.ts.map +1 -1
- package/dist/esm/core/config/useSettingsHubConfig.js +8 -1
- package/dist/esm/core/config/useSettingsHubConfig.js.map +1 -1
- package/dist/esm/core/events/events.frontend.schemas.d.ts +4 -4
- package/dist/esm/core/external-providers/ProviderFilePickerHost.d.ts +12 -1
- package/dist/esm/core/external-providers/ProviderFilePickerHost.d.ts.map +1 -1
- package/dist/esm/core/external-providers/ProviderFilePickerHost.js +15 -2
- package/dist/esm/core/external-providers/ProviderFilePickerHost.js.map +1 -1
- package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.d.ts +1 -2
- package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.d.ts.map +1 -1
- package/dist/esm/core/external-providers/provider-file-selection.frontend.utils.js.map +1 -1
- package/dist/esm/core/flows-actors/FlowsActorsContext.d.ts +6 -1
- package/dist/esm/core/flows-actors/FlowsActorsContext.d.ts.map +1 -1
- package/dist/esm/core/flows-actors/FlowsActorsContext.js +10 -2
- package/dist/esm/core/flows-actors/FlowsActorsContext.js.map +1 -1
- package/dist/esm/core/i18n/I18nContext.d.ts +23 -0
- package/dist/esm/core/i18n/I18nContext.d.ts.map +1 -1
- package/dist/esm/core/i18n/I18nContext.js +6 -1
- package/dist/esm/core/i18n/I18nContext.js.map +1 -1
- package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.d.ts +75 -2
- package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.d.ts.map +1 -1
- package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.js +52 -0
- package/dist/esm/core/requests/wildo-http-client-manual-calls.frontend.service.js.map +1 -1
- package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.d.ts +3 -2
- package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.d.ts.map +1 -1
- package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.js +57 -4
- package/dist/esm/core/requests/wildo-http-client-resources.frontend.service.js.map +1 -1
- package/dist/esm/core/resources/ResourceReadCacheBridge.d.ts.map +1 -1
- package/dist/esm/core/resources/ResourceReadCacheBridge.js +130 -37
- package/dist/esm/core/resources/ResourceReadCacheBridge.js.map +1 -1
- package/dist/esm/core/resources/resources.frontend.schemas.d.ts +2 -2
- package/dist/esm/core/runtime/start-application.frontend.service.d.ts.map +1 -1
- package/dist/esm/core/runtime/start-application.frontend.service.js +17 -9
- package/dist/esm/core/runtime/start-application.frontend.service.js.map +1 -1
- package/dist/esm/core/security/UserOrgsContext.d.ts.map +1 -1
- package/dist/esm/core/security/UserOrgsContext.js +61 -5
- package/dist/esm/core/security/UserOrgsContext.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -44,7 +44,9 @@ function isScalarContextualParameterValue(value) {
|
|
|
44
44
|
*/
|
|
45
45
|
function isCacheableReadOperation(operation) {
|
|
46
46
|
const coreOperation = resolveEffectiveCoreOperationFromOperation(operation);
|
|
47
|
-
return coreOperation === CoreResourceOperation.READ
|
|
47
|
+
return coreOperation === CoreResourceOperation.READ
|
|
48
|
+
|| coreOperation === CoreResourceOperation.LIST
|
|
49
|
+
|| coreOperation === CoreResourceOperation.SEARCH;
|
|
48
50
|
}
|
|
49
51
|
export class WildoBackendHttpClient_Resources extends WildoBackendHttpClient {
|
|
50
52
|
resourcesRegistry;
|
|
@@ -85,8 +87,9 @@ export class WildoBackendHttpClient_Resources extends WildoBackendHttpClient {
|
|
|
85
87
|
/**
|
|
86
88
|
* The cache identity of a READ, and the scope rooms that would carry its invalidation.
|
|
87
89
|
*
|
|
88
|
-
* Called only for operations `isCacheableReadOperation` already admitted
|
|
89
|
-
*
|
|
90
|
+
* Called only for operations `isCacheableReadOperation` already admitted — the two entry points
|
|
91
|
+
* being `doOperation` and `executeSearchOperation`, which is the whole read family — so it answers
|
|
92
|
+
* the narrower question: can this particular CALL be keyed, and what covers it?
|
|
90
93
|
*
|
|
91
94
|
* `null` means "run it and cache nothing" — for parameters that cannot be rendered into a stable
|
|
92
95
|
* key (a cycle, a function in a filter), or for an operation carrying no primary scope. Neither is
|
|
@@ -218,7 +221,57 @@ export class WildoBackendHttpClient_Resources extends WildoBackendHttpClient {
|
|
|
218
221
|
if (resolveEffectiveCoreOperationFromOperation(operation) !== CoreResourceOperation.SEARCH) {
|
|
219
222
|
throw this.buildError(ErrorCustomMessageReference.FRONTEND_RESOURCE_SEARCH_OPERATION_INVALID, operationPathKey, { operationPathKey, actualOperationIdentifier: operation.operationIdentifier });
|
|
220
223
|
}
|
|
221
|
-
|
|
224
|
+
/*
|
|
225
|
+
* The SAME read-through cache `doOperation` applies, because a SEARCH is the same kind of read.
|
|
226
|
+
*
|
|
227
|
+
* ## Why SEARCH was uncached, and why that was an accident rather than a decision
|
|
228
|
+
*
|
|
229
|
+
* `ResourceRegistryContext.doOperation` routes a SEARCH here instead of to `doOperation`, and the
|
|
230
|
+
* cache block lived only there — so a collection surface served by a SEARCH got none of the tier,
|
|
231
|
+
* silently, with no diagnostic and nothing in the tier's own prose saying so. Nothing about SEARCH
|
|
232
|
+
* justified the exclusion: it is a projection of stored rows, it derives its scope rooms from the
|
|
233
|
+
* same contextual parameters and primary scope as a LIST on the same resource, and it is
|
|
234
|
+
* invalidated by the same per-resource-type channel. The asymmetry was an artefact of the routing.
|
|
235
|
+
*
|
|
236
|
+
* ## The key, and the churn question that decided it
|
|
237
|
+
*
|
|
238
|
+
* `renderResourceReadCacheKey` is total over any parameters object — sorted keys, cycle-safe,
|
|
239
|
+
* refusing what it cannot render — so the search body varies the key exactly as page, limit, sort
|
|
240
|
+
* and filter already do. The real objection to caching a search is CARDINALITY: a typeahead
|
|
241
|
+
* produces a distinct key per query and could evict everything else. It does not, and the tier
|
|
242
|
+
* already says why — eviction is least-recently-USED, "so an entry a surface keeps reading
|
|
243
|
+
* survives while a page visited once does not". A one-shot query evicts itself first.
|
|
244
|
+
*
|
|
245
|
+
* ## What did NOT change
|
|
246
|
+
*
|
|
247
|
+
* Coverage. A SEARCH entry is servable only while every room it belongs to is joined and
|
|
248
|
+
* CONFIRMED, exactly like a LIST, so the safety contract is untouched and an unscoped search is
|
|
249
|
+
* still refused at the door by `store()`.
|
|
250
|
+
*
|
|
251
|
+
* Both entry points gate on the SAME `isCacheableReadOperation`, and that is not decoration. The
|
|
252
|
+
* first version of this called `resolveCacheableRead` directly here, which made the predicate
|
|
253
|
+
* INERT on the search path — two mechanisms deciding one question, with the one a reader would
|
|
254
|
+
* check having no effect on the path they were reading about. A mutation removing SEARCH from the
|
|
255
|
+
* predicate changed nothing, which is how that was found.
|
|
256
|
+
*
|
|
257
|
+
* Widening the shared predicate rather than adding a second one also removes a latent defect on
|
|
258
|
+
* the other path: a SEARCH reaching `doOperation` was previously NOT read-family, so it took the
|
|
259
|
+
* mutation branch and INVALIDATED its own resource type. Unreachable through the registry today,
|
|
260
|
+
* and wrong wherever it became reachable.
|
|
261
|
+
*/
|
|
262
|
+
const cacheable = isCacheableReadOperation(operation)
|
|
263
|
+
? this.resolveCacheableRead(operationPathKey, operation, parameters)
|
|
264
|
+
: null;
|
|
265
|
+
if (cacheable) {
|
|
266
|
+
const cached = this.readCache.read(cacheable.key);
|
|
267
|
+
if (cached !== undefined)
|
|
268
|
+
return structuredClone(cached);
|
|
269
|
+
}
|
|
270
|
+
const response = await this.executeSearchOperationInternal(operation, parameters, options);
|
|
271
|
+
if (cacheable) {
|
|
272
|
+
this.readCache.store(cacheable.key, response, cacheable.resourceType, cacheable.scopes);
|
|
273
|
+
}
|
|
274
|
+
return response;
|
|
222
275
|
}
|
|
223
276
|
/**
|
|
224
277
|
* Select the appropriate response DTO based on dataMode
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wildo-http-client-resources.frontend.service.js","sourceRoot":"","sources":["../../../../src/core/requests/wildo-http-client-resources.frontend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WildoBackendHttpClient_Resources\n * Specialized HTTP client for resource-based operations (CRUD)\n * Extends base WildoBackendHttpClient with resource-specific functionality\n */\n\nimport { z } from 'zod';\nimport { WildoBackendHttpClient, WildoBackendHttpClientConfig, RequestOptions } from './wildo-http-client.frontend.service';\n\n/**\n * The per-request timeout for one operation dispatch — the ONE seam all three requestOptions\n * assemblies in this file (api-call, api-call-with-callback, search) route through, so a\n * long-running variant behaves the same through every dispatch shape and a fourth assembly cannot\n * silently skip the rule (issue #237; invariant-call-site-enumeration: prefer a shared predicate\n * over N hand-applied spreads).\n *\n * Precedence: caller-supplied `options.timeout` wins; else the variant's declared\n * `clientRequestTimeoutMs`; else empty — the client's instance default applies.\n */\nexport function resolveOperationRequestTimeout(\n options: RequestOptions | undefined,\n operation: { clientRequestTimeoutMs?: number },\n): { timeout: number } | Record<string, never> {\n if (options?.timeout !== undefined) return {}; // already in the caller's spread\n if (operation.clientRequestTimeoutMs !== undefined) return { timeout: operation.clientRequestTimeoutMs };\n return {};\n}\nimport {\n ResourceConfiguration_Operation_UrlInitiatorInfo,\n ResourceConfiguration_Operation_UrlParameterInfo,\n ResourceConfiguration_OperationPath,\n ResourcesConfig_OperationPathUtils,\n ResourceOperationVariantType,\n HttpMethod,\n ErrorType,\n ErrorCustomMessageReference,\n DataMode,\n CoreResourceOperation,\n ResourcesConfigOperationsDtosBuilderUtils,\n ResourceOperationRiskLevel,\n type Resources_PaginationRequest,\n type ResourceType,\n} from '@wildo-ai/saas-models';\nimport type { FrontendResource_ParentResourceRequirement } from '~wildo-frontend-lib/core/resources/resource-path.frontend.schemas';\nimport type {\n FrontendResourcesRegistry,\n AnyFrontendResourceConfiguration,\n FrontendResourceConfiguration_Operation,\n} from '~wildo-frontend-lib/core/resources/resources.frontend.schemas';\nimport { ErrorBuilderFrontend } from '~wildo-frontend-lib/core/errors/errors-builder.frontend.services';\nimport { LoadingTier, LoadingPhase } from '~wildo-frontend-lib/core/loading/loading-types.frontend.schemas';\nimport { FrontendResourceUtils } from '~wildo-frontend-lib/core/resources/frontend-resource.utils';\nimport { resolveEffectiveCoreOperationFromOperation } from '~wildo-frontend-lib/core/resources/operation-semantics.frontend.utils';\nimport {\n ResourceReadCacheFrontendService,\n renderResourceReadCacheKey,\n} from '~wildo-frontend-lib/core/resources/resource-read-cache.frontend.service';\nimport { deriveResourceScopeRoomQualifiers, ResourcePrimaryScope } from '@wildo-ai/saas-models';\nimport type { ResourceScopeRoomQualifier } from '@wildo-ai/saas-models';\n\n/**\n * Parameters needed to execute a resource operation\n */\nexport type ResourceContextualParameterValue = string | number | string[];\n\nfunction isScalarContextualParameterValue(\n value: ResourceContextualParameterValue | undefined\n): value is string | number {\n return typeof value === 'string' || typeof value === 'number';\n}\n\nexport interface ResourceOperationCallParameters {\n /** Values for URL parameters (matching initiator.parameters) */\n contextualParameters: Record<string, ResourceContextualParameterValue>;\n /** Request body data (for POST/PUT operations) */\n requestData?: any;\n /** Query parameters (for search operations and GET requests) */\n queryParameters?: Record<string, any>;\n /** For callback operations: 'primaryCall' | 'callbackCall' */\n callType?: 'primaryCall' | 'callbackCall';\n /** \n * Parent resource requirements for deterministic URL selection.\n * Used to select the correct endpoint when multiple URLs are available.\n * Should be passed from resourceContext.parentResourcesRequirements.\n */\n parentResourcesRequirements?: FrontendResource_ParentResourceRequirement[];\n /**\n * Data mode controlling fields returned and population behavior.\n * - RAW: All stored fields, no population (default)\n * - SUMMARY: Summary fields only, populate isSummaryField({ populate: true }) FKs\n * - CONTEXT: All fields, populate based on contextPolicy\n */\n dataMode?: DataMode;\n}\n\n/**\n * Search-specific parameters extending base operation parameters\n */\nexport interface ResourceSearchCallParameters extends ResourceOperationCallParameters {\n /** Search query string */\n searchQuery?: string;\n /** Filter parameters */\n filters?: Record<string, any>;\n /** Sort configuration */\n sort?: { field: string; direction: 'asc' | 'desc' }[];\n /** Pagination */\n pagination?: Resources_PaginationRequest;\n // Note: dataMode is inherited from ResourceOperationCallParameters\n}\n\n/**\n * Result of URL building process\n */\ninterface UrlBuildResult {\n url: string;\n missingParameters: string[];\n}\n\n/**\n * Specialized HTTP client for resource-based operations\n * Should only be used through ResourceRepositoryContext\n */\n/**\n * Whether this operation READS, in the sense that its result is a projection of stored rows.\n *\n * Module-scoped rather than a method because it is a pure question about the operation, and because\n * it is the predicate a reader has to check when asking why something was or was not cached.\n */\nfunction isCacheableReadOperation(operation: FrontendResourceConfiguration_Operation): boolean {\n const coreOperation = resolveEffectiveCoreOperationFromOperation(operation);\n return coreOperation === CoreResourceOperation.READ || coreOperation === CoreResourceOperation.LIST;\n}\n\nexport class WildoBackendHttpClient_Resources extends WildoBackendHttpClient {\n private resourcesRegistry: FrontendResourcesRegistry;\n private errorBuilder: ErrorBuilderFrontend;\n\n constructor(\n resourcesRegistry: FrontendResourcesRegistry,\n config: WildoBackendHttpClientConfig = {}\n ) {\n super(config);\n this.resourcesRegistry = resourcesRegistry;\n this.errorBuilder = new ErrorBuilderFrontend();\n }\n\n /**\n * Build a WildoError for frontend resource operations\n */\n private buildError(\n customMessageReference: ErrorCustomMessageReference,\n operationPathKey?: string,\n context?: Record<string, any>\n ): Error {\n const wildoError = this.errorBuilder.buildWildoError_Frontend(\n ErrorType.INTERNAL,\n { customMessageReference, operationPathKey, context }\n );\n // Attach the WildoError to the Error for downstream handling\n const error = new Error(customMessageReference);\n (error as any).wildoError = wildoError;\n return error;\n }\n\n /**\n * Execute a resource operation using operation path\n * @param operationPathKey - String representation of the operation path\n * @param parameters - Parameters needed for the operation\n * @param options - Additional request options\n */\n /**\n * The engine-wide read cache for resource operations.\n *\n * Held on this service because it is the one object both read paths reach, and because it must\n * outlive any React tree — a cache that died with a route would answer the question this exists\n * to answer (\"was this surface visited before?\") with \"no\" every time.\n */\n private readonly readCache = new ResourceReadCacheFrontendService();\n\n /** The cache tier, for the WebSocket layer to install coverage into and invalidate through. */\n public getReadCache(): ResourceReadCacheFrontendService {\n return this.readCache;\n }\n\n /**\n * The cache identity of a READ, and the scope rooms that would carry its invalidation.\n *\n * Called only for operations `isCacheableReadOperation` already admitted, so it answers the\n * narrower question: can this particular CALL be keyed, and what covers it?\n *\n * `null` means \"run it and cache nothing\" — for parameters that cannot be rendered into a stable\n * key (a cycle, a function in a filter), or for an operation carrying no primary scope. Neither is\n * an error, and neither invalidates anything: a read we cannot key must not evict a resource that\n * other readers are using.\n */\n private resolveCacheableRead(\n operationPathKey: string,\n operation: FrontendResourceConfiguration_Operation,\n parameters: ResourceOperationCallParameters,\n ): { key: string; resourceType: string; scopes: ResourceScopeRoomQualifier[] } | null {\n const resourceType = operation.resourceIdentifier as string;\n const key = renderResourceReadCacheKey(operationPathKey, parameters);\n if (key === null) return null;\n\n // The primary scope is carried on the OPERATION, which is the same object the URL was built\n // from — so there is no second lookup that could disagree with it.\n const primaryScope = operation.resourcePrimaryScope;\n if (!primaryScope) return null;\n\n /*\n * Scope ids come from the call's own contextual parameters, which is what the URL was built from\n * — so the rooms derived here are the rooms a mutation on this very path would emit into. Values\n * are narrowed to strings because a room id is a string; a numeric parameter is stringified\n * rather than dropped, since the backend's own context map is string-valued.\n */\n const contextResourceIdentifiers: Record<string, string> = {};\n for (const [name, value] of Object.entries(parameters.contextualParameters ?? {})) {\n if (typeof value === 'string') contextResourceIdentifiers[name] = value;\n else if (typeof value === 'number') contextResourceIdentifiers[name] = String(value);\n }\n\n /*\n * An APPLICATION-scoped resource's scope is AMBIENT, never addressed — no URL carries an\n * application id, so the loop above can never produce one and `deriveResourceScopeRoomQualifiers`\n * would fall through to whatever incidental `org`/`user` rooms the parameters imply.\n *\n * That is not a cosmetic miss. Measured 2026-09-03 (issue #283): the workbench subscribed to\n * `org` and `user` for `workbenchDomainResources` — an APPLICATION-scoped resource — and was\n * confirmed in both, while the companion published to the `app` room. Correct producer, correct\n * subscriber, different rooms, zero frames.\n */\n if (primaryScope === ResourcePrimaryScope.APPLICATION) {\n /*\n * Absent is TOLERATED, deliberately. Refusing to cache without it was tried and is strictly\n * worse: it disabled the tier for every APPLICATION-scoped resource wherever the ambient id is\n * not published, which is a regression in exchange for nothing. Without it the entry simply\n * derives whatever rooms its parameters imply and does not hear the application-room push —\n * the behaviour that existed before this change.\n */\n const applicationId = this.readCache.getApplicationId();\n if (applicationId) contextResourceIdentifiers.applicationId = applicationId;\n }\n\n return {\n key,\n resourceType,\n scopes: deriveResourceScopeRoomQualifiers(contextResourceIdentifiers, primaryScope),\n };\n }\n\n public async doOperation<TResponse = any>(\n operationPathKey: string,\n parameters: ResourceOperationCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n // Parse and validate operation path\n const operationPath = ResourcesConfig_OperationPathUtils.parseOperationPathKey(operationPathKey);\n \n // Find the operation in the registry\n const operation = this.findOperation(operationPath);\n if (!operation) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_OPERATION_NOT_FOUND,\n operationPathKey,\n { operationPathKey }\n );\n }\n\n /*\n * Read-through cache (issue #240).\n *\n * Placed here rather than in the React layer because BOTH read paths converge on this service —\n * `ResourceRegistryContext.doOperation` and, through the ref it injects, every RMM's\n * `HttpTransportAdapter`. Caching one layer up would leave the other uncached and the two\n * disagreeing about the same row.\n *\n * A MUTATION drops the resource's entries before it runs. The server echo is not enough on its\n * own: it arrives asynchronously and, for the initiator, may be filtered as its own event — so a\n * caller that writes and immediately re-reads would otherwise be served the value it just\n * replaced.\n */\n const isReadFamily = isCacheableReadOperation(operation);\n if (!isReadFamily) {\n // A MUTATION drops this resource's entries before it runs. The server echo is not enough on\n // its own: it arrives asynchronously and, for the initiator, may be filtered as its own event\n // — so a caller that writes and immediately re-reads would otherwise be served the value it\n // just replaced. A read we merely cannot KEY must not land here, or every such read would\n // evict the resource for everyone.\n this.readCache.invalidateResourceType(operation.resourceIdentifier as string);\n }\n\n const cacheable = isReadFamily\n ? this.resolveCacheableRead(operationPathKey, operation, parameters)\n : null;\n if (cacheable) {\n const cached = this.readCache.read(cacheable.key);\n if (cached !== undefined) {\n return structuredClone(cached) as TResponse;\n }\n }\n\n // Handle different operation types\n switch (operation.variantType) {\n case ResourceOperationVariantType.API_CALL:\n return this.executeApiCallOperation(operation, parameters, options).then((response) => {\n if (cacheable) {\n this.readCache.store(cacheable.key, response, cacheable.resourceType, cacheable.scopes);\n }\n return response;\n }) as Promise<TResponse>;\n \n case ResourceOperationVariantType.API_CALL_WITH_CALLBACK:\n return this.executeApiCallWithCallbackOperation(operation, parameters, options);\n \n default: {\n const _exhaustiveCheck: never = operation;\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_UNSUPPORTED_OPERATION_TYPE,\n operationPathKey,\n { operationPathKey }\n );\n }\n }\n }\n\n /**\n * Execute a search operation with additional search parameters\n * @param operationPathKey - String representation of the search operation path\n * @param parameters - Search parameters\n * @param options - Additional request options\n */\n public async executeSearchOperation<TResponse = any>(\n operationPathKey: string,\n parameters: ResourceSearchCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n // Parse and validate operation path\n const operationPath = ResourcesConfig_OperationPathUtils.parseOperationPathKey(operationPathKey);\n \n // Find the search operation\n const operation = this.findOperation(operationPath);\n if (!operation) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_OPERATION_NOT_FOUND,\n operationPathKey,\n { operationPathKey, operationType: 'search' }\n );\n }\n\n // Verify it carries SEARCH semantics, including custom search-like operations.\n if (resolveEffectiveCoreOperationFromOperation(operation) !== CoreResourceOperation.SEARCH) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_SEARCH_OPERATION_INVALID,\n operationPathKey,\n { operationPathKey, actualOperationIdentifier: operation.operationIdentifier }\n );\n }\n\n return this.executeSearchOperationInternal(operation, parameters, options);\n }\n\n /**\n * Select the appropriate response DTO based on dataMode\n * @param operation - The operation configuration\n * @param dataMode - The data mode (RAW, SUMMARY, CONTEXT)\n * @returns The selected Zod schema for validation, or null if no DTO is available\n */\n private selectResponseDto(\n operation: FrontendResourceConfiguration_Operation,\n dataMode?: DataMode\n ): z.ZodSchema<any> | null {\n const selected = ResourcesConfigOperationsDtosBuilderUtils.selectResponseDto(operation, dataMode);\n \n // Validate that the returned value is actually a Zod schema\n // If it's not a valid schema (undefined, null, or non-schema object), return null\n if (!selected || typeof selected !== 'object' || typeof selected.parse !== 'function') {\n return null;\n }\n \n return selected as z.ZodSchema<any>;\n }\n\n /**\n * Validate response data against the selected DTO\n * @param responseData - The response data to validate\n * @param schema - The Zod schema to validate against\n * @param operationPathKey - Optional operation path key for error context\n * @returns Validated response data\n * @throws Error if validation fails\n */\n private validateResponseData<TResponse>(\n responseData: any,\n schema: z.ZodSchema<any> | null,\n operationPathKey?: string\n ): TResponse {\n // If no schema is available, return data as-is (backward compatibility)\n if (!schema) {\n return responseData as TResponse;\n }\n\n try {\n const parsed = schema.parse(responseData) as TResponse;\n // `_version` (optimistic-locking counter) and `_field_meta` (CRDT causality) are engine\n // metadata NOT declared in any resource schema, so this `schema.parse` strips them — the\n // symmetric client-side counterpart of the two backend parses (services-registry-handler\n // `transformOutput` + operation-response-serializer). They must survive: the Resource\n // Mutation Manager seeds its optimistic-locking version from the READ response\n // (`ResourceAutomaticDisplayer` → `rmm.setInitialState(row, row._version ?? 0)`) and echoes\n // it as `If-Match` on inline updates. Stripped here, the RMM seeds `0`, so every inline\n // update sends `If-Match: 0` and the server (at a real version) 409s permanently.\n WildoBackendHttpClient_Resources.reattachEngineMetadata(responseData, parsed);\n return parsed;\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_RESPONSE_VALIDATION_FAILED,\n operationPathKey,\n {\n validationErrors: error.issues,\n responseData: responseData\n }\n );\n }\n throw error;\n }\n }\n\n /**\n * Reattach engine metadata (`_version`, `_field_meta`) that a strict responseDto parse strips,\n * from the raw wire payload onto the parsed result. Recurses into flat arrays (LIST) and\n * `{ data: [...] }` paginated wrappers so every item keeps its optimistic-locking version.\n */\n private static reattachEngineMetadata(source: unknown, parsed: unknown): void {\n if (!source || typeof source !== 'object' || !parsed || typeof parsed !== 'object') return;\n\n if (Array.isArray(source) && Array.isArray(parsed)) {\n for (let i = 0; i < parsed.length; i++) {\n WildoBackendHttpClient_Resources.reattachEngineMetadata(source[i], parsed[i]);\n }\n return;\n }\n\n const sourceRecord = source as Record<string, unknown>;\n const parsedRecord = parsed as Record<string, unknown>;\n\n if (Array.isArray(sourceRecord.data) && Array.isArray(parsedRecord.data)) {\n const sourceItems = sourceRecord.data;\n const parsedItems = parsedRecord.data;\n for (let i = 0; i < parsedItems.length; i++) {\n WildoBackendHttpClient_Resources.reattachEngineMetadata(sourceItems[i], parsedItems[i]);\n }\n }\n\n for (const key of ['_field_meta', '_version'] as const) {\n if (sourceRecord[key] !== undefined && parsedRecord[key] === undefined) {\n parsedRecord[key] = sourceRecord[key];\n }\n }\n }\n\n /**\n * Find an operation in the registry based on operation path\n */\n private findOperation(operationPath: ResourceConfiguration_OperationPath<any, any>): FrontendResourceConfiguration_Operation | null {\n const resourceConfig = this.resourcesRegistry.resourceConfigurations[operationPath.resourceIdentifier];\n if (!resourceConfig) {\n return null;\n }\n\n // Find matching operation (using same logic as backend)\n const foundOp = resourceConfig.operations.find((op: any) => {\n const opPath = ResourcesConfig_OperationPathUtils.extractOperationPath(op);\n \n // Basic field matching\n if (opPath.operationIdentifier !== operationPath.operationIdentifier) return false;\n if (opPath.variantType !== operationPath.variantType) return false;\n \n // Match default/variant key\n if (operationPath.isOperationDefault) {\n if (!opPath.isOperationDefault) return false;\n } else {\n const expectedVariantKey = operationPath.variantKey;\n const actualVariantKey = opPath.variantKey;\n if ((actualVariantKey ?? undefined) !== (expectedVariantKey ?? undefined)) return false;\n }\n \n // For URL-bearing operations, match bulk flag (same logic as backend)\n // Normalize both to boolean: undefined/false ? false, true ? true\n if (\n opPath.variantType === ResourceOperationVariantType.API_CALL\n || opPath.variantType === ResourceOperationVariantType.API_CALL_WITH_CALLBACK\n ) {\n const opIsBulk = opPath.isBulkOperation === true;\n const pathIsBulk = operationPath.isBulkOperation === true;\n return opIsBulk === pathIsBulk;\n }\n \n return true;\n }) || null;\n \n return foundOp;\n }\n\n /**\n * Execute API_CALL operation\n */\n private async executeApiCallOperation<TResponse>(\n operation: FrontendResourceConfiguration_Operation,\n parameters: ResourceOperationCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n const targetDefaultFieldIdentifier =\n this.resourcesRegistry.resourceConfigurations[operation.resourceIdentifier]?.resourceFieldIdentifier ?? '';\n\n // Build URL from initiatorInfos and contextual parameters with deterministic selection\n const { url, missingParameters } = this.buildUrlFromInitiatorInfos(\n operation.initiatorInfos || [], \n parameters.contextualParameters,\n operation.resourceIdentifier,\n targetDefaultFieldIdentifier,\n parameters.parentResourcesRequirements\n );\n\n // Validate that all required parameters were provided\n if (missingParameters.length > 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n {\n reason: 'Missing required URL parameters',\n missingParameters,\n availableParameters: Object.keys(parameters.contextualParameters),\n url\n }\n );\n }\n\n // Build query parameters, including dataMode if specified\n const queryParams = { ...parameters.queryParameters };\n if (parameters.dataMode) {\n queryParams.dataMode = parameters.dataMode;\n }\n\n // Prepare request options with error handling context\n // The riskLevel from the operation affects how errors are handled globally\n const requestOptions: RequestOptions = {\n ...options,\n ...resolveOperationRequestTimeout(options, operation),\n params: queryParams,\n riskLevel: operation.riskLevel || ResourceOperationRiskLevel.MEDIUM,\n resourceType: operation.resourceIdentifier,\n operationIdentifier: String(operation.operationIdentifier),\n variantKey: operation.variantKey,\n isBulkOperation: operation.isBulkOperation,\n isOperationDefault: operation.isOperationDefault,\n loading: options?.loading ?? {\n tier: LoadingTier.COMPONENT,\n phase: LoadingPhase.INITIAL,\n },\n };\n\n // Execute based on HTTP method and validate response\n let responseData: any;\n switch (operation.httpVerb) {\n case HttpMethod.GET:\n responseData = await this.get<TResponse>(url, requestOptions);\n break;\n \n case HttpMethod.POST:\n responseData = await this.post<TResponse>(url, parameters.requestData, requestOptions);\n break;\n \n case HttpMethod.PUT:\n responseData = await this.put<TResponse>(url, parameters.requestData, requestOptions);\n break;\n \n case HttpMethod.DELETE:\n responseData = await this.delete<TResponse>(url, requestOptions);\n break;\n \n case HttpMethod.PATCH:\n responseData = await this.patch<TResponse>(url, parameters.requestData, requestOptions);\n break;\n \n default:\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_UNSUPPORTED_HTTP_METHOD,\n undefined,\n { httpMethod: operation.httpVerb, url }\n );\n }\n\n // Select and validate response DTO\n const responseDto = this.selectResponseDto(operation, parameters.dataMode);\n return this.validateResponseData<TResponse>(responseData, responseDto);\n }\n\n /**\n * Execute API_CALL_WITH_CALLBACK operation\n */\n private async executeApiCallWithCallbackOperation<TResponse>(\n operation: FrontendResourceConfiguration_Operation,\n parameters: ResourceOperationCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n // Determine which URL to use based on callType\n const callType = parameters.callType || 'primaryCall';\n const targetDefaultFieldIdentifier =\n this.resourcesRegistry.resourceConfigurations[operation.resourceIdentifier]?.resourceFieldIdentifier ?? '';\n \n if (callType === 'callbackCall') {\n // Use callback URL from initiatorInfos\n const { url, missingParameters } = this.buildCallbackUrlFromInitiatorInfos(\n operation.initiatorInfos || [],\n parameters.contextualParameters,\n operation.resourceIdentifier,\n targetDefaultFieldIdentifier,\n parameters.parentResourcesRequirements,\n );\n \n // Validate that all required parameters were provided\n if (missingParameters.length > 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n {\n reason: 'Missing required callback URL parameters',\n missingParameters,\n availableParameters: Object.keys(parameters.contextualParameters),\n url\n }\n );\n }\n \n const requestOptions: RequestOptions = {\n ...options,\n ...resolveOperationRequestTimeout(options, operation),\n params: parameters.queryParameters,\n riskLevel: operation.riskLevel || ResourceOperationRiskLevel.MEDIUM,\n resourceType: operation.resourceIdentifier,\n operationIdentifier: String(operation.operationIdentifier),\n variantKey: operation.variantKey,\n isBulkOperation: operation.isBulkOperation,\n isOperationDefault: operation.isOperationDefault,\n loading: options?.loading ?? {\n tier: LoadingTier.COMPONENT,\n phase: LoadingPhase.INITIAL,\n },\n };\n\n // Callback calls are typically POST\n const responseData = await this.post<TResponse>(url, parameters.requestData, requestOptions);\n \n // Select and validate response DTO\n const responseDto = this.selectResponseDto(operation, parameters.dataMode);\n return this.validateResponseData<TResponse>(responseData, responseDto);\n } else {\n // Use primary URL (same as regular API_CALL, which already validates)\n return this.executeApiCallOperation(operation, parameters, options);\n }\n }\n\n /**\n * Execute search operation with search-specific parameters.\n * Operation is typed as FrontendResourceConfiguration_Operation; at runtime it is always\n * a SEARCH operation (verified by caller) with flattened collection-view fields.\n */\n private async executeSearchOperationInternal<TResponse>(\n operation: FrontendResourceConfiguration_Operation,\n parameters: ResourceSearchCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n const op = operation as {\n initiatorInfos?: ResourceConfiguration_Operation_UrlInitiatorInfo[];\n filterFields?: Record<string, unknown>;\n maxPaginatedResultPerPageLimit?: number;\n riskLevel?: ResourceOperationRiskLevel;\n clientRequestTimeoutMs?: number;\n resourceIdentifier?: string;\n operationIdentifier?: string;\n };\n const targetResourceType = String(op.resourceIdentifier) as ResourceType;\n const targetDefaultFieldIdentifier =\n this.resourcesRegistry.resourceConfigurations[targetResourceType]?.resourceFieldIdentifier ?? '';\n\n // Build URL from initiatorInfos with deterministic selection\n const { url, missingParameters } = this.buildUrlFromInitiatorInfos(\n op.initiatorInfos || [],\n parameters.contextualParameters,\n targetResourceType,\n targetDefaultFieldIdentifier,\n parameters.parentResourcesRequirements\n );\n \n // Validate that all required parameters were provided\n if (missingParameters.length > 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n {\n reason: 'Missing required URL parameters',\n missingParameters,\n availableParameters: Object.keys(parameters.contextualParameters),\n url\n }\n );\n }\n\n // Build search query parameters\n const searchParams: Record<string, any> = {\n ...parameters.queryParameters\n };\n\n // Add dataMode if specified (not RAW)\n if (parameters.dataMode && parameters.dataMode !== DataMode.RAW) {\n searchParams.dataMode = parameters.dataMode;\n }\n\n // Add search query if provided\n if (parameters.searchQuery) {\n searchParams.q = parameters.searchQuery;\n }\n\n // Add filters if provided\n if (parameters.filters && op.filterFields) {\n Object.entries(parameters.filters).forEach(([key, value]) => {\n if (op.filterFields![key]) {\n searchParams[key] = value;\n }\n });\n }\n\n // Add sorting if provided\n if (parameters.sort && parameters.sort.length > 0) {\n searchParams.sort = parameters.sort.map(s => `${s.field}:${s.direction}`).join(',');\n }\n\n // Add pagination if provided\n if (parameters.pagination) {\n searchParams.page = parameters.pagination.page;\n const maxLimit = op.maxPaginatedResultPerPageLimit ?? 50;\n searchParams.limit = Math.min(parameters.pagination.limit, maxLimit);\n }\n\n const requestOptions: RequestOptions = {\n ...options,\n ...resolveOperationRequestTimeout(options, op),\n params: searchParams,\n riskLevel: op.riskLevel || ResourceOperationRiskLevel.MEDIUM,\n resourceType: op.resourceIdentifier,\n operationIdentifier: String(op.operationIdentifier),\n variantKey: operation.variantKey,\n isBulkOperation: operation.isBulkOperation,\n isOperationDefault: operation.isOperationDefault,\n loading: options?.loading ?? {\n tier: LoadingTier.COMPONENT,\n phase: LoadingPhase.INITIAL,\n },\n };\n\n // Search operations are always GET\n const responseData = await this.get<TResponse>(url, requestOptions);\n\n // Select and validate response DTO\n const responseDto = this.selectResponseDto(operation, parameters.dataMode);\n return this.validateResponseData<TResponse>(responseData, responseDto);\n }\n\n /**\n * Select the best matching initiatorInfo based on context.\n *\n * The deterministic selection algorithm lives in\n * `FrontendResourceUtils.selectOperationUrlInitiatorInfo` — shared with\n * non-transport consumers (e.g. the filters layer derives URL-pinned filter\n * fields from the same selection). This wrapper owns only the transport\n * error semantics: an unsatisfiable selection is a hard\n * FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE failure here.\n */\n private selectInitiatorInfo(\n initiatorInfos: ResourceConfiguration_Operation_UrlInitiatorInfo[],\n contextualParameters: Record<string, ResourceContextualParameterValue>,\n targetResourceType: ResourceType,\n targetDefaultFieldIdentifier: string,\n parentResourcesRequirements?: FrontendResource_ParentResourceRequirement[]\n ): ResourceConfiguration_Operation_UrlInitiatorInfo {\n\n if (initiatorInfos.length === 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n { reason: 'No initiator infos available for this operation' }\n );\n }\n\n const selected = FrontendResourceUtils.selectOperationUrlInitiatorInfo({\n initiatorInfos,\n contextualParameters,\n targetResourceType,\n targetDefaultFieldIdentifier,\n parentResourcesRequirements,\n });\n\n if (!selected) {\n const available = Object.keys(contextualParameters).join(', ');\n const required = initiatorInfos.map(i =>\n i.parameters.map(p => p.fieldIdentifier).join(', ')\n ).join(' OR ');\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n { availableParams: available, requiredParams: required }\n );\n }\n\n return selected;\n }\n\n /**\n * Build URL from initiator infos and contextual parameters.\n * Uses deterministic selection algorithm with parentResourcesRequirements.\n */\n private buildUrlFromInitiatorInfos(\n initiatorInfos: ResourceConfiguration_Operation_UrlInitiatorInfo[],\n contextualParameters: Record<string, ResourceContextualParameterValue>,\n targetResourceType: ResourceType,\n targetDefaultFieldIdentifier: string,\n parentResourcesRequirements?: FrontendResource_ParentResourceRequirement[]\n ): UrlBuildResult {\n const selected = this.selectInitiatorInfo(\n initiatorInfos, \n contextualParameters, \n targetResourceType,\n targetDefaultFieldIdentifier,\n parentResourcesRequirements\n );\n \n return this.buildUrlFromInitiatorInfo(selected, contextualParameters);\n }\n\n /**\n * Build callback URL from initiator infos\n */\n private buildCallbackUrlFromInitiatorInfos(\n initiatorInfos: ResourceConfiguration_Operation_UrlInitiatorInfo[],\n contextualParameters: Record<string, ResourceContextualParameterValue>,\n targetResourceType: ResourceType,\n targetDefaultFieldIdentifier: string,\n parentResourcesRequirements?: FrontendResource_ParentResourceRequirement[]\n ): UrlBuildResult {\n if (initiatorInfos.length === 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_CALLBACK_URL,\n undefined,\n { reason: 'No initiator infos available for callback operation' }\n );\n }\n\n // Reuse the same candidate-selection semantics as the primary URL path,\n // but constrain the pool to callback-capable initiators.\n const callbackCandidates = initiatorInfos.filter((info) => info.urlCallback);\n const callbackInitiator = callbackCandidates.length > 0\n ? this.selectInitiatorInfo(\n callbackCandidates,\n contextualParameters,\n targetResourceType,\n targetDefaultFieldIdentifier,\n parentResourcesRequirements,\n )\n : undefined;\n if (!callbackInitiator) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_CALLBACK_URL,\n undefined,\n { reason: 'No callback URL defined in any initiator info' }\n );\n }\n\n // Build callback URL\n let url = callbackInitiator.urlCallback!;\n const missingParameters: string[] = [];\n\n // Replace URL parameters\n // Support both {fieldIdentifier} (backend style) and :fieldIdentifier (React Router style)\n for (const param of callbackInitiator.parameters) {\n const paramValue = contextualParameters[param.fieldIdentifier];\n if (isScalarContextualParameterValue(paramValue)) {\n const paramValueStr = String(paramValue);\n // Replace {fieldIdentifier} format (backend style)\n url = url.replace(`{${param.fieldIdentifier}}`, paramValueStr);\n // Replace :fieldIdentifier format (React Router style) - use word boundary to avoid partial matches\n const colonRegex = new RegExp(`:${param.fieldIdentifier.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?=[/\\\\?]|$)`, 'g');\n url = url.replace(colonRegex, paramValueStr);\n } else {\n missingParameters.push(param.fieldIdentifier);\n }\n }\n\n return { url, missingParameters };\n }\n\n /**\n * Build URL from a single initiator info\n */\n private buildUrlFromInitiatorInfo(\n initiatorInfo: ResourceConfiguration_Operation_UrlInitiatorInfo,\n contextualParameters: Record<string, ResourceContextualParameterValue>\n ): UrlBuildResult {\n let url = initiatorInfo.url;\n const missingParameters: string[] = [];\n\n // Replace URL parameters with contextual values\n // Support both {fieldIdentifier} (backend style) and :fieldIdentifier (React Router style)\n for (const param of initiatorInfo.parameters) {\n const paramValue = contextualParameters[param.fieldIdentifier];\n if (isScalarContextualParameterValue(paramValue)) {\n const paramValueStr = String(paramValue);\n // Replace {fieldIdentifier} format (backend style)\n url = url.replace(`{${param.fieldIdentifier}}`, paramValueStr);\n // Replace :fieldIdentifier format (React Router style) - use word boundary to avoid partial matches\n const colonRegex = new RegExp(`:${param.fieldIdentifier.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?=[/\\\\?]|$)`, 'g');\n url = url.replace(colonRegex, paramValueStr);\n } else {\n missingParameters.push(param.fieldIdentifier);\n }\n }\n\n return { url, missingParameters };\n }\n\n /**\n * Get available operation paths from the registry\n */\n public getAvailableOperationPaths(): string[] {\n const operationPaths: string[] = [];\n\n for (const [resourceType, resourceConfig] of Object.entries(this.resourcesRegistry.resourceConfigurations)) {\n const config = resourceConfig as AnyFrontendResourceConfiguration;\n for (const operation of config.operations) {\n const operationPath = ResourcesConfig_OperationPathUtils.extractOperationPath(operation);\n const pathKey = ResourcesConfig_OperationPathUtils.createOperationPathKey(operationPath);\n operationPaths.push(pathKey);\n }\n }\n\n return operationPaths;\n }\n\n /**\n * Get operation details for debugging\n */\n public getOperationDetails(operationPathKey: string): FrontendResourceConfiguration_Operation | null {\n const operationPath = ResourcesConfig_OperationPathUtils.parseOperationPathKey(operationPathKey);\n return this.findOperation(operationPath);\n }\n}\n\n// Note: No singleton export - this class should only be instantiated through ResourceRepositoryContext\n"]}
|
|
1
|
+
{"version":3,"file":"wildo-http-client-resources.frontend.service.js","sourceRoot":"","sources":["../../../../src/core/requests/wildo-http-client-resources.frontend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WildoBackendHttpClient_Resources\n * Specialized HTTP client for resource-based operations (CRUD)\n * Extends base WildoBackendHttpClient with resource-specific functionality\n */\n\nimport { z } from 'zod';\nimport { WildoBackendHttpClient, WildoBackendHttpClientConfig, RequestOptions } from './wildo-http-client.frontend.service';\n\n/**\n * The per-request timeout for one operation dispatch — the ONE seam all three requestOptions\n * assemblies in this file (api-call, api-call-with-callback, search) route through, so a\n * long-running variant behaves the same through every dispatch shape and a fourth assembly cannot\n * silently skip the rule (issue #237; invariant-call-site-enumeration: prefer a shared predicate\n * over N hand-applied spreads).\n *\n * Precedence: caller-supplied `options.timeout` wins; else the variant's declared\n * `clientRequestTimeoutMs`; else empty — the client's instance default applies.\n */\nexport function resolveOperationRequestTimeout(\n options: RequestOptions | undefined,\n operation: { clientRequestTimeoutMs?: number },\n): { timeout: number } | Record<string, never> {\n if (options?.timeout !== undefined) return {}; // already in the caller's spread\n if (operation.clientRequestTimeoutMs !== undefined) return { timeout: operation.clientRequestTimeoutMs };\n return {};\n}\nimport {\n ResourceConfiguration_Operation_UrlInitiatorInfo,\n ResourceConfiguration_Operation_UrlParameterInfo,\n ResourceConfiguration_OperationPath,\n ResourcesConfig_OperationPathUtils,\n ResourceOperationVariantType,\n HttpMethod,\n ErrorType,\n ErrorCustomMessageReference,\n DataMode,\n CoreResourceOperation,\n ResourcesConfigOperationsDtosBuilderUtils,\n ResourceOperationRiskLevel,\n type Resources_PaginationRequest,\n type ResourceType,\n} from '@wildo-ai/saas-models';\nimport type { FrontendResource_ParentResourceRequirement } from '~wildo-frontend-lib/core/resources/resource-path.frontend.schemas';\nimport type {\n FrontendResourcesRegistry,\n AnyFrontendResourceConfiguration,\n FrontendResourceConfiguration_Operation,\n} from '~wildo-frontend-lib/core/resources/resources.frontend.schemas';\nimport { ErrorBuilderFrontend } from '~wildo-frontend-lib/core/errors/errors-builder.frontend.services';\nimport { LoadingTier, LoadingPhase } from '~wildo-frontend-lib/core/loading/loading-types.frontend.schemas';\nimport { FrontendResourceUtils } from '~wildo-frontend-lib/core/resources/frontend-resource.utils';\nimport { resolveEffectiveCoreOperationFromOperation } from '~wildo-frontend-lib/core/resources/operation-semantics.frontend.utils';\nimport {\n ResourceReadCacheFrontendService,\n renderResourceReadCacheKey,\n} from '~wildo-frontend-lib/core/resources/resource-read-cache.frontend.service';\nimport { deriveResourceScopeRoomQualifiers, ResourcePrimaryScope } from '@wildo-ai/saas-models';\nimport type { ResourceScopeRoomQualifier } from '@wildo-ai/saas-models';\n\n/**\n * Parameters needed to execute a resource operation\n */\nexport type ResourceContextualParameterValue = string | number | string[];\n\nfunction isScalarContextualParameterValue(\n value: ResourceContextualParameterValue | undefined\n): value is string | number {\n return typeof value === 'string' || typeof value === 'number';\n}\n\nexport interface ResourceOperationCallParameters {\n /** Values for URL parameters (matching initiator.parameters) */\n contextualParameters: Record<string, ResourceContextualParameterValue>;\n /** Request body data (for POST/PUT operations) */\n requestData?: any;\n /** Query parameters (for search operations and GET requests) */\n queryParameters?: Record<string, any>;\n /** For callback operations: 'primaryCall' | 'callbackCall' */\n callType?: 'primaryCall' | 'callbackCall';\n /** \n * Parent resource requirements for deterministic URL selection.\n * Used to select the correct endpoint when multiple URLs are available.\n * Should be passed from resourceContext.parentResourcesRequirements.\n */\n parentResourcesRequirements?: FrontendResource_ParentResourceRequirement[];\n /**\n * Data mode controlling fields returned and population behavior.\n * - RAW: All stored fields, no population (default)\n * - SUMMARY: Summary fields only, populate isSummaryField({ populate: true }) FKs\n * - CONTEXT: All fields, populate based on contextPolicy\n */\n dataMode?: DataMode;\n}\n\n/**\n * Search-specific parameters extending base operation parameters\n */\nexport interface ResourceSearchCallParameters extends ResourceOperationCallParameters {\n /** Search query string */\n searchQuery?: string;\n /** Filter parameters */\n filters?: Record<string, any>;\n /** Sort configuration */\n sort?: { field: string; direction: 'asc' | 'desc' }[];\n /** Pagination */\n pagination?: Resources_PaginationRequest;\n // Note: dataMode is inherited from ResourceOperationCallParameters\n}\n\n/**\n * Result of URL building process\n */\ninterface UrlBuildResult {\n url: string;\n missingParameters: string[];\n}\n\n/**\n * Specialized HTTP client for resource-based operations\n * Should only be used through ResourceRepositoryContext\n */\n/**\n * Whether this operation READS, in the sense that its result is a projection of stored rows.\n *\n * Module-scoped rather than a method because it is a pure question about the operation, and because\n * it is the predicate a reader has to check when asking why something was or was not cached.\n */\nfunction isCacheableReadOperation(operation: FrontendResourceConfiguration_Operation): boolean {\n const coreOperation = resolveEffectiveCoreOperationFromOperation(operation);\n return coreOperation === CoreResourceOperation.READ\n || coreOperation === CoreResourceOperation.LIST\n || coreOperation === CoreResourceOperation.SEARCH;\n}\n\nexport class WildoBackendHttpClient_Resources extends WildoBackendHttpClient {\n private resourcesRegistry: FrontendResourcesRegistry;\n private errorBuilder: ErrorBuilderFrontend;\n\n constructor(\n resourcesRegistry: FrontendResourcesRegistry,\n config: WildoBackendHttpClientConfig = {}\n ) {\n super(config);\n this.resourcesRegistry = resourcesRegistry;\n this.errorBuilder = new ErrorBuilderFrontend();\n }\n\n /**\n * Build a WildoError for frontend resource operations\n */\n private buildError(\n customMessageReference: ErrorCustomMessageReference,\n operationPathKey?: string,\n context?: Record<string, any>\n ): Error {\n const wildoError = this.errorBuilder.buildWildoError_Frontend(\n ErrorType.INTERNAL,\n { customMessageReference, operationPathKey, context }\n );\n // Attach the WildoError to the Error for downstream handling\n const error = new Error(customMessageReference);\n (error as any).wildoError = wildoError;\n return error;\n }\n\n /**\n * Execute a resource operation using operation path\n * @param operationPathKey - String representation of the operation path\n * @param parameters - Parameters needed for the operation\n * @param options - Additional request options\n */\n /**\n * The engine-wide read cache for resource operations.\n *\n * Held on this service because it is the one object both read paths reach, and because it must\n * outlive any React tree — a cache that died with a route would answer the question this exists\n * to answer (\"was this surface visited before?\") with \"no\" every time.\n */\n private readonly readCache = new ResourceReadCacheFrontendService();\n\n /** The cache tier, for the WebSocket layer to install coverage into and invalidate through. */\n public getReadCache(): ResourceReadCacheFrontendService {\n return this.readCache;\n }\n\n /**\n * The cache identity of a READ, and the scope rooms that would carry its invalidation.\n *\n * Called only for operations `isCacheableReadOperation` already admitted — the two entry points\n * being `doOperation` and `executeSearchOperation`, which is the whole read family — so it answers\n * the narrower question: can this particular CALL be keyed, and what covers it?\n *\n * `null` means \"run it and cache nothing\" — for parameters that cannot be rendered into a stable\n * key (a cycle, a function in a filter), or for an operation carrying no primary scope. Neither is\n * an error, and neither invalidates anything: a read we cannot key must not evict a resource that\n * other readers are using.\n */\n private resolveCacheableRead(\n operationPathKey: string,\n operation: FrontendResourceConfiguration_Operation,\n parameters: ResourceOperationCallParameters,\n ): { key: string; resourceType: string; scopes: ResourceScopeRoomQualifier[] } | null {\n const resourceType = operation.resourceIdentifier as string;\n const key = renderResourceReadCacheKey(operationPathKey, parameters);\n if (key === null) return null;\n\n // The primary scope is carried on the OPERATION, which is the same object the URL was built\n // from — so there is no second lookup that could disagree with it.\n const primaryScope = operation.resourcePrimaryScope;\n if (!primaryScope) return null;\n\n /*\n * Scope ids come from the call's own contextual parameters, which is what the URL was built from\n * — so the rooms derived here are the rooms a mutation on this very path would emit into. Values\n * are narrowed to strings because a room id is a string; a numeric parameter is stringified\n * rather than dropped, since the backend's own context map is string-valued.\n */\n const contextResourceIdentifiers: Record<string, string> = {};\n for (const [name, value] of Object.entries(parameters.contextualParameters ?? {})) {\n if (typeof value === 'string') contextResourceIdentifiers[name] = value;\n else if (typeof value === 'number') contextResourceIdentifiers[name] = String(value);\n }\n\n /*\n * An APPLICATION-scoped resource's scope is AMBIENT, never addressed — no URL carries an\n * application id, so the loop above can never produce one and `deriveResourceScopeRoomQualifiers`\n * would fall through to whatever incidental `org`/`user` rooms the parameters imply.\n *\n * That is not a cosmetic miss. Measured 2026-09-03 (issue #283): the workbench subscribed to\n * `org` and `user` for `workbenchDomainResources` — an APPLICATION-scoped resource — and was\n * confirmed in both, while the companion published to the `app` room. Correct producer, correct\n * subscriber, different rooms, zero frames.\n */\n if (primaryScope === ResourcePrimaryScope.APPLICATION) {\n /*\n * Absent is TOLERATED, deliberately. Refusing to cache without it was tried and is strictly\n * worse: it disabled the tier for every APPLICATION-scoped resource wherever the ambient id is\n * not published, which is a regression in exchange for nothing. Without it the entry simply\n * derives whatever rooms its parameters imply and does not hear the application-room push —\n * the behaviour that existed before this change.\n */\n const applicationId = this.readCache.getApplicationId();\n if (applicationId) contextResourceIdentifiers.applicationId = applicationId;\n }\n\n return {\n key,\n resourceType,\n scopes: deriveResourceScopeRoomQualifiers(contextResourceIdentifiers, primaryScope),\n };\n }\n\n public async doOperation<TResponse = any>(\n operationPathKey: string,\n parameters: ResourceOperationCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n // Parse and validate operation path\n const operationPath = ResourcesConfig_OperationPathUtils.parseOperationPathKey(operationPathKey);\n \n // Find the operation in the registry\n const operation = this.findOperation(operationPath);\n if (!operation) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_OPERATION_NOT_FOUND,\n operationPathKey,\n { operationPathKey }\n );\n }\n\n /*\n * Read-through cache (issue #240).\n *\n * Placed here rather than in the React layer because BOTH read paths converge on this service —\n * `ResourceRegistryContext.doOperation` and, through the ref it injects, every RMM's\n * `HttpTransportAdapter`. Caching one layer up would leave the other uncached and the two\n * disagreeing about the same row.\n *\n * A MUTATION drops the resource's entries before it runs. The server echo is not enough on its\n * own: it arrives asynchronously and, for the initiator, may be filtered as its own event — so a\n * caller that writes and immediately re-reads would otherwise be served the value it just\n * replaced.\n */\n const isReadFamily = isCacheableReadOperation(operation);\n if (!isReadFamily) {\n // A MUTATION drops this resource's entries before it runs. The server echo is not enough on\n // its own: it arrives asynchronously and, for the initiator, may be filtered as its own event\n // — so a caller that writes and immediately re-reads would otherwise be served the value it\n // just replaced. A read we merely cannot KEY must not land here, or every such read would\n // evict the resource for everyone.\n this.readCache.invalidateResourceType(operation.resourceIdentifier as string);\n }\n\n const cacheable = isReadFamily\n ? this.resolveCacheableRead(operationPathKey, operation, parameters)\n : null;\n if (cacheable) {\n const cached = this.readCache.read(cacheable.key);\n if (cached !== undefined) {\n return structuredClone(cached) as TResponse;\n }\n }\n\n // Handle different operation types\n switch (operation.variantType) {\n case ResourceOperationVariantType.API_CALL:\n return this.executeApiCallOperation(operation, parameters, options).then((response) => {\n if (cacheable) {\n this.readCache.store(cacheable.key, response, cacheable.resourceType, cacheable.scopes);\n }\n return response;\n }) as Promise<TResponse>;\n \n case ResourceOperationVariantType.API_CALL_WITH_CALLBACK:\n return this.executeApiCallWithCallbackOperation(operation, parameters, options);\n \n default: {\n const _exhaustiveCheck: never = operation;\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_UNSUPPORTED_OPERATION_TYPE,\n operationPathKey,\n { operationPathKey }\n );\n }\n }\n }\n\n /**\n * Execute a search operation with additional search parameters\n * @param operationPathKey - String representation of the search operation path\n * @param parameters - Search parameters\n * @param options - Additional request options\n */\n public async executeSearchOperation<TResponse = any>(\n operationPathKey: string,\n parameters: ResourceSearchCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n // Parse and validate operation path\n const operationPath = ResourcesConfig_OperationPathUtils.parseOperationPathKey(operationPathKey);\n \n // Find the search operation\n const operation = this.findOperation(operationPath);\n if (!operation) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_OPERATION_NOT_FOUND,\n operationPathKey,\n { operationPathKey, operationType: 'search' }\n );\n }\n\n // Verify it carries SEARCH semantics, including custom search-like operations.\n if (resolveEffectiveCoreOperationFromOperation(operation) !== CoreResourceOperation.SEARCH) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_SEARCH_OPERATION_INVALID,\n operationPathKey,\n { operationPathKey, actualOperationIdentifier: operation.operationIdentifier }\n );\n }\n\n /*\n * The SAME read-through cache `doOperation` applies, because a SEARCH is the same kind of read.\n *\n * ## Why SEARCH was uncached, and why that was an accident rather than a decision\n *\n * `ResourceRegistryContext.doOperation` routes a SEARCH here instead of to `doOperation`, and the\n * cache block lived only there — so a collection surface served by a SEARCH got none of the tier,\n * silently, with no diagnostic and nothing in the tier's own prose saying so. Nothing about SEARCH\n * justified the exclusion: it is a projection of stored rows, it derives its scope rooms from the\n * same contextual parameters and primary scope as a LIST on the same resource, and it is\n * invalidated by the same per-resource-type channel. The asymmetry was an artefact of the routing.\n *\n * ## The key, and the churn question that decided it\n *\n * `renderResourceReadCacheKey` is total over any parameters object — sorted keys, cycle-safe,\n * refusing what it cannot render — so the search body varies the key exactly as page, limit, sort\n * and filter already do. The real objection to caching a search is CARDINALITY: a typeahead\n * produces a distinct key per query and could evict everything else. It does not, and the tier\n * already says why — eviction is least-recently-USED, \"so an entry a surface keeps reading\n * survives while a page visited once does not\". A one-shot query evicts itself first.\n *\n * ## What did NOT change\n *\n * Coverage. A SEARCH entry is servable only while every room it belongs to is joined and\n * CONFIRMED, exactly like a LIST, so the safety contract is untouched and an unscoped search is\n * still refused at the door by `store()`.\n *\n * Both entry points gate on the SAME `isCacheableReadOperation`, and that is not decoration. The\n * first version of this called `resolveCacheableRead` directly here, which made the predicate\n * INERT on the search path — two mechanisms deciding one question, with the one a reader would\n * check having no effect on the path they were reading about. A mutation removing SEARCH from the\n * predicate changed nothing, which is how that was found.\n *\n * Widening the shared predicate rather than adding a second one also removes a latent defect on\n * the other path: a SEARCH reaching `doOperation` was previously NOT read-family, so it took the\n * mutation branch and INVALIDATED its own resource type. Unreachable through the registry today,\n * and wrong wherever it became reachable.\n */\n const cacheable = isCacheableReadOperation(operation)\n ? this.resolveCacheableRead(operationPathKey, operation, parameters)\n : null;\n if (cacheable) {\n const cached = this.readCache.read(cacheable.key);\n if (cached !== undefined) return structuredClone(cached) as TResponse;\n }\n\n const response = await this.executeSearchOperationInternal<TResponse>(operation, parameters, options);\n if (cacheable) {\n this.readCache.store(cacheable.key, response, cacheable.resourceType, cacheable.scopes);\n }\n return response;\n }\n\n /**\n * Select the appropriate response DTO based on dataMode\n * @param operation - The operation configuration\n * @param dataMode - The data mode (RAW, SUMMARY, CONTEXT)\n * @returns The selected Zod schema for validation, or null if no DTO is available\n */\n private selectResponseDto(\n operation: FrontendResourceConfiguration_Operation,\n dataMode?: DataMode\n ): z.ZodSchema<any> | null {\n const selected = ResourcesConfigOperationsDtosBuilderUtils.selectResponseDto(operation, dataMode);\n \n // Validate that the returned value is actually a Zod schema\n // If it's not a valid schema (undefined, null, or non-schema object), return null\n if (!selected || typeof selected !== 'object' || typeof selected.parse !== 'function') {\n return null;\n }\n \n return selected as z.ZodSchema<any>;\n }\n\n /**\n * Validate response data against the selected DTO\n * @param responseData - The response data to validate\n * @param schema - The Zod schema to validate against\n * @param operationPathKey - Optional operation path key for error context\n * @returns Validated response data\n * @throws Error if validation fails\n */\n private validateResponseData<TResponse>(\n responseData: any,\n schema: z.ZodSchema<any> | null,\n operationPathKey?: string\n ): TResponse {\n // If no schema is available, return data as-is (backward compatibility)\n if (!schema) {\n return responseData as TResponse;\n }\n\n try {\n const parsed = schema.parse(responseData) as TResponse;\n // `_version` (optimistic-locking counter) and `_field_meta` (CRDT causality) are engine\n // metadata NOT declared in any resource schema, so this `schema.parse` strips them — the\n // symmetric client-side counterpart of the two backend parses (services-registry-handler\n // `transformOutput` + operation-response-serializer). They must survive: the Resource\n // Mutation Manager seeds its optimistic-locking version from the READ response\n // (`ResourceAutomaticDisplayer` → `rmm.setInitialState(row, row._version ?? 0)`) and echoes\n // it as `If-Match` on inline updates. Stripped here, the RMM seeds `0`, so every inline\n // update sends `If-Match: 0` and the server (at a real version) 409s permanently.\n WildoBackendHttpClient_Resources.reattachEngineMetadata(responseData, parsed);\n return parsed;\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_RESPONSE_VALIDATION_FAILED,\n operationPathKey,\n {\n validationErrors: error.issues,\n responseData: responseData\n }\n );\n }\n throw error;\n }\n }\n\n /**\n * Reattach engine metadata (`_version`, `_field_meta`) that a strict responseDto parse strips,\n * from the raw wire payload onto the parsed result. Recurses into flat arrays (LIST) and\n * `{ data: [...] }` paginated wrappers so every item keeps its optimistic-locking version.\n */\n private static reattachEngineMetadata(source: unknown, parsed: unknown): void {\n if (!source || typeof source !== 'object' || !parsed || typeof parsed !== 'object') return;\n\n if (Array.isArray(source) && Array.isArray(parsed)) {\n for (let i = 0; i < parsed.length; i++) {\n WildoBackendHttpClient_Resources.reattachEngineMetadata(source[i], parsed[i]);\n }\n return;\n }\n\n const sourceRecord = source as Record<string, unknown>;\n const parsedRecord = parsed as Record<string, unknown>;\n\n if (Array.isArray(sourceRecord.data) && Array.isArray(parsedRecord.data)) {\n const sourceItems = sourceRecord.data;\n const parsedItems = parsedRecord.data;\n for (let i = 0; i < parsedItems.length; i++) {\n WildoBackendHttpClient_Resources.reattachEngineMetadata(sourceItems[i], parsedItems[i]);\n }\n }\n\n for (const key of ['_field_meta', '_version'] as const) {\n if (sourceRecord[key] !== undefined && parsedRecord[key] === undefined) {\n parsedRecord[key] = sourceRecord[key];\n }\n }\n }\n\n /**\n * Find an operation in the registry based on operation path\n */\n private findOperation(operationPath: ResourceConfiguration_OperationPath<any, any>): FrontendResourceConfiguration_Operation | null {\n const resourceConfig = this.resourcesRegistry.resourceConfigurations[operationPath.resourceIdentifier];\n if (!resourceConfig) {\n return null;\n }\n\n // Find matching operation (using same logic as backend)\n const foundOp = resourceConfig.operations.find((op: any) => {\n const opPath = ResourcesConfig_OperationPathUtils.extractOperationPath(op);\n \n // Basic field matching\n if (opPath.operationIdentifier !== operationPath.operationIdentifier) return false;\n if (opPath.variantType !== operationPath.variantType) return false;\n \n // Match default/variant key\n if (operationPath.isOperationDefault) {\n if (!opPath.isOperationDefault) return false;\n } else {\n const expectedVariantKey = operationPath.variantKey;\n const actualVariantKey = opPath.variantKey;\n if ((actualVariantKey ?? undefined) !== (expectedVariantKey ?? undefined)) return false;\n }\n \n // For URL-bearing operations, match bulk flag (same logic as backend)\n // Normalize both to boolean: undefined/false ? false, true ? true\n if (\n opPath.variantType === ResourceOperationVariantType.API_CALL\n || opPath.variantType === ResourceOperationVariantType.API_CALL_WITH_CALLBACK\n ) {\n const opIsBulk = opPath.isBulkOperation === true;\n const pathIsBulk = operationPath.isBulkOperation === true;\n return opIsBulk === pathIsBulk;\n }\n \n return true;\n }) || null;\n \n return foundOp;\n }\n\n /**\n * Execute API_CALL operation\n */\n private async executeApiCallOperation<TResponse>(\n operation: FrontendResourceConfiguration_Operation,\n parameters: ResourceOperationCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n const targetDefaultFieldIdentifier =\n this.resourcesRegistry.resourceConfigurations[operation.resourceIdentifier]?.resourceFieldIdentifier ?? '';\n\n // Build URL from initiatorInfos and contextual parameters with deterministic selection\n const { url, missingParameters } = this.buildUrlFromInitiatorInfos(\n operation.initiatorInfos || [], \n parameters.contextualParameters,\n operation.resourceIdentifier,\n targetDefaultFieldIdentifier,\n parameters.parentResourcesRequirements\n );\n\n // Validate that all required parameters were provided\n if (missingParameters.length > 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n {\n reason: 'Missing required URL parameters',\n missingParameters,\n availableParameters: Object.keys(parameters.contextualParameters),\n url\n }\n );\n }\n\n // Build query parameters, including dataMode if specified\n const queryParams = { ...parameters.queryParameters };\n if (parameters.dataMode) {\n queryParams.dataMode = parameters.dataMode;\n }\n\n // Prepare request options with error handling context\n // The riskLevel from the operation affects how errors are handled globally\n const requestOptions: RequestOptions = {\n ...options,\n ...resolveOperationRequestTimeout(options, operation),\n params: queryParams,\n riskLevel: operation.riskLevel || ResourceOperationRiskLevel.MEDIUM,\n resourceType: operation.resourceIdentifier,\n operationIdentifier: String(operation.operationIdentifier),\n variantKey: operation.variantKey,\n isBulkOperation: operation.isBulkOperation,\n isOperationDefault: operation.isOperationDefault,\n loading: options?.loading ?? {\n tier: LoadingTier.COMPONENT,\n phase: LoadingPhase.INITIAL,\n },\n };\n\n // Execute based on HTTP method and validate response\n let responseData: any;\n switch (operation.httpVerb) {\n case HttpMethod.GET:\n responseData = await this.get<TResponse>(url, requestOptions);\n break;\n \n case HttpMethod.POST:\n responseData = await this.post<TResponse>(url, parameters.requestData, requestOptions);\n break;\n \n case HttpMethod.PUT:\n responseData = await this.put<TResponse>(url, parameters.requestData, requestOptions);\n break;\n \n case HttpMethod.DELETE:\n responseData = await this.delete<TResponse>(url, requestOptions);\n break;\n \n case HttpMethod.PATCH:\n responseData = await this.patch<TResponse>(url, parameters.requestData, requestOptions);\n break;\n \n default:\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_UNSUPPORTED_HTTP_METHOD,\n undefined,\n { httpMethod: operation.httpVerb, url }\n );\n }\n\n // Select and validate response DTO\n const responseDto = this.selectResponseDto(operation, parameters.dataMode);\n return this.validateResponseData<TResponse>(responseData, responseDto);\n }\n\n /**\n * Execute API_CALL_WITH_CALLBACK operation\n */\n private async executeApiCallWithCallbackOperation<TResponse>(\n operation: FrontendResourceConfiguration_Operation,\n parameters: ResourceOperationCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n // Determine which URL to use based on callType\n const callType = parameters.callType || 'primaryCall';\n const targetDefaultFieldIdentifier =\n this.resourcesRegistry.resourceConfigurations[operation.resourceIdentifier]?.resourceFieldIdentifier ?? '';\n \n if (callType === 'callbackCall') {\n // Use callback URL from initiatorInfos\n const { url, missingParameters } = this.buildCallbackUrlFromInitiatorInfos(\n operation.initiatorInfos || [],\n parameters.contextualParameters,\n operation.resourceIdentifier,\n targetDefaultFieldIdentifier,\n parameters.parentResourcesRequirements,\n );\n \n // Validate that all required parameters were provided\n if (missingParameters.length > 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n {\n reason: 'Missing required callback URL parameters',\n missingParameters,\n availableParameters: Object.keys(parameters.contextualParameters),\n url\n }\n );\n }\n \n const requestOptions: RequestOptions = {\n ...options,\n ...resolveOperationRequestTimeout(options, operation),\n params: parameters.queryParameters,\n riskLevel: operation.riskLevel || ResourceOperationRiskLevel.MEDIUM,\n resourceType: operation.resourceIdentifier,\n operationIdentifier: String(operation.operationIdentifier),\n variantKey: operation.variantKey,\n isBulkOperation: operation.isBulkOperation,\n isOperationDefault: operation.isOperationDefault,\n loading: options?.loading ?? {\n tier: LoadingTier.COMPONENT,\n phase: LoadingPhase.INITIAL,\n },\n };\n\n // Callback calls are typically POST\n const responseData = await this.post<TResponse>(url, parameters.requestData, requestOptions);\n \n // Select and validate response DTO\n const responseDto = this.selectResponseDto(operation, parameters.dataMode);\n return this.validateResponseData<TResponse>(responseData, responseDto);\n } else {\n // Use primary URL (same as regular API_CALL, which already validates)\n return this.executeApiCallOperation(operation, parameters, options);\n }\n }\n\n /**\n * Execute search operation with search-specific parameters.\n * Operation is typed as FrontendResourceConfiguration_Operation; at runtime it is always\n * a SEARCH operation (verified by caller) with flattened collection-view fields.\n */\n private async executeSearchOperationInternal<TResponse>(\n operation: FrontendResourceConfiguration_Operation,\n parameters: ResourceSearchCallParameters,\n options?: RequestOptions\n ): Promise<TResponse> {\n const op = operation as {\n initiatorInfos?: ResourceConfiguration_Operation_UrlInitiatorInfo[];\n filterFields?: Record<string, unknown>;\n maxPaginatedResultPerPageLimit?: number;\n riskLevel?: ResourceOperationRiskLevel;\n clientRequestTimeoutMs?: number;\n resourceIdentifier?: string;\n operationIdentifier?: string;\n };\n const targetResourceType = String(op.resourceIdentifier) as ResourceType;\n const targetDefaultFieldIdentifier =\n this.resourcesRegistry.resourceConfigurations[targetResourceType]?.resourceFieldIdentifier ?? '';\n\n // Build URL from initiatorInfos with deterministic selection\n const { url, missingParameters } = this.buildUrlFromInitiatorInfos(\n op.initiatorInfos || [],\n parameters.contextualParameters,\n targetResourceType,\n targetDefaultFieldIdentifier,\n parameters.parentResourcesRequirements\n );\n \n // Validate that all required parameters were provided\n if (missingParameters.length > 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n {\n reason: 'Missing required URL parameters',\n missingParameters,\n availableParameters: Object.keys(parameters.contextualParameters),\n url\n }\n );\n }\n\n // Build search query parameters\n const searchParams: Record<string, any> = {\n ...parameters.queryParameters\n };\n\n // Add dataMode if specified (not RAW)\n if (parameters.dataMode && parameters.dataMode !== DataMode.RAW) {\n searchParams.dataMode = parameters.dataMode;\n }\n\n // Add search query if provided\n if (parameters.searchQuery) {\n searchParams.q = parameters.searchQuery;\n }\n\n // Add filters if provided\n if (parameters.filters && op.filterFields) {\n Object.entries(parameters.filters).forEach(([key, value]) => {\n if (op.filterFields![key]) {\n searchParams[key] = value;\n }\n });\n }\n\n // Add sorting if provided\n if (parameters.sort && parameters.sort.length > 0) {\n searchParams.sort = parameters.sort.map(s => `${s.field}:${s.direction}`).join(',');\n }\n\n // Add pagination if provided\n if (parameters.pagination) {\n searchParams.page = parameters.pagination.page;\n const maxLimit = op.maxPaginatedResultPerPageLimit ?? 50;\n searchParams.limit = Math.min(parameters.pagination.limit, maxLimit);\n }\n\n const requestOptions: RequestOptions = {\n ...options,\n ...resolveOperationRequestTimeout(options, op),\n params: searchParams,\n riskLevel: op.riskLevel || ResourceOperationRiskLevel.MEDIUM,\n resourceType: op.resourceIdentifier,\n operationIdentifier: String(op.operationIdentifier),\n variantKey: operation.variantKey,\n isBulkOperation: operation.isBulkOperation,\n isOperationDefault: operation.isOperationDefault,\n loading: options?.loading ?? {\n tier: LoadingTier.COMPONENT,\n phase: LoadingPhase.INITIAL,\n },\n };\n\n // Search operations are always GET\n const responseData = await this.get<TResponse>(url, requestOptions);\n\n // Select and validate response DTO\n const responseDto = this.selectResponseDto(operation, parameters.dataMode);\n return this.validateResponseData<TResponse>(responseData, responseDto);\n }\n\n /**\n * Select the best matching initiatorInfo based on context.\n *\n * The deterministic selection algorithm lives in\n * `FrontendResourceUtils.selectOperationUrlInitiatorInfo` — shared with\n * non-transport consumers (e.g. the filters layer derives URL-pinned filter\n * fields from the same selection). This wrapper owns only the transport\n * error semantics: an unsatisfiable selection is a hard\n * FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE failure here.\n */\n private selectInitiatorInfo(\n initiatorInfos: ResourceConfiguration_Operation_UrlInitiatorInfo[],\n contextualParameters: Record<string, ResourceContextualParameterValue>,\n targetResourceType: ResourceType,\n targetDefaultFieldIdentifier: string,\n parentResourcesRequirements?: FrontendResource_ParentResourceRequirement[]\n ): ResourceConfiguration_Operation_UrlInitiatorInfo {\n\n if (initiatorInfos.length === 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n { reason: 'No initiator infos available for this operation' }\n );\n }\n\n const selected = FrontendResourceUtils.selectOperationUrlInitiatorInfo({\n initiatorInfos,\n contextualParameters,\n targetResourceType,\n targetDefaultFieldIdentifier,\n parentResourcesRequirements,\n });\n\n if (!selected) {\n const available = Object.keys(contextualParameters).join(', ');\n const required = initiatorInfos.map(i =>\n i.parameters.map(p => p.fieldIdentifier).join(', ')\n ).join(' OR ');\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_ENDPOINT_AVAILABLE,\n undefined,\n { availableParams: available, requiredParams: required }\n );\n }\n\n return selected;\n }\n\n /**\n * Build URL from initiator infos and contextual parameters.\n * Uses deterministic selection algorithm with parentResourcesRequirements.\n */\n private buildUrlFromInitiatorInfos(\n initiatorInfos: ResourceConfiguration_Operation_UrlInitiatorInfo[],\n contextualParameters: Record<string, ResourceContextualParameterValue>,\n targetResourceType: ResourceType,\n targetDefaultFieldIdentifier: string,\n parentResourcesRequirements?: FrontendResource_ParentResourceRequirement[]\n ): UrlBuildResult {\n const selected = this.selectInitiatorInfo(\n initiatorInfos, \n contextualParameters, \n targetResourceType,\n targetDefaultFieldIdentifier,\n parentResourcesRequirements\n );\n \n return this.buildUrlFromInitiatorInfo(selected, contextualParameters);\n }\n\n /**\n * Build callback URL from initiator infos\n */\n private buildCallbackUrlFromInitiatorInfos(\n initiatorInfos: ResourceConfiguration_Operation_UrlInitiatorInfo[],\n contextualParameters: Record<string, ResourceContextualParameterValue>,\n targetResourceType: ResourceType,\n targetDefaultFieldIdentifier: string,\n parentResourcesRequirements?: FrontendResource_ParentResourceRequirement[]\n ): UrlBuildResult {\n if (initiatorInfos.length === 0) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_CALLBACK_URL,\n undefined,\n { reason: 'No initiator infos available for callback operation' }\n );\n }\n\n // Reuse the same candidate-selection semantics as the primary URL path,\n // but constrain the pool to callback-capable initiators.\n const callbackCandidates = initiatorInfos.filter((info) => info.urlCallback);\n const callbackInitiator = callbackCandidates.length > 0\n ? this.selectInitiatorInfo(\n callbackCandidates,\n contextualParameters,\n targetResourceType,\n targetDefaultFieldIdentifier,\n parentResourcesRequirements,\n )\n : undefined;\n if (!callbackInitiator) {\n throw this.buildError(\n ErrorCustomMessageReference.FRONTEND_RESOURCE_NO_CALLBACK_URL,\n undefined,\n { reason: 'No callback URL defined in any initiator info' }\n );\n }\n\n // Build callback URL\n let url = callbackInitiator.urlCallback!;\n const missingParameters: string[] = [];\n\n // Replace URL parameters\n // Support both {fieldIdentifier} (backend style) and :fieldIdentifier (React Router style)\n for (const param of callbackInitiator.parameters) {\n const paramValue = contextualParameters[param.fieldIdentifier];\n if (isScalarContextualParameterValue(paramValue)) {\n const paramValueStr = String(paramValue);\n // Replace {fieldIdentifier} format (backend style)\n url = url.replace(`{${param.fieldIdentifier}}`, paramValueStr);\n // Replace :fieldIdentifier format (React Router style) - use word boundary to avoid partial matches\n const colonRegex = new RegExp(`:${param.fieldIdentifier.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?=[/\\\\?]|$)`, 'g');\n url = url.replace(colonRegex, paramValueStr);\n } else {\n missingParameters.push(param.fieldIdentifier);\n }\n }\n\n return { url, missingParameters };\n }\n\n /**\n * Build URL from a single initiator info\n */\n private buildUrlFromInitiatorInfo(\n initiatorInfo: ResourceConfiguration_Operation_UrlInitiatorInfo,\n contextualParameters: Record<string, ResourceContextualParameterValue>\n ): UrlBuildResult {\n let url = initiatorInfo.url;\n const missingParameters: string[] = [];\n\n // Replace URL parameters with contextual values\n // Support both {fieldIdentifier} (backend style) and :fieldIdentifier (React Router style)\n for (const param of initiatorInfo.parameters) {\n const paramValue = contextualParameters[param.fieldIdentifier];\n if (isScalarContextualParameterValue(paramValue)) {\n const paramValueStr = String(paramValue);\n // Replace {fieldIdentifier} format (backend style)\n url = url.replace(`{${param.fieldIdentifier}}`, paramValueStr);\n // Replace :fieldIdentifier format (React Router style) - use word boundary to avoid partial matches\n const colonRegex = new RegExp(`:${param.fieldIdentifier.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?=[/\\\\?]|$)`, 'g');\n url = url.replace(colonRegex, paramValueStr);\n } else {\n missingParameters.push(param.fieldIdentifier);\n }\n }\n\n return { url, missingParameters };\n }\n\n /**\n * Get available operation paths from the registry\n */\n public getAvailableOperationPaths(): string[] {\n const operationPaths: string[] = [];\n\n for (const [resourceType, resourceConfig] of Object.entries(this.resourcesRegistry.resourceConfigurations)) {\n const config = resourceConfig as AnyFrontendResourceConfiguration;\n for (const operation of config.operations) {\n const operationPath = ResourcesConfig_OperationPathUtils.extractOperationPath(operation);\n const pathKey = ResourcesConfig_OperationPathUtils.createOperationPathKey(operationPath);\n operationPaths.push(pathKey);\n }\n }\n\n return operationPaths;\n }\n\n /**\n * Get operation details for debugging\n */\n public getOperationDetails(operationPathKey: string): FrontendResourceConfiguration_Operation | null {\n const operationPath = ResourcesConfig_OperationPathUtils.parseOperationPathKey(operationPathKey);\n return this.findOperation(operationPath);\n }\n}\n\n// Note: No singleton export - this class should only be instantiated through ResourceRepositoryContext\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResourceReadCacheBridge.d.ts","sourceRoot":"","sources":["../../../../src/core/resources/ResourceReadCacheBridge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqD,MAAM,OAAO,CAAC;AAsC1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,uBAAuB,EAAE,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"ResourceReadCacheBridge.d.ts","sourceRoot":"","sources":["../../../../src/core/resources/ResourceReadCacheBridge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqD,MAAM,OAAO,CAAC;AAsC1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,uBAAuB,EAAE,KAAK,CAAC,EAoU3C,CAAC"}
|
|
@@ -122,6 +122,68 @@ export const ResourceReadCacheBridge = () => {
|
|
|
122
122
|
const confirmedRoomsRef = useRef(new Set());
|
|
123
123
|
/** Rooms claimed but not yet confirmed, so a burst of reads claims each room once. */
|
|
124
124
|
const requestedRoomsRef = useRef(new Map());
|
|
125
|
+
/*
|
|
126
|
+
* Rooms a read asked for BEFORE the socket was up, held until it is.
|
|
127
|
+
*
|
|
128
|
+
* This is the difference between a cache that works on a page load and one that does not.
|
|
129
|
+
* `requestCoverage` used to return silently when disconnected, and nothing ever asked again — so
|
|
130
|
+
* every read that completed during the connect window was stored uncovered and stayed uncovered
|
|
131
|
+
* for the surface's whole life. Measured on the running dogfood application (2026-09-10): a single
|
|
132
|
+
* navigation to the todos collection issued FOUR coverage requests for `todos`, all four with
|
|
133
|
+
* `isConnected: false`, and the client emitted no `resource:subscribe` frame at all. Whether a room
|
|
134
|
+
* was ever claimed came down to whether some LATER read happened to re-enter `store()` after the
|
|
135
|
+
* socket came up, which is incidental rather than designed — and on the e2e lane's timing it did
|
|
136
|
+
* not happen, so the scenario timed out against a subscription nobody had asked for.
|
|
137
|
+
*/
|
|
138
|
+
const pendingRoomsRef = useRef(new Map());
|
|
139
|
+
/*
|
|
140
|
+
* LATEST-VALUE refs, read by the authority rather than captured by it.
|
|
141
|
+
*
|
|
142
|
+
* The authority must be installed ONCE per cache instance, because installing it CLEARS the cache
|
|
143
|
+
* (see `setCoverageAuthority`). Capturing `isConnected` or the claim callbacks in the closure would
|
|
144
|
+
* put them in the effect's dependency list and reinstall the authority every time any of them
|
|
145
|
+
* changed — which is exactly what happened on the `isConnected` false -> true edge, wiping the
|
|
146
|
+
* cache at the precise moment it first became coverable. Assigned during render so a read firing
|
|
147
|
+
* from a sibling's effect cannot observe a stale value.
|
|
148
|
+
*/
|
|
149
|
+
const isConnectedRef = useRef(isConnected);
|
|
150
|
+
isConnectedRef.current = isConnected;
|
|
151
|
+
/*
|
|
152
|
+
* Claim one scope room and record the outcome. The single place a claim is made, so a room queued
|
|
153
|
+
* while disconnected and a room requested while connected travel identical paths.
|
|
154
|
+
*/
|
|
155
|
+
const claimScopeRoom = useCallback((roomName, qualifier) => {
|
|
156
|
+
if (requestedRoomsRef.current.has(roomName))
|
|
157
|
+
return;
|
|
158
|
+
requestedRoomsRef.current.set(roomName, qualifier);
|
|
159
|
+
void claimResourceRoom({
|
|
160
|
+
ownerKey: `${CLAIM_OWNER_PREFIX}:${roomName}`,
|
|
161
|
+
resourceType: qualifier.resourceType,
|
|
162
|
+
scopeKey: qualifier.scopeKey,
|
|
163
|
+
scopeId: qualifier.scopeId,
|
|
164
|
+
/*
|
|
165
|
+
* The scope's own identifier, in the shape the server's authorization expects. The subscribe
|
|
166
|
+
* handler refuses an EMPTY `contextResourceIdentifiers` outright, and `verifyScopeAccess` reads
|
|
167
|
+
* the scope from it — so this is the authorization input, not decoration.
|
|
168
|
+
*/
|
|
169
|
+
contextResourceIdentifiers: { [`${qualifier.scopeKey}Id`]: qualifier.scopeId },
|
|
170
|
+
}).then((result) => {
|
|
171
|
+
if (result?.success) {
|
|
172
|
+
confirmedRoomsRef.current.add(roomName);
|
|
173
|
+
logDebug('scope room confirmed', { roomName });
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Refused or unreachable. The room stays unconfirmed, so nothing keyed to it is ever
|
|
177
|
+
// served — the cache degrades to the un-cached path rather than guessing.
|
|
178
|
+
requestedRoomsRef.current.delete(roomName);
|
|
179
|
+
logDebug('scope room not confirmed; entries under it stay unservable', { roomName });
|
|
180
|
+
}
|
|
181
|
+
}).catch(() => {
|
|
182
|
+
requestedRoomsRef.current.delete(roomName);
|
|
183
|
+
});
|
|
184
|
+
}, [claimResourceRoom]);
|
|
185
|
+
const claimScopeRoomRef = useRef(claimScopeRoom);
|
|
186
|
+
claimScopeRoomRef.current = claimScopeRoom;
|
|
125
187
|
const releaseAllRooms = useCallback(() => {
|
|
126
188
|
for (const [roomName, qualifier] of requestedRoomsRef.current) {
|
|
127
189
|
void releaseResourceRoom({
|
|
@@ -134,7 +196,10 @@ export const ResourceReadCacheBridge = () => {
|
|
|
134
196
|
}
|
|
135
197
|
requestedRoomsRef.current.clear();
|
|
136
198
|
confirmedRoomsRef.current.clear();
|
|
199
|
+
pendingRoomsRef.current.clear();
|
|
137
200
|
}, [releaseResourceRoom]);
|
|
201
|
+
const releaseAllRoomsRef = useRef(releaseAllRooms);
|
|
202
|
+
releaseAllRoomsRef.current = releaseAllRooms;
|
|
138
203
|
/*
|
|
139
204
|
* Install the authority, and take it away again on unmount.
|
|
140
205
|
*
|
|
@@ -146,55 +211,68 @@ export const ResourceReadCacheBridge = () => {
|
|
|
146
211
|
const cache = readCache;
|
|
147
212
|
const authority = {
|
|
148
213
|
covers: (_resourceType, scopes) => {
|
|
149
|
-
if (!
|
|
214
|
+
if (!isConnectedRef.current)
|
|
150
215
|
return false;
|
|
151
216
|
if (scopes.length === 0)
|
|
152
217
|
return false;
|
|
153
218
|
return scopes.every((scope) => confirmedRoomsRef.current.has(buildScopeRoomName(_resourceType, scope.scopeKey, scope.scopeId)));
|
|
154
219
|
},
|
|
155
220
|
requestCoverage: (resourceType, scopes) => {
|
|
156
|
-
if (!isConnected)
|
|
157
|
-
return;
|
|
158
221
|
for (const scope of scopes) {
|
|
159
222
|
const roomName = buildScopeRoomName(resourceType, scope.scopeKey, scope.scopeId);
|
|
160
223
|
if (requestedRoomsRef.current.has(roomName))
|
|
161
224
|
continue;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
*/
|
|
174
|
-
contextResourceIdentifiers: { [`${scope.scopeKey}Id`]: scope.scopeId },
|
|
175
|
-
}).then((result) => {
|
|
176
|
-
if (result?.success) {
|
|
177
|
-
confirmedRoomsRef.current.add(roomName);
|
|
178
|
-
logDebug('scope room confirmed', { roomName });
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
// Refused or unreachable. The room stays unconfirmed, so nothing keyed to it is ever
|
|
182
|
-
// served — the cache degrades to the un-cached path rather than guessing.
|
|
183
|
-
requestedRoomsRef.current.delete(roomName);
|
|
184
|
-
logDebug('scope room not confirmed; entries under it stay unservable', { roomName });
|
|
185
|
-
}
|
|
186
|
-
}).catch(() => {
|
|
187
|
-
requestedRoomsRef.current.delete(roomName);
|
|
188
|
-
});
|
|
225
|
+
/*
|
|
226
|
+
* DEFERRED, not dropped. A read completing before the socket is up is the ordinary case on
|
|
227
|
+
* a page load, not an edge — the surface's own first read is usually one of them — and
|
|
228
|
+
* returning here silently left its entry uncovered forever.
|
|
229
|
+
*/
|
|
230
|
+
if (!isConnectedRef.current) {
|
|
231
|
+
pendingRoomsRef.current.set(roomName, { ...scope, resourceType });
|
|
232
|
+
logDebug('coverage deferred until the socket is up', { roomName });
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
claimScopeRoomRef.current(roomName, { ...scope, resourceType });
|
|
189
236
|
}
|
|
190
237
|
},
|
|
191
238
|
};
|
|
192
239
|
cache.setCoverageAuthority(authority);
|
|
193
240
|
return () => {
|
|
194
241
|
cache.setCoverageAuthority(null);
|
|
195
|
-
|
|
242
|
+
releaseAllRoomsRef.current();
|
|
196
243
|
};
|
|
197
|
-
|
|
244
|
+
/*
|
|
245
|
+
* `readCache` ALONE, and that is the whole point of the refs above.
|
|
246
|
+
*
|
|
247
|
+
* `isConnected` was in this list until 2026-09-10, and because installing an authority clears
|
|
248
|
+
* the cache, the false -> true edge emptied it at the exact moment it first became coverable.
|
|
249
|
+
* Every entry a page had read up to that point was discarded, and the coverage those reads had
|
|
250
|
+
* asked for had already been dropped by the disconnected early-return. The tier could therefore
|
|
251
|
+
* only ever cache reads that happened to occur AFTER the socket came up — on the dogfood
|
|
252
|
+
* application's todos collection, none did, so it served nothing while reporting nothing.
|
|
253
|
+
*
|
|
254
|
+
* The authority's IDENTITY does not change when the socket connects; only its ability to claim
|
|
255
|
+
* rooms does, and that is now read from a ref. A genuine socket REPLACEMENT is a different event
|
|
256
|
+
* and is still handled, by the `connectionCount` effect below.
|
|
257
|
+
*/
|
|
258
|
+
}, [readCache]);
|
|
259
|
+
/*
|
|
260
|
+
* Claim what the page already asked for, as soon as the socket can carry it.
|
|
261
|
+
*
|
|
262
|
+
* The other half of the deferral above. Without this the queue would only be a politer way of
|
|
263
|
+
* dropping the request.
|
|
264
|
+
*/
|
|
265
|
+
useEffect(() => {
|
|
266
|
+
if (!isConnected)
|
|
267
|
+
return;
|
|
268
|
+
if (pendingRoomsRef.current.size === 0)
|
|
269
|
+
return;
|
|
270
|
+
const deferred = [...pendingRoomsRef.current.entries()];
|
|
271
|
+
pendingRoomsRef.current.clear();
|
|
272
|
+
logDebug('claiming coverage deferred during the connect window', { rooms: deferred.length });
|
|
273
|
+
for (const [roomName, qualifier] of deferred)
|
|
274
|
+
claimScopeRoom(roomName, qualifier);
|
|
275
|
+
}, [isConnected, claimScopeRoom]);
|
|
198
276
|
/*
|
|
199
277
|
* Hand the cache the ambient application id.
|
|
200
278
|
*
|
|
@@ -207,19 +285,34 @@ export const ResourceReadCacheBridge = () => {
|
|
|
207
285
|
readCache.setApplicationId(currentApplicationId);
|
|
208
286
|
}, [currentApplicationId, readCache]);
|
|
209
287
|
/*
|
|
210
|
-
* A
|
|
288
|
+
* A RE-connect invalidates every confirmation. The FIRST connection does not.
|
|
211
289
|
*
|
|
212
|
-
* Rooms are per-SOCKET, so a
|
|
290
|
+
* Rooms are per-SOCKET, so a REPLACEMENT socket has joined nothing — and the window in which a
|
|
213
291
|
* socket was down is exactly the window in which a mutation could have gone unheard. Both halves
|
|
214
|
-
* point the same way: drop the cache and start the claims again.
|
|
292
|
+
* point the same way for a reconnect: drop the cache and start the claims again.
|
|
293
|
+
*
|
|
294
|
+
* Neither half holds for connection number one, and treating it the same was the second half of
|
|
295
|
+
* the page-load defect. There is no earlier socket whose rooms could have lapsed, nothing was ever
|
|
296
|
+
* served (`covers()` answers false while disconnected, so a stale entry could not have reached a
|
|
297
|
+
* caller), and the "window in which a mutation went unheard" is the page load itself — during
|
|
298
|
+
* which the entries were read from the server and are as fresh as any read. Clearing there simply
|
|
299
|
+
* discarded the first screen's worth of reads and left the tier inert for the surface that
|
|
300
|
+
* triggered them. The residual window — a mutation between a read and its room being joined — is
|
|
301
|
+
* unavoidable in any read-through cache and exists identically for the first read AFTER connection.
|
|
215
302
|
*/
|
|
303
|
+
const previousConnectionCountRef = useRef(connectionCount);
|
|
216
304
|
useEffect(() => {
|
|
217
|
-
|
|
305
|
+
const previousConnectionCount = previousConnectionCountRef.current;
|
|
306
|
+
previousConnectionCountRef.current = connectionCount;
|
|
307
|
+
if (connectionCount <= 1)
|
|
308
|
+
return;
|
|
309
|
+
if (connectionCount === previousConnectionCount)
|
|
218
310
|
return;
|
|
219
311
|
confirmedRoomsRef.current.clear();
|
|
220
312
|
requestedRoomsRef.current.clear();
|
|
313
|
+
pendingRoomsRef.current.clear();
|
|
221
314
|
readCache.clear();
|
|
222
|
-
logDebug('
|
|
315
|
+
logDebug('reconnected; coverage and cache reset', { connectionCount });
|
|
223
316
|
}, [connectionCount, readCache]);
|
|
224
317
|
/*
|
|
225
318
|
* An ORGANIZATION SWITCH changes which rows a read returns without changing the request.
|