@objectstack/core 17.0.0-rc.3 → 17.0.0-rc.5
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/CHANGELOG.md +548 -2
- package/README.md +0 -1
- package/dist/index.cjs +316 -598
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +181 -318
- package/dist/index.d.ts +181 -318
- package/dist/index.js +316 -596
- package/dist/index.js.map +1 -1
- package/dist/logger.cjs +117 -10
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.d.cts +40 -0
- package/dist/logger.d.ts +40 -0
- package/dist/logger.js +117 -10
- package/dist/logger.js.map +1 -1
- package/package.json +4 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Logger, LifecycleEventName, IServiceRegistry, IObjectQLEngine } from '@objectstack/spec/contracts';
|
|
2
|
-
export { EngineSchemaRegistryView, IDataDriver, IDataEngine, IHttpRequest, IHttpResponse, IHttpServer, IObjectQLEngine, Logger, Middleware, RouteHandler } from '@objectstack/spec/contracts';
|
|
2
|
+
export { EngineSchemaRegistryView, EngineTransactionInfo, EngineTransactionOptions, IDataDriver, IDataEngine, IHttpRequest, IHttpResponse, IHttpServer, IObjectQLEngine, Logger, Middleware, RouteHandler } from '@objectstack/spec/contracts';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { LoggerConfig, MigrationOnCrashPolicy, MigrationJournalEvent } from '@objectstack/spec/system';
|
|
5
5
|
import { ObjectLogger } from './logger.cjs';
|
|
6
6
|
export { createLogger } from './logger.cjs';
|
|
7
|
-
import { ConflictResolutionStrategy, ApiRegistryEntryInput, ApiRegistryEntry, ApiDiscoveryQuery, ApiDiscoveryResponse, ApiEndpointRegistration, ApiRegistry as ApiRegistry$1 } from '@objectstack/spec/api';
|
|
8
7
|
import * as QA from '@objectstack/spec/qa';
|
|
9
8
|
import { KeyObject } from 'node:crypto';
|
|
10
9
|
import { PluginCapability, PluginPermissions as PluginPermissions$1, PluginPermissionSet, ResourceType, PermissionAction, PluginPermission, SandboxConfig, KernelSecurityScanResult, KernelSecurityVulnerability, PluginHealthCheck, PluginHealthStatus as PluginHealthStatus$1, PluginHealthReport, HotReloadConfig, VersionConstraint, DependencyConflict, SemanticVersion, CompatibilityLevel } from '@objectstack/spec/kernel';
|
|
@@ -336,6 +335,33 @@ declare class ObjectKernel {
|
|
|
336
335
|
private describeInitOrderFault;
|
|
337
336
|
private startPluginWithTimeout;
|
|
338
337
|
private rollbackStartedPlugins;
|
|
338
|
+
/**
|
|
339
|
+
* Dispatch `kernel:shutdown`, ISOLATING failures: a handler that throws is
|
|
340
|
+
* logged and the remaining handlers still run (#5274).
|
|
341
|
+
*
|
|
342
|
+
* This is a per-hook judgement, deliberately NOT the bare awaited loop
|
|
343
|
+
* `context.trigger` runs for every other hook — the boot-path hooks
|
|
344
|
+
* (`kernel:ready`, `kernel:bootstrapped`, `kernel:listening`) keep
|
|
345
|
+
* propagating, because everything dispatched before "✅ Bootstrap complete"
|
|
346
|
+
* is a precondition of that claim and swallowing a throw there only hides
|
|
347
|
+
* the failure behind a process reporting success (#5170, #5257).
|
|
348
|
+
*
|
|
349
|
+
* On the teardown path there is no "refuse to proceed" left to buy. What is
|
|
350
|
+
* queued behind a failing shutdown handler is the rest of the cleanup —
|
|
351
|
+
* every other subscriber, then each plugin's `destroy()` in reverse order —
|
|
352
|
+
* which is what flushes buffers, closes connections and releases locks. So
|
|
353
|
+
* one bad handler must not amplify into leaked resources and unflushed
|
|
354
|
+
* writes. Same reasoning, same wording, same `Hook handler failed:
|
|
355
|
+
* kernel:shutdown` log line as `LiteKernel`'s dispatch site, which reaches
|
|
356
|
+
* the shared isolating dispatcher `ObjectKernelBase.triggerHook` (#5257).
|
|
357
|
+
*
|
|
358
|
+
* `ObjectKernel` cannot call that dispatcher: it does not extend
|
|
359
|
+
* `ObjectKernelBase` (only `LiteKernel` does) and owns its own `hooks` map,
|
|
360
|
+
* so the semantics are mirrored here rather than shared. One hook name
|
|
361
|
+
* meaning two opposite things across the two kernels is exactly the bug
|
|
362
|
+
* #5170/#5257 closed, so the pin for this one lives on both sides too.
|
|
363
|
+
*/
|
|
364
|
+
private triggerShutdownHookIsolating;
|
|
339
365
|
private performShutdown;
|
|
340
366
|
/**
|
|
341
367
|
* Topological order over `dependencies` (hard) + `optionalDependencies`
|
|
@@ -581,11 +607,64 @@ declare abstract class ObjectKernelBase {
|
|
|
581
607
|
*/
|
|
582
608
|
protected runPluginDestroy(plugin: Plugin): Promise<void>;
|
|
583
609
|
/**
|
|
584
|
-
* Trigger a hook with all registered handlers
|
|
610
|
+
* Trigger a hook with all registered handlers, ISOLATING failures: a
|
|
611
|
+
* handler that throws is logged and the remaining handlers still run.
|
|
612
|
+
*
|
|
613
|
+
* Use this for hooks where one subscriber's failure must not deny the
|
|
614
|
+
* others their turn — notification-style hooks, and `kernel:shutdown`,
|
|
615
|
+
* where the handlers still queued behind the failing one are the cleanup
|
|
616
|
+
* that flushes buffers and releases resources (#5257).
|
|
617
|
+
*
|
|
618
|
+
* It is the WRONG dispatcher for anything on the BOOT path. Every hook
|
|
619
|
+
* dispatched before "✅ Bootstrap complete" is a precondition of that
|
|
620
|
+
* claim, so swallowing a throw there does not rescue the boot — it only
|
|
621
|
+
* hides the failure behind a process that reports success. Those hooks
|
|
622
|
+
* (`kernel:ready`, `kernel:bootstrapped`, `kernel:listening`) use
|
|
623
|
+
* {@link triggerHookOrThrow} (#5170, #5257).
|
|
624
|
+
*
|
|
585
625
|
* @param name - Hook name
|
|
586
626
|
* @param args - Arguments to pass to handlers
|
|
587
627
|
*/
|
|
588
628
|
protected triggerHook(name: string, ...args: any[]): Promise<void>;
|
|
629
|
+
/**
|
|
630
|
+
* Trigger a hook with all registered handlers, PROPAGATING the first
|
|
631
|
+
* failure: the remaining handlers do not run and the original error
|
|
632
|
+
* reaches the caller unwrapped.
|
|
633
|
+
*
|
|
634
|
+
* This is the dispatch semantics `ObjectKernel` has always had for every
|
|
635
|
+
* lifecycle hook (its `context.trigger` is a bare awaited loop that never
|
|
636
|
+
* catches). `LiteKernel` used the isolating {@link triggerHook} for all of
|
|
637
|
+
* them, so one hook name meant two opposite things depending on which
|
|
638
|
+
* kernel booted the same plugin code (#5170).
|
|
639
|
+
*
|
|
640
|
+
* `LiteKernel` now uses this dispatcher for all three BOOT-path hooks:
|
|
641
|
+
*
|
|
642
|
+
* - `kernel:ready` (#5170) — the only correct moment for a plugin to
|
|
643
|
+
* assert that the preconditions it declared were actually met (the
|
|
644
|
+
* registries are still filling during `init()`), so "declared but not
|
|
645
|
+
* deliverable ⇒ refuse to boot" gates live there. On LiteKernel, which
|
|
646
|
+
* is what vitest/serverless/edge run, they were downgraded to an error
|
|
647
|
+
* log while the process carried on serving traffic without the
|
|
648
|
+
* guarantee it claimed.
|
|
649
|
+
* - `kernel:bootstrapped` and `kernel:listening` (#5257) — the same
|
|
650
|
+
* argument one hook later. `kernel:listening` is where HTTP server
|
|
651
|
+
* plugins open their socket, so a swallowed failure there produced the
|
|
652
|
+
* worst shape available: a live process printing "✅ Bootstrap complete"
|
|
653
|
+
* with nothing listening. `kernel:bootstrapped` carries reconcile and
|
|
654
|
+
* audit passes whose silent failure is a quieter version of the same
|
|
655
|
+
* lie.
|
|
656
|
+
*
|
|
657
|
+
* Deliberately NOT applied to `kernel:shutdown`, which keeps
|
|
658
|
+
* {@link triggerHook}: on the teardown path a failing handler must not
|
|
659
|
+
* block the cleanup queued behind it. That is a per-hook judgement
|
|
660
|
+
* recorded at the dispatch site in `lite-kernel.ts`, not an inherited
|
|
661
|
+
* default — and it is the reason this dispatcher is chosen per hook rather
|
|
662
|
+
* than swapped in wholesale.
|
|
663
|
+
*
|
|
664
|
+
* @param name - Hook name
|
|
665
|
+
* @param args - Arguments to pass to handlers
|
|
666
|
+
*/
|
|
667
|
+
protected triggerHookOrThrow(name: string, ...args: any[]): Promise<void>;
|
|
589
668
|
/**
|
|
590
669
|
* Get current kernel state
|
|
591
670
|
*/
|
|
@@ -748,315 +827,6 @@ declare class LiteKernel extends ObjectKernelBase {
|
|
|
748
827
|
isRunning(): boolean;
|
|
749
828
|
}
|
|
750
829
|
|
|
751
|
-
/**
|
|
752
|
-
* API Registry Service
|
|
753
|
-
*
|
|
754
|
-
* Central registry for managing API endpoints across different protocols.
|
|
755
|
-
* Provides endpoint registration, discovery, and conflict resolution.
|
|
756
|
-
*
|
|
757
|
-
* **Features:**
|
|
758
|
-
* - Multi-protocol support (REST, GraphQL, OData, WebSocket, etc.)
|
|
759
|
-
* - Route conflict detection with configurable resolution strategies
|
|
760
|
-
* - RBAC permission integration
|
|
761
|
-
* - Dynamic schema linking with ObjectQL references
|
|
762
|
-
* - Plugin API registration
|
|
763
|
-
*
|
|
764
|
-
* **Architecture Alignment:**
|
|
765
|
-
* - Kubernetes: Service Discovery & API Server
|
|
766
|
-
* - AWS API Gateway: Unified API Management
|
|
767
|
-
* - Kong Gateway: Plugin-based API Management
|
|
768
|
-
*
|
|
769
|
-
* @example
|
|
770
|
-
* ```typescript
|
|
771
|
-
* const registry = new ApiRegistry(logger, 'priority');
|
|
772
|
-
*
|
|
773
|
-
* // Register an API
|
|
774
|
-
* registry.registerApi({
|
|
775
|
-
* id: 'customer_api',
|
|
776
|
-
* name: 'Customer API',
|
|
777
|
-
* type: 'rest',
|
|
778
|
-
* version: 'v1',
|
|
779
|
-
* basePath: '/api/v1/customers',
|
|
780
|
-
* endpoints: [...]
|
|
781
|
-
* });
|
|
782
|
-
*
|
|
783
|
-
* // Discover APIs
|
|
784
|
-
* const apis = registry.findApis({ type: 'rest', status: 'active' });
|
|
785
|
-
*
|
|
786
|
-
* // Get registry snapshot
|
|
787
|
-
* const snapshot = registry.getRegistry();
|
|
788
|
-
* ```
|
|
789
|
-
*/
|
|
790
|
-
declare class ApiRegistry {
|
|
791
|
-
private apis;
|
|
792
|
-
private endpoints;
|
|
793
|
-
private routes;
|
|
794
|
-
private apisByType;
|
|
795
|
-
private apisByTag;
|
|
796
|
-
private apisByStatus;
|
|
797
|
-
private conflictResolution;
|
|
798
|
-
private logger;
|
|
799
|
-
private version;
|
|
800
|
-
private updatedAt;
|
|
801
|
-
constructor(logger: Logger, conflictResolution?: ConflictResolutionStrategy, version?: string);
|
|
802
|
-
/**
|
|
803
|
-
* Register an API with its endpoints
|
|
804
|
-
*
|
|
805
|
-
* @param api - API registry entry
|
|
806
|
-
* @throws Error if API already registered or route conflicts detected
|
|
807
|
-
*/
|
|
808
|
-
registerApi(api: ApiRegistryEntryInput): void;
|
|
809
|
-
/**
|
|
810
|
-
* Unregister an API and all its endpoints
|
|
811
|
-
*
|
|
812
|
-
* @param apiId - API identifier
|
|
813
|
-
*/
|
|
814
|
-
unregisterApi(apiId: string): void;
|
|
815
|
-
/**
|
|
816
|
-
* Register a single endpoint
|
|
817
|
-
*
|
|
818
|
-
* @param apiId - API identifier
|
|
819
|
-
* @param endpoint - Endpoint registration
|
|
820
|
-
* @throws Error if route conflict detected
|
|
821
|
-
*/
|
|
822
|
-
private registerEndpoint;
|
|
823
|
-
/**
|
|
824
|
-
* Unregister a single endpoint
|
|
825
|
-
*
|
|
826
|
-
* @param apiId - API identifier
|
|
827
|
-
* @param endpointId - Endpoint identifier
|
|
828
|
-
*/
|
|
829
|
-
private unregisterEndpoint;
|
|
830
|
-
/**
|
|
831
|
-
* Register a route with conflict detection
|
|
832
|
-
*
|
|
833
|
-
* @param apiId - API identifier
|
|
834
|
-
* @param endpoint - Endpoint registration
|
|
835
|
-
* @throws Error if route conflict detected (based on strategy)
|
|
836
|
-
*/
|
|
837
|
-
private registerRoute;
|
|
838
|
-
/**
|
|
839
|
-
* Handle route conflict based on resolution strategy
|
|
840
|
-
*
|
|
841
|
-
* @param routeKey - Route key
|
|
842
|
-
* @param apiId - New API identifier
|
|
843
|
-
* @param endpoint - New endpoint
|
|
844
|
-
* @param existingRoute - Existing route registration
|
|
845
|
-
* @param newPriority - New endpoint priority
|
|
846
|
-
* @throws Error if strategy is 'error'
|
|
847
|
-
*/
|
|
848
|
-
private handleRouteConflict;
|
|
849
|
-
/**
|
|
850
|
-
* Generate a unique route key for conflict detection
|
|
851
|
-
*
|
|
852
|
-
* NOTE: This implementation uses exact string matching for route conflict detection.
|
|
853
|
-
* It works well for static paths but has limitations with parameterized routes.
|
|
854
|
-
* For example, `/api/users/:id` and `/api/users/:userId` will NOT be detected as conflicts
|
|
855
|
-
* even though they are semantically identical parameterized patterns. Similarly,
|
|
856
|
-
* `/api/:resource/list` and `/api/:entity/list` would also not be detected as conflicting.
|
|
857
|
-
*
|
|
858
|
-
* For more advanced conflict detection (e.g., path-to-regexp pattern matching),
|
|
859
|
-
* consider integrating with your routing library's conflict detection mechanism.
|
|
860
|
-
*
|
|
861
|
-
* @param endpoint - Endpoint registration
|
|
862
|
-
* @returns Route key (e.g., "GET:/api/v1/customers/:id")
|
|
863
|
-
*/
|
|
864
|
-
private getRouteKey;
|
|
865
|
-
/**
|
|
866
|
-
* Validate endpoint registration
|
|
867
|
-
*
|
|
868
|
-
* @param endpoint - Endpoint to validate
|
|
869
|
-
* @param apiId - API identifier (for error messages)
|
|
870
|
-
* @throws Error if endpoint is invalid
|
|
871
|
-
*/
|
|
872
|
-
private validateEndpoint;
|
|
873
|
-
/**
|
|
874
|
-
* Get an API by ID
|
|
875
|
-
*
|
|
876
|
-
* @param apiId - API identifier
|
|
877
|
-
* @returns API registry entry or undefined
|
|
878
|
-
*/
|
|
879
|
-
getApi(apiId: string): ApiRegistryEntry | undefined;
|
|
880
|
-
/**
|
|
881
|
-
* Get all registered APIs
|
|
882
|
-
*
|
|
883
|
-
* @returns Array of all APIs
|
|
884
|
-
*/
|
|
885
|
-
getAllApis(): ApiRegistryEntry[];
|
|
886
|
-
/**
|
|
887
|
-
* Find APIs matching query criteria
|
|
888
|
-
*
|
|
889
|
-
* Performance optimized with auxiliary indices for O(1) lookups on type, tags, and status.
|
|
890
|
-
*
|
|
891
|
-
* @param query - Discovery query parameters
|
|
892
|
-
* @returns Matching APIs
|
|
893
|
-
*/
|
|
894
|
-
findApis(query: ApiDiscoveryQuery): ApiDiscoveryResponse;
|
|
895
|
-
/**
|
|
896
|
-
* Get endpoint by API ID and endpoint ID
|
|
897
|
-
*
|
|
898
|
-
* @param apiId - API identifier
|
|
899
|
-
* @param endpointId - Endpoint identifier
|
|
900
|
-
* @returns Endpoint registration or undefined
|
|
901
|
-
*/
|
|
902
|
-
getEndpoint(apiId: string, endpointId: string): ApiEndpointRegistration | undefined;
|
|
903
|
-
/**
|
|
904
|
-
* Find endpoint by route (method + path)
|
|
905
|
-
*
|
|
906
|
-
* @param method - HTTP method
|
|
907
|
-
* @param path - URL path
|
|
908
|
-
* @returns Endpoint registration or undefined
|
|
909
|
-
*/
|
|
910
|
-
findEndpointByRoute(method: string, path: string): {
|
|
911
|
-
api: ApiRegistryEntry;
|
|
912
|
-
endpoint: ApiEndpointRegistration;
|
|
913
|
-
} | undefined;
|
|
914
|
-
/**
|
|
915
|
-
* Get complete registry snapshot
|
|
916
|
-
*
|
|
917
|
-
* @returns Current registry state
|
|
918
|
-
*/
|
|
919
|
-
getRegistry(): ApiRegistry$1;
|
|
920
|
-
/**
|
|
921
|
-
* Clear all registered APIs
|
|
922
|
-
*
|
|
923
|
-
* **⚠️ SAFETY WARNING:**
|
|
924
|
-
* This method clears all registered APIs and should be used with caution.
|
|
925
|
-
*
|
|
926
|
-
* **Usage Restrictions:**
|
|
927
|
-
* - In production environments (NODE_ENV=production), a `force: true` parameter is required
|
|
928
|
-
* - Primarily intended for testing and development hot-reload scenarios
|
|
929
|
-
*
|
|
930
|
-
* @param options - Clear options
|
|
931
|
-
* @param options.force - Force clear in production environment (default: false)
|
|
932
|
-
* @throws Error if called in production without force flag
|
|
933
|
-
*
|
|
934
|
-
* @example Safe usage in tests
|
|
935
|
-
* ```typescript
|
|
936
|
-
* beforeEach(() => {
|
|
937
|
-
* registry.clear(); // OK in test environment
|
|
938
|
-
* });
|
|
939
|
-
* ```
|
|
940
|
-
*
|
|
941
|
-
* @example Usage in production (requires explicit force)
|
|
942
|
-
* ```typescript
|
|
943
|
-
* // In production, explicit force is required
|
|
944
|
-
* registry.clear({ force: true });
|
|
945
|
-
* ```
|
|
946
|
-
*/
|
|
947
|
-
clear(options?: {
|
|
948
|
-
force?: boolean;
|
|
949
|
-
}): void;
|
|
950
|
-
/**
|
|
951
|
-
* Get registry statistics
|
|
952
|
-
*
|
|
953
|
-
* @returns Registry statistics
|
|
954
|
-
*/
|
|
955
|
-
getStats(): {
|
|
956
|
-
totalApis: number;
|
|
957
|
-
totalEndpoints: number;
|
|
958
|
-
totalRoutes: number;
|
|
959
|
-
apisByType: Record<string, number>;
|
|
960
|
-
endpointsByApi: Record<string, number>;
|
|
961
|
-
};
|
|
962
|
-
/**
|
|
963
|
-
* Update auxiliary indices when an API is registered
|
|
964
|
-
*
|
|
965
|
-
* @param api - API entry to index
|
|
966
|
-
* @private
|
|
967
|
-
* @internal
|
|
968
|
-
*/
|
|
969
|
-
private updateIndices;
|
|
970
|
-
/**
|
|
971
|
-
* Remove API from auxiliary indices when unregistered
|
|
972
|
-
*
|
|
973
|
-
* @param api - API entry to remove from indices
|
|
974
|
-
* @private
|
|
975
|
-
* @internal
|
|
976
|
-
*/
|
|
977
|
-
private removeFromIndices;
|
|
978
|
-
/**
|
|
979
|
-
* Helper to ensure an index set exists and return it
|
|
980
|
-
*
|
|
981
|
-
* @param map - Index map
|
|
982
|
-
* @param key - Index key
|
|
983
|
-
* @returns The Set for this key (created if needed)
|
|
984
|
-
* @private
|
|
985
|
-
* @internal
|
|
986
|
-
*/
|
|
987
|
-
private ensureIndexSet;
|
|
988
|
-
/**
|
|
989
|
-
* Helper to remove an ID from an index set and clean up empty sets
|
|
990
|
-
*
|
|
991
|
-
* @param map - Index map
|
|
992
|
-
* @param key - Index key
|
|
993
|
-
* @param id - API ID to remove
|
|
994
|
-
* @private
|
|
995
|
-
* @internal
|
|
996
|
-
*/
|
|
997
|
-
private removeFromIndexSet;
|
|
998
|
-
/**
|
|
999
|
-
* Check if running in production environment
|
|
1000
|
-
*
|
|
1001
|
-
* @returns true if NODE_ENV is 'production'
|
|
1002
|
-
* @private
|
|
1003
|
-
* @internal
|
|
1004
|
-
*/
|
|
1005
|
-
private isProductionEnvironment;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
/**
|
|
1009
|
-
* API Registry Plugin Configuration
|
|
1010
|
-
*/
|
|
1011
|
-
interface ApiRegistryPluginConfig {
|
|
1012
|
-
/**
|
|
1013
|
-
* Conflict resolution strategy for route conflicts
|
|
1014
|
-
* @default 'error'
|
|
1015
|
-
*/
|
|
1016
|
-
conflictResolution?: ConflictResolutionStrategy;
|
|
1017
|
-
/**
|
|
1018
|
-
* Registry version
|
|
1019
|
-
* @default '1.0.0'
|
|
1020
|
-
*/
|
|
1021
|
-
version?: string;
|
|
1022
|
-
}
|
|
1023
|
-
/**
|
|
1024
|
-
* API Registry Plugin
|
|
1025
|
-
*
|
|
1026
|
-
* Registers the API Registry service in the kernel, making it available
|
|
1027
|
-
* to all plugins for endpoint registration and discovery.
|
|
1028
|
-
*
|
|
1029
|
-
* **Usage:**
|
|
1030
|
-
* ```typescript
|
|
1031
|
-
* const kernel = new ObjectKernel();
|
|
1032
|
-
*
|
|
1033
|
-
* // Register API Registry Plugin
|
|
1034
|
-
* kernel.use(createApiRegistryPlugin({ conflictResolution: 'priority' }));
|
|
1035
|
-
*
|
|
1036
|
-
* // In other plugins, access the API Registry
|
|
1037
|
-
* const plugin: Plugin = {
|
|
1038
|
-
* name: 'my-plugin',
|
|
1039
|
-
* init: async (ctx) => {
|
|
1040
|
-
* const registry = ctx.getService<ApiRegistry>('api-registry');
|
|
1041
|
-
*
|
|
1042
|
-
* // Register plugin APIs
|
|
1043
|
-
* registry.registerApi({
|
|
1044
|
-
* id: 'my_plugin_api',
|
|
1045
|
-
* name: 'My Plugin API',
|
|
1046
|
-
* type: 'rest',
|
|
1047
|
-
* version: 'v1',
|
|
1048
|
-
* basePath: '/api/v1/my-plugin',
|
|
1049
|
-
* endpoints: [...]
|
|
1050
|
-
* });
|
|
1051
|
-
* }
|
|
1052
|
-
* };
|
|
1053
|
-
* ```
|
|
1054
|
-
*
|
|
1055
|
-
* @param config - Plugin configuration
|
|
1056
|
-
* @returns Plugin instance
|
|
1057
|
-
*/
|
|
1058
|
-
declare function createApiRegistryPlugin(config?: ApiRegistryPluginConfig): Plugin;
|
|
1059
|
-
|
|
1060
830
|
/**
|
|
1061
831
|
* Interface for executing test actions against a target system.
|
|
1062
832
|
* The target could be a local Kernel instance or a remote API.
|
|
@@ -2202,7 +1972,49 @@ declare const ANONYMOUS_DENY_STATUS: 401;
|
|
|
2202
1972
|
declare const ANONYMOUS_DENY_CODE: "UNAUTHENTICATED";
|
|
2203
1973
|
/** Human-facing message. */
|
|
2204
1974
|
declare const ANONYMOUS_DENY_MESSAGE = "Authentication is required to access this endpoint.";
|
|
2205
|
-
/**
|
|
1975
|
+
/**
|
|
1976
|
+
* The **REST seam's** 401 body — flat `{ error, message }`. NOT the platform's
|
|
1977
|
+
* only one; see the two-envelope table below before you reuse this shape.
|
|
1978
|
+
*
|
|
1979
|
+
* Exactly one consumer writes it: `@objectstack/rest`'s `enforceAuth`
|
|
1980
|
+
* (`rest-server.ts` — `res.status(ANONYMOUS_DENY_STATUS).json(ANONYMOUS_DENY_BODY)`),
|
|
1981
|
+
* which owns the `/data/*` and `/meta` surfaces.
|
|
1982
|
+
*
|
|
1983
|
+
* ## Two live envelopes, one denial (#5632)
|
|
1984
|
+
*
|
|
1985
|
+
* Every HTTP seam shares the DECISION ({@link shouldDenyAnonymous}) and the
|
|
1986
|
+
* semantics ({@link ANONYMOUS_DENY_STATUS} / {@link ANONYMOUS_DENY_CODE} /
|
|
1987
|
+
* {@link ANONYMOUS_DENY_MESSAGE}). What differs is the **wrapper**:
|
|
1988
|
+
*
|
|
1989
|
+
* - **REST seam** — `@objectstack/rest` `enforceAuth`, this constant, verbatim:
|
|
1990
|
+
* `{ error: 'UNAUTHENTICATED', message: '…' }`. The code is the value of the
|
|
1991
|
+
* top-level `error` key; there is no `success` key and no nesting.
|
|
1992
|
+
* - **Dispatcher seams** — the five runtime domains `domains/ai.ts`,
|
|
1993
|
+
* `domains/meta.ts`, `domains/security.ts`, `domains/actions.ts` and
|
|
1994
|
+
* `domains/automation.ts` do NOT use this constant. Each calls
|
|
1995
|
+
* `deps.error(ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, { code: ANONYMOUS_DENY_CODE })`,
|
|
1996
|
+
* so the wire body is the dispatcher's standard wrapper:
|
|
1997
|
+
* `{ success: false, error: { code, message, httpStatus } }`.
|
|
1998
|
+
*
|
|
1999
|
+
* Both shapes are **live and sanctioned** — ADR-0112's 2026-07-30 amendment
|
|
2000
|
+
* (#4007) records the flat and wrapped envelopes as the two live ones, and
|
|
2001
|
+
* assigns retiring one of them to the envelope-convergence line (#3843 family).
|
|
2002
|
+
* Converging them is a breaking wire change; it is not this module's to make,
|
|
2003
|
+
* and this constant must not be read as if it had already happened.
|
|
2004
|
+
*
|
|
2005
|
+
* ## Reading this from a consumer (human or AI author)
|
|
2006
|
+
*
|
|
2007
|
+
* Read the envelope the seam you called DECLARES — flat from `/data` + `/meta`,
|
|
2008
|
+
* wrapped from a dispatcher-mounted surface. Do **not** write a tolerant
|
|
2009
|
+
* `body.error?.code ?? body.error` chain that swallows both: that fallback is
|
|
2010
|
+
* precisely where an envelope regression hides, and this docstring claiming to
|
|
2011
|
+
* be "the single shape every seam returns" is what used to invite it (#5632).
|
|
2012
|
+
*
|
|
2013
|
+
* Both shapes are pinned against a real booted showcase by
|
|
2014
|
+
* `packages/qa/dogfood/test/showcase-anonymous-deny-surfaces.dogfood.test.ts`,
|
|
2015
|
+
* which classifies every anonymous 401 into exactly one of the two families and
|
|
2016
|
+
* fails on a third dialect or on a seam that changes family.
|
|
2017
|
+
*/
|
|
2206
2018
|
declare const ANONYMOUS_DENY_BODY: {
|
|
2207
2019
|
readonly error: "UNAUTHENTICATED";
|
|
2208
2020
|
readonly message: "Authentication is required to access this endpoint.";
|
|
@@ -2487,9 +2299,18 @@ declare function bulkWrite<TRow, TRecord = any>(rows: TRow[], opts: BulkWriteOpt
|
|
|
2487
2299
|
* which is the same restatement this helper exists to remove.
|
|
2488
2300
|
*/
|
|
2489
2301
|
declare function engineCanRollBack<T>(engine: T): engine is T & EngineWithTransaction;
|
|
2490
|
-
/**
|
|
2302
|
+
/**
|
|
2303
|
+
* What {@link engineCanRollBack} proves is present.
|
|
2304
|
+
*
|
|
2305
|
+
* Typed FROM the contract rather than transcribed from it (#5696): a hand-copy
|
|
2306
|
+
* mirrors the signature only until the contract moves, and this one had already
|
|
2307
|
+
* started to — it predates `opts.require` and the callback's `owned` argument.
|
|
2308
|
+
* ADR-0119 D1 blessed exactly this shape for the narrow host surfaces
|
|
2309
|
+
* (`transaction?: IObjectQLEngine['transaction']`); a *narrow* surface may stay
|
|
2310
|
+
* narrow, but it may not drift from the real signature.
|
|
2311
|
+
*/
|
|
2491
2312
|
interface EngineWithTransaction {
|
|
2492
|
-
transaction
|
|
2313
|
+
transaction: IObjectQLEngine['transaction'];
|
|
2493
2314
|
}
|
|
2494
2315
|
/** What a forward/compensate callback is told about the chunk it is running. */
|
|
2495
2316
|
interface MigrationChunkContext {
|
|
@@ -3004,9 +2825,28 @@ declare class PluginHealthMonitor {
|
|
|
3004
2825
|
*/
|
|
3005
2826
|
shutdown(): void;
|
|
3006
2827
|
/**
|
|
3007
|
-
*
|
|
2828
|
+
* Race a plugin's custom health check against its timeout guard, and
|
|
2829
|
+
* reclaim the guard the moment the race settles (#4875).
|
|
2830
|
+
*
|
|
2831
|
+
* Same shape, same reasoning as `ObjectKernel.raceStartupTimeout()` (#4813,
|
|
2832
|
+
* PR #4874): the guard used to be armed and then abandoned — when the check
|
|
2833
|
+
* won the race, its `setTimeout` stayed ref'd in the event loop for the full
|
|
2834
|
+
* `config.timeout`. Health checks are *periodic*, so unlike the kernel's
|
|
2835
|
+
* one-shot startup guards the orphans here accumulate: one per plugin per
|
|
2836
|
+
* round, each pinning the loop for `config.timeout`.
|
|
2837
|
+
*
|
|
2838
|
+
* Clearing on settle rather than `unref()`-ing at arm time is deliberate.
|
|
2839
|
+
* An unref'd guard also stops pinning the loop, but it stops being a guard
|
|
2840
|
+
* as well: if the check never settles and nothing else keeps the loop alive,
|
|
2841
|
+
* Node exits before the timer can fire and the timeout is never reported.
|
|
2842
|
+
* The guard has to stay ref'd exactly as long as the race is undecided,
|
|
2843
|
+
* which is what `clearTimeout` in a `finally` expresses.
|
|
2844
|
+
*
|
|
2845
|
+
* `check` is widened to `T | PromiseLike<T>` because `checkMethod` is called
|
|
2846
|
+
* dynamically off the plugin and may be synchronous; such a check wins the
|
|
2847
|
+
* race immediately and the guard is reclaimed on the same turn.
|
|
3008
2848
|
*/
|
|
3009
|
-
private
|
|
2849
|
+
private raceCheckTimeout;
|
|
3010
2850
|
}
|
|
3011
2851
|
|
|
3012
2852
|
/**
|
|
@@ -3068,6 +2908,29 @@ declare class HotReloadManager {
|
|
|
3068
2908
|
* Trigger hot reload for a plugin
|
|
3069
2909
|
*/
|
|
3070
2910
|
reloadPlugin(pluginName: string, plugin: Plugin, version: string, getPluginState: () => Record<string, any>, restorePluginState: (state: Record<string, any>) => void): Promise<boolean>;
|
|
2911
|
+
/**
|
|
2912
|
+
* Race a plugin's `destroy()` against its shutdown-timeout guard, and
|
|
2913
|
+
* reclaim the guard the moment the race settles (#4952).
|
|
2914
|
+
*
|
|
2915
|
+
* The guard used to be armed and then abandoned — byte-for-byte the leak
|
|
2916
|
+
* #4813 fixed in the kernel's startup guards (PR #4874) and #4875 fixed in
|
|
2917
|
+
* the periodic health checks (PR #4950): when `destroy()` won the race, its
|
|
2918
|
+
* `setTimeout` stayed ref'd in the event loop for the full
|
|
2919
|
+
* `shutdownTimeout`, so a hot reload that finished in milliseconds still
|
|
2920
|
+
* pinned the loop for the whole budget — once per reload, per plugin.
|
|
2921
|
+
*
|
|
2922
|
+
* Clearing on settle rather than `unref()`-ing at arm time is deliberate.
|
|
2923
|
+
* An unref'd guard also stops pinning the loop, but it stops being a guard
|
|
2924
|
+
* as well: if `destroy()` never settles and nothing else keeps the loop
|
|
2925
|
+
* alive, Node exits before the timer can fire and the timeout is never
|
|
2926
|
+
* reported. The guard has to stay ref'd exactly as long as the race is
|
|
2927
|
+
* undecided, which is what `clearTimeout` in a `finally` expresses.
|
|
2928
|
+
*
|
|
2929
|
+
* `shutdown` is widened to `T | PromiseLike<T>` because the Plugin contract
|
|
2930
|
+
* permits a synchronous `destroy()` (`Promise<void> | void`); such a hook
|
|
2931
|
+
* wins the race immediately and the guard is reclaimed on the same turn.
|
|
2932
|
+
*/
|
|
2933
|
+
private raceShutdownTimeout;
|
|
3071
2934
|
/**
|
|
3072
2935
|
* Schedule a reload with debouncing
|
|
3073
2936
|
*/
|
|
@@ -3222,4 +3085,4 @@ declare class NamespaceResolver {
|
|
|
3222
3085
|
private suggestAlternative;
|
|
3223
3086
|
}
|
|
3224
3087
|
|
|
3225
|
-
export { ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, type AnonymousDenyInput, type ApiKeyPrincipal,
|
|
3088
|
+
export { ANONYMOUS_DENY_BODY, ANONYMOUS_DENY_CODE, ANONYMOUS_DENY_MESSAGE, ANONYMOUS_DENY_STATUS, API_KEY_PREFIX, type AnonymousDenyInput, type ApiKeyPrincipal, type AuthGate, type BucketGranularity, type BulkWriteOptions, type BulkWriteRowResult, CORE_FALLBACK_FACTORIES, type CalendarParts, DependencyResolver, type EngineWithTransaction, type ExecutionContextLike, type FilterTokenResolutionContext, type GeneratedApiKey, type GrantValidityWindow, HotReloadManager, type InterruptedRun, type KernelState, type KeyInput, type LadderPrincipal, type LadderRow, LiteKernel, type MigrationChunk, type MigrationChunkContext, MigrationJournalRefusal, type MigrationPlan, type MigrationPlanProvider, MigrationPlanRegistry, type MigrationPlanStep, type MigrationRunResult, type NamespaceCheckResult, type NamespaceConflict, type NamespaceEntry, NamespaceResolver, ObjectKernel, ObjectKernelBase, type ObjectKernelConfig, ObjectLogger, type OrderablePlugin, POSTURE_INJECTION_RULE, POSTURE_LADDER, POSTURE_RANK, type ParsedSignature, type PermissionCheckResult$1 as PermissionCheckResult, type PermissionGrant, type Plugin, type PluginArtifactVerifyResult, PluginConfigValidator, type PluginContext, PluginHealthMonitor, type PluginHealthStatus, type PluginLoadResult, PluginLoader, type PluginMetadata, type PermissionCheckResult as PluginPermissionCheckResult, PluginPermissionEnforcer, PluginPermissionManager, type PluginPermissions, PluginSandboxRuntime, PluginSecurityScanner, type PluginSignatureConfig, PluginSignatureVerifier, type PluginStartupResult, type PostureEvidence, type PublisherVerifyResult, index as QA, type ResolveAuthzInput, type ResolveLocalizationInput, type ResolveUserAuthzGrantsOptions, type ResolvedAuthzContext, type ResourceUsage, type RetryOptions, type RunMigrationJournalOptions, SIGNATURE_ALG, type SandboxContext, type ScanTarget, SecurePluginContext, type SecurityIssue, SemanticVersionManager, type ServiceFactory, ServiceLifecycle, type ServiceRegistration, type SignatureVerificationResult, UnknownFilterTokenError, UnresolvedFilterTokenError, type UserAuthzGrants, type VersionCompatibility, assertInitServiceRequirements, bucketKeyToCalendarRange, buildPermissionsFromGrants, bulkWrite, calendarPartsInTz, calendarPartsInTzOrUtc, counterSignPayload, createMemoryCache, createMemoryI18n, createMemoryJob, createMemoryMetadata, createMemoryQueue, createPluginConfigValidator, createPluginPermissionEnforcer, deepMerge, defaultIsTransientError, derivePosture, describeInitOrderFault, engineCanRollBack, evaluateAuthGate, extractApiKey, filterTokenContextFrom, findInterruptedRuns, generateApiKey, generateEd25519KeyPair, getEnv, getMemoryUsage, hashApiKey, hashMigrationPlan, isAuthGateAllowlisted, isExpired, isGrantActive, isGrantExpired, isNode, parseScopes, parseSignature, planChunks, postureVisibleRows, readAuthoredTranslationLayer, readRunJournal, resolveApiKeyPrincipal, resolveAuthzContext, resolveFilterToken, resolveFilterTokens, resolveLocale, resolveLocalizationContext, resolvePluginOrder, resolveUserAuthzGrants, resumeMigrationJournal, runMigrationJournal, safeExit, shouldDenyAnonymous, signPayload, validateInitServiceContract, verifyPayload, verifyPlatformSignature, verifyPluginArtifact, verifyPublisherSignature, wireAuthoredTranslationSync, withTransientRetry, zonedDateStartToUtcMs };
|