@lssm-tech/module.lssm-os-control-plane 2.1.2 → 2.1.3
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/application.d.ts +43 -0
- package/dist/application.js +2 -0
- package/dist/browser/application.js +1 -0
- package/dist/browser/builder-handoff.js +1 -0
- package/dist/browser/in-memory.js +1 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/ports.js +0 -0
- package/dist/browser/runtime-node-worker.js +1 -0
- package/dist/browser/topology-controller.js +1 -0
- package/dist/browser/types.js +0 -0
- package/dist/browser/worker.js +1 -0
- package/dist/builder-candidate-admission.d.ts +30 -0
- package/dist/builder-candidate-artifacts.d.ts +12 -0
- package/dist/builder-candidate-host-types.d.ts +25 -0
- package/dist/builder-candidate-host.d.ts +14 -0
- package/dist/builder-candidate-operation.d.ts +18 -0
- package/dist/builder-candidate-queue-receipt.d.ts +3 -0
- package/dist/builder-handoff.d.ts +13 -0
- package/dist/builder-handoff.js +2 -0
- package/dist/builder-runtime-execution.d.ts +20 -0
- package/dist/builder-runtime-provider.d.ts +11 -0
- package/dist/builder-runtime-receipt-writer.d.ts +12 -0
- package/dist/in-memory.d.ts +45 -0
- package/dist/in-memory.js +2 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +2 -0
- package/dist/lssm-os-control-plane.feature.d.ts +12 -0
- package/dist/node/application.js +1 -0
- package/dist/node/builder-handoff.js +1 -0
- package/dist/node/in-memory.js +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/ports.js +0 -0
- package/dist/node/runtime-node-worker.js +1 -0
- package/dist/node/topology-controller.js +1 -0
- package/dist/node/types.js +0 -0
- package/dist/node/worker.js +1 -0
- package/dist/ports.d.ts +30 -0
- package/dist/ports.js +1 -0
- package/dist/runtime-node-worker-completion.d.ts +20 -0
- package/dist/runtime-node-worker-deadline.d.ts +16 -0
- package/dist/runtime-node-worker-receipts.d.ts +5 -0
- package/dist/runtime-node-worker-types.d.ts +40 -0
- package/dist/runtime-node-worker-validation.d.ts +16 -0
- package/dist/runtime-node-worker.d.ts +12 -0
- package/dist/runtime-node-worker.js +2 -0
- package/dist/scheduling-authority.d.ts +4 -0
- package/dist/topology-controller-authorization.d.ts +40 -0
- package/dist/topology-controller-commands.d.ts +6 -0
- package/dist/topology-controller-custody.d.ts +2 -0
- package/dist/topology-controller-disposition.d.ts +3 -0
- package/dist/topology-controller-lifecycle-forward.d.ts +2 -0
- package/dist/topology-controller-lifecycle.d.ts +4 -0
- package/dist/topology-controller-recipe-bindings.d.ts +4 -0
- package/dist/topology-controller-recipe.d.ts +6 -0
- package/dist/topology-controller-scale-transition.d.ts +2 -0
- package/dist/topology-controller-scale.d.ts +2 -0
- package/dist/topology-controller-state.d.ts +5 -0
- package/dist/topology-controller-types.d.ts +46 -0
- package/dist/topology-controller-v2.d.ts +8 -0
- package/dist/topology-controller-validation.d.ts +6 -0
- package/dist/topology-controller.d.ts +20 -0
- package/dist/topology-controller.js +2 -0
- package/dist/topology-scale-planner-choice.d.ts +10 -0
- package/dist/topology-scale-planner-composition.d.ts +3 -0
- package/dist/topology-scale-planner-decision.d.ts +14 -0
- package/dist/topology-scale-planner-results.d.ts +64 -0
- package/dist/topology-scale-planner-scope.d.ts +6 -0
- package/dist/topology-scale-planner-types.d.ts +42 -0
- package/dist/topology-scale-planner-validation.d.ts +6 -0
- package/dist/topology-scale-planner.d.ts +4 -0
- package/dist/types.d.ts +44 -0
- package/dist/types.js +1 -0
- package/dist/worker.d.ts +17 -0
- package/dist/worker.js +2 -0
- package/package.json +15 -14
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{bindProviderStepExecutionV2 as A,executeProviderStepV2 as E}from"@lssm-tech/lib.lssm-os-runtime";import{canonicalize as v,createRuntimeWorkOrderCompletionV2 as N}from"@lssm-tech/lib.lssm-os-runtime";function u(e){return{tenantId:e.tenantId,workspaceId:e.workspaceId,environmentId:e.environmentId,orderId:e.orderId}}function l(e,r){return{status:"rejected",phase:e,reason:r}}function o(e,r,t){return{status:"indeterminate",phase:e,reason:r,claim:t}}function C(e){let r=e.receipts.at(-1);if(!r)throw Error("Completion requires durable receipts.");let t=e.receipts.every((i)=>i.status==="succeeded")?"succeeded":r.status;return N({contractVersion:"2.0.0",tenantId:e.order.tenantId,workspaceId:e.order.workspaceId,environmentId:e.order.environmentId,completionId:e.completionId,orderId:e.order.orderId,workOrderDigest:e.order.workOrderDigest,claimId:e.claim.claimId,claimDigest:e.claim.claimDigest,nodeId:e.claim.nodeId,providerBindingDigest:e.claim.providerBindingDigest,leaseId:e.claim.leaseId,fencingToken:e.claim.fencingToken,attemptId:e.claim.attemptId,status:t,receiptDigests:e.receipts.map((i)=>i.attestationDigest),evidenceRefs:[...new Set(e.receipts.flatMap((i)=>i.evidenceRefs))].sort(),completedAt:e.completedAt})}function b(e,r){return v(e)===v(r)}async function W(e){let r;try{r=C(e)}catch{return o("completion","completion_invalid",e.claim)}let t=await e.deadline.call(()=>e.workOrders.complete({completion:r,expectedClaimDigest:e.claim.claimDigest,expectedFencingToken:e.claim.fencingToken}));if(t.status==="ok"&&t.value)return{status:"completed",completion:r};let i=await e.deadline.call(()=>e.workOrders.getCompletion(u(e.order)));if(i.status==="ok"&&i.value&&b(i.value,r))return{status:"completed",completion:i.value};return o("completion","completion_unconfirmed",e.claim)}class k{scheduler;#e;#r;constructor(e,r){this.scheduler=e;if(!Number.isFinite(r)||r<=0)throw Error("Runtime Node worker timeout must be positive.");let t=e.now();if(!Number.isFinite(t))throw Error("Runtime Node worker scheduler time must be finite.");this.#r=t,this.#e=t+r}async call(e){let r;try{r=this.scheduler.now()}catch{return{status:"failed"}}if(!Number.isFinite(r)||r<this.#r)return{status:"failed"};this.#r=r;let t=this.#e-r;if(t<=0)return{status:"timeout"};return new Promise((i)=>{let n=!1,a,s;try{if(a=this.scheduler.schedule(t,()=>{if(n)return;n=!0,i({status:"timeout"})}),n)return;s=e(),Promise.prototype.then.call(s,(c)=>d({status:"ok",value:c}),()=>d({status:"failed"}))}catch{d({status:"failed"})}function d(c){if(n)return;n=!0;try{a?.cancel()}catch{}i(c)}})}}var y={now:()=>performance.now(),schedule(e,r){let t=setTimeout(r,e);return{cancel:()=>clearTimeout(t)}}};import{validateProviderStepReceiptV2 as _}from"@lssm-tech/lib.lssm-os-runtime";function R(e){let r=[...e.order.steps].sort((n,a)=>n.sequence-a.sequence),t=e.receipts.map((n)=>_(n)),i=Number.NEGATIVE_INFINITY;for(let[n,a]of t.entries()){let s=r[n];if(!s||!S(a,e.order,s))throw Error("Durable receipt prefix is not authorized.");if(n<t.length-1&&a.status!=="succeeded")throw Error("Durable receipt prefix continues after a terminal step.");let d=Date.parse(a.recordedAt);if(d<i)throw Error("Durable receipt chronology is invalid.");i=d}return t}function S(e,r,t){let i=r.providerBinding;return P(e,r)&&e.orderId===r.orderId&&e.workOrderDigest===r.workOrderDigest&&e.nodeId===r.nodeId&&e.providerId===i.providerId&&e.adapterId===i.adapterId&&e.adapterVersion===i.adapterVersion&&e.adapterDigest===i.adapterDigest&&e.profileId===i.profileId&&e.profileDigest===i.profileDigest&&e.providerBindingDigest===i.bindingDigest&&e.environmentDigest===i.environmentDigest&&e.sourceDigest===i.sourceDigest&&e.qualificationBindingDigest===i.qualificationBindingDigest&&e.planDigest===t.planDigest&&e.authorizationDigest===t.authorizationDigest&&e.stepId===t.stepId&&e.action===t.action&&e.effectDigest===t.effectDigest}function P(e,r){return e.tenantId===r.tenantId&&e.workspaceId===r.workspaceId&&e.environmentId===r.environmentId}import{canonicalize as p,RuntimeTimestampSchema as x,validateRuntimeNodeEligibilityDecisionV1 as T,validateSignedRuntimeWorkOrderV2 as h}from"@lssm-tech/lib.lssm-os-runtime";function w(e){if(e.completionId.length===0)throw Error("Missing completion id.");let r=h(e.order),t=T(e.eligibilityDecision);if(t.orderId!==r.orderId||t.workOrderDigest!==r.workOrderDigest||t.nodeId!==r.nodeId||t.providerBindingDigest!==r.providerBinding.bindingDigest||!q(t,r))throw Error("Eligibility decision binding mismatch.");return r}function I(e){return x.parse(e)}function D(e){if(!e.result||e.result.revoked)return!1;let r;try{r=h(e.result.order)}catch{return!1}return p(r)===p(e.order)&&Date.parse(r.issuedAt)<=Date.parse(e.now)&&Date.parse(r.expiresAt)>Date.parse(e.now)}function O(e,r){return p(e)===p(r)}function q(e,r){return e.tenantId===r.tenantId&&e.workspaceId===r.workspaceId&&e.environmentId===r.environmentId}class B{dependencies;#e;constructor(e,r){this.dependencies=e;if(!Number.isFinite(r.operationTimeoutMs)||r.operationTimeoutMs<=0)throw Error("Runtime Node worker timeout must be positive.");this.#e=r.operationTimeoutMs}async run(e){let r;try{r=w(e)}catch{return l("input","invalid_work_order")}let t;try{t=new k(this.dependencies.scheduler??y,this.#e)}catch{return o("state","scheduler_unavailable")}let i=this.readClock();if(!i)return l("connect","invalid_trusted_clock");let n=await t.call(()=>this.dependencies.connectVerifier.verify({order:structuredClone(r),verifiedAt:i}));if(n.status==="timeout")return o("connect","verification_timeout");if(n.status==="failed")return l("connect","verification_failed");let a=this.readClock();if(!a||Date.parse(a)<Date.parse(i)||!D({order:r,result:n.value,now:a}))return l("connect","work_order_untrusted");if((await t.call(()=>this.dependencies.workOrders.putIssued(r))).status!=="ok")return o("state","issue_unconfirmed");let d=await t.call(()=>this.dependencies.workOrders.claim(e));if(d.status!=="ok")return o("claim","claim_unconfirmed");if(d.value.status==="completed")return{status:"completed",completion:d.value.completion};if(d.value.status==="rejected")return l("claim","claim_rejected");let c=d.value.claim;return this.executeClaim({deadline:t,order:r,claim:c,request:e,receiptOnly:d.value.status==="already_claimed"||c.previousClaimDigest!==void 0||c.fencingToken>1})}async executeClaim(e){let r=u(e.order),t=await e.deadline.call(()=>this.dependencies.receipts.list(r));if(t.status!=="ok")return o("receipt","receipt_state_unavailable",e.claim);let i;try{i=R({order:e.order,receipts:t.value})}catch{return o("receipt","receipt_state_untrusted",e.claim)}let n=[...e.order.steps].sort((s,d)=>s.sequence-d.sequence);while(i.length<n.length&&i.every((s)=>s.status==="succeeded")){if(e.receiptOnly)return o("claim",e.claim.previousClaimDigest!==void 0||e.claim.fencingToken>1?"prior_claim_requires_reconciliation":"active_claim_requires_reconciliation",e.claim);let s=n[i.length];if(!s)break;let d=await e.deadline.call(()=>this.dependencies.workOrders.getClaim(r));if(d.status!=="ok"||!d.value||!O(d.value,e.claim))return o("lease","claim_authority_lost",e.claim);let c=this.readClock();if(!c||Date.parse(e.order.expiresAt)<=Date.parse(c))return o("lease","work_order_expired",e.claim);let f;try{f=A({order:e.order,claim:e.claim,stepId:s.stepId,now:c})}catch{return o("lease","claim_authority_invalid",e.claim)}let m=await e.deadline.call(()=>E({execution:f,router:this.dependencies.router}));if(m.status!=="ok")return o("provider","provider_outcome_unresolved",e.claim);if((await e.deadline.call(()=>this.dependencies.receipts.append(m.value))).status!=="ok")return o("receipt","receipt_append_unconfirmed",e.claim);let V=await e.deadline.call(()=>this.dependencies.receipts.list(r));if(V.status!=="ok")return o("receipt","receipt_append_unconfirmed",e.claim);try{i=R({order:e.order,receipts:V.value})}catch{return o("receipt","receipt_state_untrusted",e.claim)}if(!i.some((g)=>g.stepId===m.value.stepId&&g.attestationDigest===m.value.attestationDigest))return o("receipt","receipt_append_unconfirmed",e.claim)}let a=this.readClock();if(!a)return o("completion","invalid_trusted_clock",e.claim);return W({deadline:e.deadline,workOrders:this.dependencies.workOrders,order:e.order,claim:e.claim,receipts:i,completionId:e.request.completionId,completedAt:a})}readClock(){try{return I(this.dependencies.clock.now())}catch{return}}}export{B as LssmOsRuntimeNodeWorkerV2};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ConnectAuthorizationRefV1, type RuntimePlanV1 } from '@lssm-tech/lib.lssm-os-runtime';
|
|
2
|
+
import type { LssmOsControlPlanePorts } from './application.js';
|
|
3
|
+
/** Verify externally issued authority against fresh state after asynchronous verification. */
|
|
4
|
+
export declare function requireSchedulingAuthority(ports: LssmOsControlPlanePorts, plan: RuntimePlanV1, reference: ConnectAuthorizationRefV1, actorRef?: string): Promise<void>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type TopologyTransitionReceiptV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
import type { ExecuteTopologyStepInputV1, TopologyControllerDependenciesV1 } from './topology-controller-types.js';
|
|
3
|
+
export declare function createAuthorizedReceipt(dependencies: TopologyControllerDependenciesV1, input: ExecuteTopologyStepInputV1, current: TopologyTransitionReceiptV1): Promise<{
|
|
4
|
+
readonly status: 'already_applied';
|
|
5
|
+
readonly value: never;
|
|
6
|
+
} | {
|
|
7
|
+
readonly status: 'conflict' | 'unavailable' | 'indeterminate';
|
|
8
|
+
readonly code: string;
|
|
9
|
+
readonly evidenceRefs: readonly string[];
|
|
10
|
+
} | {
|
|
11
|
+
status: 'ok';
|
|
12
|
+
value: {
|
|
13
|
+
contractVersion: "1.0.0";
|
|
14
|
+
scope: {
|
|
15
|
+
tenantId: string;
|
|
16
|
+
workspaceId: string;
|
|
17
|
+
productId: string;
|
|
18
|
+
applicationId: string;
|
|
19
|
+
environmentId: string;
|
|
20
|
+
};
|
|
21
|
+
evidenceRefs: {
|
|
22
|
+
id: string;
|
|
23
|
+
digest: string;
|
|
24
|
+
}[];
|
|
25
|
+
recordedAt: string;
|
|
26
|
+
receiptId: string;
|
|
27
|
+
planDigest: string;
|
|
28
|
+
operationId: string;
|
|
29
|
+
claimId: string;
|
|
30
|
+
attemptId: string;
|
|
31
|
+
fencingToken: number;
|
|
32
|
+
sourceTopologyDigest: string;
|
|
33
|
+
targetTopologyDigest: string;
|
|
34
|
+
state: "active" | "authorized" | "blocked" | "canary" | "indeterminate" | "manual_custody" | "observed" | "proposed" | "provisioning" | "rejected" | "rolled_back" | "rolling_back" | "shadowing" | "simulated" | "stabilizing" | "verified";
|
|
35
|
+
completedStepIds: string[];
|
|
36
|
+
outboxCursorRef?: string | undefined;
|
|
37
|
+
rollbackPlanDigest?: string | undefined;
|
|
38
|
+
receiptDigest: `sha256:${string}`;
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TopologyTransitionReceiptV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
import type { TopologyControllerDependenciesV1, TopologyTransitionInputV1, TopologyTransitionResultV1 } from './topology-controller-types.js';
|
|
3
|
+
export declare function recordObservedTopology(dependencies: TopologyControllerDependenciesV1, input: TopologyTransitionInputV1): Promise<TopologyTransitionResultV1>;
|
|
4
|
+
export declare function compareTopologyState(dependencies: TopologyControllerDependenciesV1, input: TopologyTransitionInputV1 & {
|
|
5
|
+
readonly expectedState: TopologyTransitionReceiptV1['state'];
|
|
6
|
+
}): Promise<TopologyTransitionResultV1>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { ExecuteTopologyStepInputV1, TopologyControllerDependenciesV1 } from './topology-controller-types.js';
|
|
2
|
+
export declare function recordIndeterminateCustody(dependencies: TopologyControllerDependenciesV1, input: ExecuteTopologyStepInputV1, recoveryRef: string): Promise<boolean>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { TopologyTransitionReceiptV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
import type { TopologyControllerDependenciesV1, TopologyTransitionInputV1 } from './topology-controller-types.js';
|
|
3
|
+
export declare function verifyTopologyDisposition(dependencies: TopologyControllerDependenciesV1, input: TopologyTransitionInputV1, current: TopologyTransitionReceiptV1): Promise<TopologyTransitionReceiptV1 | undefined>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TopologyTransitionPlanV1, TopologyTransitionReceiptV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
export declare function validTopologyLifecycleMove(current: TopologyTransitionReceiptV1, next: TopologyTransitionReceiptV1): boolean;
|
|
3
|
+
export declare function validTopologyEffectMove(current: TopologyTransitionReceiptV1, next: TopologyTransitionReceiptV1, plan: TopologyTransitionPlanV1, stepId: string): boolean;
|
|
4
|
+
export declare function canExecuteTopologyStep(current: TopologyTransitionReceiptV1, stepId: string, prerequisiteStepIds: readonly string[]): boolean;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { RuntimeTopologyProfileV1, TopologyTransitionPlanV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
export declare function validRecipeComponentDelta(source: RuntimeTopologyProfileV1, target: RuntimeTopologyProfileV1, transitionClass: TopologyTransitionPlanV1['transitionClass']): boolean;
|
|
3
|
+
export declare function sameRecipeAuthority(source: RuntimeTopologyProfileV1, target: RuntimeTopologyProfileV1, transitionClass: TopologyTransitionPlanV1['transitionClass']): boolean;
|
|
4
|
+
export declare function sameRecipeScope(source: RuntimeTopologyProfileV1, target: RuntimeTopologyProfileV1, plan: TopologyTransitionPlanV1): boolean;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RuntimeTopologyProfileV1, TopologyTransitionPlanV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
export declare function validateTopologyTransitionRecipeV1(input: {
|
|
3
|
+
readonly plan: TopologyTransitionPlanV1;
|
|
4
|
+
readonly source: RuntimeTopologyProfileV1;
|
|
5
|
+
readonly target: RuntimeTopologyProfileV1;
|
|
6
|
+
}): readonly string[];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { ProposeScaleTransitionInputV1, TopologyControllerDependenciesV1, TopologyTransitionResultV1 } from './topology-controller-types.js';
|
|
2
|
+
export declare function proposeScaleTransition(dependencies: TopologyControllerDependenciesV1, input: ProposeScaleTransitionInputV1): Promise<TopologyTransitionResultV1>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { EvaluateTopologyScaleInputV1, TopologyControllerDependenciesV1, TopologyScaleResultV1 } from './topology-controller-types.js';
|
|
2
|
+
export declare function evaluateTopologyScale(dependencies: TopologyControllerDependenciesV1, input: EvaluateTopologyScaleInputV1): Promise<TopologyScaleResultV1>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ScalabilityBindingV1, type TopologyStatePortV1 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability';
|
|
2
|
+
import { type TopologyTransitionPlanV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
3
|
+
import type { TopologyTransitionResultV1 } from './topology-controller-types.js';
|
|
4
|
+
export declare function invokeTopologyState(operation: () => Promise<unknown>, timeoutMs: number, binding: ScalabilityBindingV1, plan: TopologyTransitionPlanV1): Promise<TopologyTransitionResultV1>;
|
|
5
|
+
export declare const getTopologyTransition: (state: TopologyStatePortV1, timeoutMs: number, binding: ScalabilityBindingV1, plan: TopologyTransitionPlanV1) => Promise<TopologyTransitionResultV1>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SignedRuntimeWorkOrderV3 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node';
|
|
2
|
+
import type { AuthorizedTopologyDependenciesV1, AuthorizedTopologyDependenciesV2, BoundScalabilityValueV1, CapacityObservationPortV1, ScalabilityBindingV1, ScalabilityPortResultV1, ScalePlannerPortV1, TopologyStatePortV1 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability';
|
|
3
|
+
import type { RuntimeTopologyProfileV1, ScaleDecisionV1, ScalePolicyV1, TopologyTransitionPlanV1, TopologyTransitionReceiptV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
4
|
+
export interface TopologyControllerDependenciesV1 extends AuthorizedTopologyDependenciesV1 {
|
|
5
|
+
readonly topologyState: TopologyStatePortV1;
|
|
6
|
+
readonly capacityObservation: CapacityObservationPortV1;
|
|
7
|
+
readonly scalePlanner: ScalePlannerPortV1;
|
|
8
|
+
readonly dispositionVerifier: TopologyDispositionVerifierV1;
|
|
9
|
+
}
|
|
10
|
+
export interface TopologyControllerDependenciesV2 extends Omit<TopologyControllerDependenciesV1, 'executor'>, AuthorizedTopologyDependenciesV2 {
|
|
11
|
+
}
|
|
12
|
+
export interface TopologyDispositionVerifierV1 {
|
|
13
|
+
verify(input: {
|
|
14
|
+
readonly current: TopologyTransitionReceiptV1;
|
|
15
|
+
readonly candidate: TopologyTransitionReceiptV1;
|
|
16
|
+
readonly plan: TopologyTransitionPlanV1;
|
|
17
|
+
readonly verifiedAt: string;
|
|
18
|
+
}): Promise<TopologyTransitionReceiptV1 | undefined>;
|
|
19
|
+
}
|
|
20
|
+
export interface EvaluateTopologyScaleInputV1 {
|
|
21
|
+
readonly binding: ScalabilityBindingV1;
|
|
22
|
+
readonly policy: ScalePolicyV1;
|
|
23
|
+
}
|
|
24
|
+
export interface ProposeScaleTransitionInputV1 extends EvaluateTopologyScaleInputV1 {
|
|
25
|
+
readonly plan: TopologyTransitionPlanV1;
|
|
26
|
+
readonly receipt: TopologyTransitionReceiptV1;
|
|
27
|
+
}
|
|
28
|
+
export interface TopologyTransitionInputV1 {
|
|
29
|
+
readonly binding: ScalabilityBindingV1;
|
|
30
|
+
readonly plan: TopologyTransitionPlanV1;
|
|
31
|
+
readonly receipt: TopologyTransitionReceiptV1;
|
|
32
|
+
}
|
|
33
|
+
export interface TopologyProfileTransitionInputV1 extends TopologyTransitionInputV1 {
|
|
34
|
+
readonly sourceProfile: RuntimeTopologyProfileV1;
|
|
35
|
+
readonly targetProfile: RuntimeTopologyProfileV1;
|
|
36
|
+
}
|
|
37
|
+
export interface ExecuteTopologyStepInputV1 {
|
|
38
|
+
readonly binding: ScalabilityBindingV1;
|
|
39
|
+
readonly plan: TopologyTransitionPlanV1;
|
|
40
|
+
readonly order: Extract<SignedRuntimeWorkOrderV3, {
|
|
41
|
+
readonly purpose: 'standard';
|
|
42
|
+
}>;
|
|
43
|
+
readonly stepId: string;
|
|
44
|
+
}
|
|
45
|
+
export type TopologyScaleResultV1 = ScalabilityPortResultV1<BoundScalabilityValueV1<ScaleDecisionV1>>;
|
|
46
|
+
export type TopologyTransitionResultV1 = ScalabilityPortResultV1<BoundScalabilityValueV1<TopologyTransitionReceiptV1>>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExecuteTopologyStepInputV1, TopologyControllerDependenciesV2, TopologyTransitionResultV1 } from './topology-controller-types.js';
|
|
2
|
+
/** V2 executes one physical provider step with exact prior-receipt custody. */
|
|
3
|
+
export declare class LssmOsTopologyControllerV2 {
|
|
4
|
+
private readonly dependencies;
|
|
5
|
+
constructor(dependencies: TopologyControllerDependenciesV2);
|
|
6
|
+
executeAuthorizedStep(input: ExecuteTopologyStepInputV1): Promise<TopologyTransitionResultV1>;
|
|
7
|
+
private custody;
|
|
8
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ScalabilityBindingV1 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability';
|
|
2
|
+
import type { RuntimeTopologyProfileV1, ScaleDecisionV1, ScalePolicyV1, TopologyTransitionPlanV1, TopologyTransitionReceiptV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
3
|
+
export declare function validScalePolicy(policy: ScalePolicyV1, binding: ScalabilityBindingV1): boolean;
|
|
4
|
+
export declare function validScaleDecision(decision: ScaleDecisionV1, binding: ScalabilityBindingV1, policy: ScalePolicyV1, profile: RuntimeTopologyProfileV1, observationDigest: string, now: string): boolean;
|
|
5
|
+
export declare function validTransitionPlan(plan: TopologyTransitionPlanV1, binding: ScalabilityBindingV1): boolean;
|
|
6
|
+
export declare function validTransitionReceipt(receipt: TopologyTransitionReceiptV1, binding: ScalabilityBindingV1, plan: TopologyTransitionPlanV1): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TopologyTransitionReceiptV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
import type { EvaluateTopologyScaleInputV1, ExecuteTopologyStepInputV1, ProposeScaleTransitionInputV1, TopologyControllerDependenciesV1, TopologyProfileTransitionInputV1, TopologyScaleResultV1, TopologyTransitionInputV1, TopologyTransitionResultV1 } from './topology-controller-types.js';
|
|
3
|
+
export { validateTopologyTransitionRecipeV1 } from './topology-controller-recipe.js';
|
|
4
|
+
export * from './topology-scale-planner.js';
|
|
5
|
+
export declare class LssmOsTopologyControllerV1 {
|
|
6
|
+
private readonly dependencies;
|
|
7
|
+
constructor(dependencies: TopologyControllerDependenciesV1);
|
|
8
|
+
evaluateScale(input: EvaluateTopologyScaleInputV1): Promise<TopologyScaleResultV1>;
|
|
9
|
+
proposeScaleTransition(input: ProposeScaleTransitionInputV1): Promise<TopologyTransitionResultV1>;
|
|
10
|
+
recordObserved(input: TopologyTransitionInputV1): Promise<TopologyTransitionResultV1>;
|
|
11
|
+
recordObservedProfileTransition(input: TopologyProfileTransitionInputV1): Promise<TopologyTransitionResultV1>;
|
|
12
|
+
compareAndSetState(input: TopologyTransitionInputV1 & {
|
|
13
|
+
readonly expectedState: TopologyTransitionReceiptV1['state'];
|
|
14
|
+
}): Promise<TopologyTransitionResultV1>;
|
|
15
|
+
authorizeTransition(input: ExecuteTopologyStepInputV1): Promise<TopologyTransitionResultV1>;
|
|
16
|
+
recordVerifiedDisposition(input: TopologyTransitionInputV1 & {
|
|
17
|
+
readonly expectedState: TopologyTransitionReceiptV1['state'];
|
|
18
|
+
}): Promise<TopologyTransitionResultV1>;
|
|
19
|
+
executeAuthorizedStep(input: ExecuteTopologyStepInputV1): Promise<TopologyTransitionResultV1>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{executeAuthorizedTopologyStepV1 as Ze}from"@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability";import{verifyAuthorizedTopologyIntentV1 as ne}from"@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability";import{digestTopologyTransitionReceiptV1 as re,TopologyTransitionReceiptV1Schema as se}from"@lssm-tech/lib.lssm-os-spec/runtime-topology";async function x(e,o,t){let i=await ne(e,o);if(i.status!=="ok")return i;let a;try{a=e.clock.now()}catch{return{status:"conflict",code:"topology.invalid_clock",evidenceRefs:[]}}let r=[{id:o.order.orderId,digest:o.order.workOrderDigest},{id:o.plan.authorityRef,digest:o.plan.authorizationDigest}].sort((c,m)=>c.id<m.id?-1:c.id>m.id?1:0),n=se.safeParse({contractVersion:"1.0.0",scope:o.plan.scope,receiptId:`authorized-${o.plan.planId}`,planDigest:o.plan.planDigest,operationId:o.plan.operationId,claimId:o.plan.claimId,attemptId:o.plan.attemptId,fencingToken:o.plan.fencingToken,sourceTopologyDigest:o.plan.sourceTopologyDigest,targetTopologyDigest:o.plan.targetTopologyDigest,state:"authorized",completedStepIds:t.completedStepIds,evidenceRefs:r,recordedAt:a,receiptDigest:o.plan.planDigest});if(!n.success)return{status:"conflict",code:"topology.invalid_authorization_evidence",evidenceRefs:[]};let s=n.data;return{status:"ok",value:{...s,receiptDigest:re(s)}}}function M(e,o,t){let i=o.steps.filter((a)=>a.action!=="rollback"&&a.action!=="decommission");return i.at(-1)?.stepId===t&&i.slice(0,-1).every((a)=>e.completedStepIds.includes(a.stepId))}var A={observed:["proposed","rejected","blocked"],proposed:["simulated","rejected","blocked"],simulated:["authorized","rejected","blocked"],authorized:["provisioning","blocked"],provisioning:["shadowing","rolling_back","indeterminate","manual_custody"],shadowing:["canary","rolling_back","indeterminate","manual_custody"],canary:["active","rolling_back","indeterminate","manual_custody"],active:["stabilizing","rolling_back","indeterminate","manual_custody"],stabilizing:["verified","rolling_back","indeterminate","manual_custody"],rolling_back:["rolled_back","indeterminate","manual_custody"],indeterminate:["rolling_back","manual_custody"],rejected:[],blocked:[],verified:[],rolled_back:[],manual_custody:[]};function b(e,o){if(!A[e.state].includes(o.state))return!1;return e.completedStepIds.length===o.completedStepIds.length&&e.completedStepIds.every((t,i)=>o.completedStepIds[i]===t)}function O(e,o,t,i){let a=M(e,t,i);if(!A[e.state].includes(o.state)&&!(a&&["shadowing","canary","active","stabilizing"].includes(e.state)&&o.state==="verified"))return!1;if(e.completedStepIds.some((n,s)=>o.completedStepIds[s]!==n))return!1;let r=new Set(t.steps.map((n)=>n.stepId));return o.completedStepIds.length===e.completedStepIds.length+1&&o.completedStepIds.at(-1)===i&&new Set(o.completedStepIds).size===o.completedStepIds.length&&o.completedStepIds.every((n)=>r.has(n))&&!e.completedStepIds.includes(i)}function z(e,o,t){if(!["authorized","provisioning","shadowing","canary","active","stabilizing","rolling_back"].includes(e.state))return!1;return!e.completedStepIds.includes(o)&&t.every((i)=>e.completedStepIds.includes(i))}import{isScalabilityPortResultV1 as Se,parseBoundScalabilityValueV1 as be}from"@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability";import{TopologyTransitionReceiptV1Schema as ve}from"@lssm-tech/lib.lssm-os-spec/runtime-topology";import{hasValidScaleDecisionV1Digest as le,hasValidScalePolicyV1Digest as ce,hasValidTopologyTransitionPlanV1Digest as pe,hasValidTopologyTransitionReceiptV1Digest as de,ScaleDecisionV1Schema as ge,ScalePolicyV1Schema as ye,TopologyTransitionPlanV1Schema as me,TopologyTransitionReceiptV1Schema as ue,validateScalePolicyV1 as fe,validateTopologyTransitionPlanV1 as Te}from"@lssm-tech/lib.lssm-os-spec/runtime-topology";function E(e,o){let t=ye.safeParse(e);return Boolean(t.success&&ce(t.data)&&fe(t.data).length===0&&v(t.data.scope,o)&&t.data.sourceTopologyDigest===o.topologyDigest)}function B(e,o,t,i,a,r){let n=ge.safeParse(e),s=Date.parse(r);return Boolean(n.success&&le(n.data)&&v(n.data.scope,o)&&n.data.sourceTopologyDigest===o.topologyDigest&&n.data.policyDigest===t.policyDigest&&n.data.observationDigests.length===1&&n.data.observationDigests[0]===a&&Ve(n.data,t,i)&&Number.isFinite(s)&&Date.parse(n.data.decidedAt)<=s&&s<Date.parse(n.data.expiresAt))}function u(e,o){let t=me.safeParse(e);return Boolean(t.success&&pe(t.data)&&Te(t.data).length===0&&v(t.data.scope,o)&&t.data.sourceTopologyDigest===o.topologyDigest)}function Ve(e,o,t){let i=e.targetReplicas-t.runtimeNodeReplicas,a=["scale_in","remove_cache","remove_broker"].includes(e.action),r=["scale_out","add_cache","add_broker"].includes(e.action),n=e.action!=="no_change";return e.estimatedDailyCostEurMicros<=o.dailyCostCeilingEurMicros&&e.targetReplicas>=o.minimumReplicas&&e.targetReplicas<=o.maximumReplicas&&e.targetReplicas<=o.providerQuotaCeiling&&e.targetReplicas<=o.tenantConcurrencyCeiling&&Math.abs(i)<=o.maximumStep&&(e.action!=="scale_out"||i>0)&&(e.action!=="scale_in"||i<0)&&(e.action!=="no_change"||i===0)&&(o.freezeMode==="unfrozen"||!r)&&(o.freezeMode!=="all_frozen"||!n)&&(o.automaticMode==="bidirectional"||!a)&&(o.automaticMode!=="disabled"||!n)&&(!n||o.reversibleTransitionDigests.includes(e.targetTopologyDigest))}function p(e,o,t){let i=ue.safeParse(e);return Boolean(i.success&&de(i.data)&&v(i.data.scope,o)&&i.data.planDigest===t.planDigest&&i.data.operationId===t.operationId&&i.data.claimId===t.claimId&&i.data.attemptId===t.attemptId&&i.data.fencingToken===t.fencingToken&&i.data.sourceTopologyDigest===t.sourceTopologyDigest&&i.data.targetTopologyDigest===t.targetTopologyDigest)}function v(e,o){return e.tenantId===o.tenantId&&e.workspaceId===o.workspaceId&&e.environmentId===o.environmentId&&e.productId===o.productId&&e.applicationId===o.applicationId}async function y(e,o,t,i){let a;try{let r=await Promise.race([Promise.resolve().then(e),new Promise((s)=>{a=setTimeout(()=>s(void 0),o)})]);if(!Se(r))return h("invalid_result");if(r.status!=="ok"&&r.status!=="already_applied")return r;let n=be(r.value,t,(s)=>{let l=ve.safeParse(s);return l.success&&p(l.data,t,i)?l.data:void 0});if(!n)return h("invalid_result");return j({status:r.status,value:n})}catch{return h("dependency_failure")}finally{if(a)clearTimeout(a)}}var T=(e,o,t,i)=>y(()=>e.getTransition({...t,planDigest:i.planDigest}),o,t,i),h=(e)=>({status:"unavailable",code:e,evidenceRefs:[]});function j(e){if(e&&typeof e==="object"&&!Object.isFrozen(e)){for(let o of Object.values(e))j(o);Object.freeze(e)}return e}async function V(e,o){if(!u(o.plan,o.binding)||o.receipt.state!=="observed"||!p(o.receipt,o.binding,o.plan))return _("topology.invalid_observation");return y(()=>e.topologyState.recordObservedTransition({...o.binding,receipt:o.receipt}),e.timeoutMs,o.binding,o.plan)}async function N(e,o){if(!u(o.plan,o.binding)||!p(o.receipt,o.binding,o.plan)||!["proposed","simulated"].includes(o.receipt.state))return _("topology.invalid_transition");let t=await T(e.topologyState,e.timeoutMs,o.binding,o.plan);if(t.status!=="ok"&&t.status!=="already_applied")return t;if(t.value.value.state!==o.expectedState||!b(t.value.value,o.receipt))return _("topology.state_conflict");return y(()=>e.topologyState.compareAndSetTransition({...o.binding,expectedState:o.expectedState,receipt:o.receipt}),e.timeoutMs,o.binding,o.plan)}var _=(e)=>({status:"conflict",code:e,evidenceRefs:[]});async function I(e,o,t){let i;try{return await Promise.race([De(e,o,t),new Promise((a)=>{i=setTimeout(()=>a(!1),e.timeoutMs)})])}catch{return!1}finally{if(i)clearTimeout(i)}}async function De(e,o,t){let i=await e.operations.get({tenantId:o.binding.tenantId,workspaceId:o.binding.workspaceId,environmentId:o.binding.environmentId,operationId:o.plan.operationId});if(!i||!he(i,o))return!1;if(i.status==="indeterminate")return i.recoveryRef===t;if(i.status!=="running")return!1;let a=e.clock.now();return e.operations.transition({operation:{...i,status:"indeterminate",version:i.version+1,updatedAt:a,recoveryRef:t},expectedVersion:i.version,expectedStatus:"running",expectedAttemptId:o.plan.attemptId,expectedClaimId:o.plan.claimId,expectedFencingToken:o.plan.fencingToken})}function he(e,o){return e.attemptId===o.plan.attemptId&&e.claimId===o.plan.claimId&&e.fencingToken===o.plan.fencingToken}var _e=new Set(["rejected","blocked","indeterminate","manual_custody"]);async function L(e,o,t){if(!_e.has(o.receipt.state)||!b(t,o.receipt))return;let i;try{i=e.clock.now()}catch{return}let a;try{let r=await Promise.race([Promise.resolve().then(()=>e.dispositionVerifier.verify({current:t,candidate:o.receipt,plan:o.plan,verifiedAt:i})),new Promise((n)=>{a=setTimeout(()=>n(void 0),e.timeoutMs)})]);if(!r||r.receiptDigest!==o.receipt.receiptDigest)return;return p(r,o.binding,o.plan)&&r.state===o.receipt.state?structuredClone(r):void 0}catch{return}finally{if(a)clearTimeout(a)}}import{validateRuntimeTopologyProfileV1 as Z,validateTopologyTransitionPlanV1 as Ie}from"@lssm-tech/lib.lssm-os-spec/runtime-topology";function F(e,o,t){if(["promote_state_backend","demote_state_backend"].includes(t))return e.authorityStoreComponentId!==o.authorityStoreComponentId&&e.queueComponentId!==o.queueComponentId&&e.cacheComponentId===o.cacheComponentId;if(t==="add_cache")return!e.cacheComponentId&&Boolean(o.cacheComponentId)&&e.queueComponentId===o.queueComponentId;if(t==="remove_cache")return Boolean(e.cacheComponentId)&&!o.cacheComponentId&&e.queueComponentId===o.queueComponentId;if(["add_broker","remove_broker"].includes(t))return e.queueComponentId!==o.queueComponentId&&e.cacheComponentId===o.cacheComponentId;return!0}function q(e,o,t){let i=e.components.find((r)=>r.componentId===e.authorityStoreComponentId),a=o.components.find((r)=>r.componentId===o.authorityStoreComponentId);if(!i||!a)return!1;if(["promote_state_backend","demote_state_backend"].includes(t))return i.profileDigest!==a.profileDigest;return i.profileDigest===a.profileDigest}function K(e,o,t){let i=(a)=>Object.values(a.scope).join("\x00");return i(e)===i(o)&&i(e)===i(t)}var Pe=new Map([["t0_embedded>t1_database_only","promote_state_backend"],["t1_database_only>t0_embedded","demote_state_backend"],["t1_database_only>t2_cache_accelerated","add_cache"],["t2_cache_accelerated>t1_database_only","remove_cache"],["t1_database_only>t3_broker_backed","add_broker"],["t2_cache_accelerated>t3_broker_backed","add_broker"],["t3_broker_backed>t1_database_only","remove_broker"],["t3_broker_backed>t2_cache_accelerated","remove_broker"]]);function P(e){let o=[...Z(e.source).map((t)=>`source.${t}`),...Z(e.target).map((t)=>`target.${t}`),...Ie(e.plan)];if(e.plan.sourceTopologyDigest!==e.source.profileDigest)o.push("recipe.source_digest");if(e.plan.targetTopologyDigest!==e.target.profileDigest)o.push("recipe.target_digest");if(!K(e.source,e.target,e.plan))o.push("recipe.scope");if(!q(e.source,e.target,e.plan.transitionClass))o.push("recipe.authority_changed");if(e.source.dataClassification!==e.target.dataClassification||e.source.encryptionProfileDigest!==e.target.encryptionProfileDigest||e.source.residencyRegionIds.join("\x00")!==e.target.residencyRegionIds.join("\x00"))o.push("recipe.data_policy_changed");if(!Re(e.source.topologyKind,e.target.topologyKind,e.plan))o.push("recipe.transition_class");if(!F(e.source,e.target,e.plan.transitionClass))o.push("recipe.component_delta");return[...new Set(o)]}function Re(e,o,t){if(e===o)return["vertical_resize","scale_out","scale_in"].includes(t.transitionClass);return Pe.get(`${e}>${o}`)===t.transitionClass}import{invokeCapacityObservationPortV1 as Ce,invokeScaleDecisionPortV1 as ke,invokeTopologyProfilePortV1 as we}from"@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability";async function D(e,o){if(!E(o.policy,o.binding))return R("topology.invalid_policy");let t=await we(()=>e.topologyState.getActive(o.binding),e.timeoutMs,o.binding);if(t.status!=="ok"&&t.status!=="already_applied")return t;let i=await Ce(()=>e.capacityObservation.observe(o.binding),e.timeoutMs,o.binding);if(i.status!=="ok"&&i.status!=="already_applied")return i;let a=await ke(()=>e.scalePlanner.evaluate({...o.binding,profile:t.value.value,policy:o.policy,observations:[i.value.value]}),e.timeoutMs,o.binding);if(a.status!=="ok"&&a.status!=="already_applied")return a;let r;try{r=e.clock.now()}catch{return R("topology.invalid_clock")}return B(a.value.value,o.binding,o.policy,t.value.value,i.value.value.observationDigest,r)?a:R("topology.invalid_scale_decision")}var R=(e)=>({status:"conflict",code:e,evidenceRefs:[]});async function Y(e,o){let t=await D(e,o);if(t.status!=="ok"&&t.status!=="already_applied")return t;if(!xe(o,t.value.value))return Ae("topology.scale_plan_mismatch");return V(e,o)}function xe(e,o){let t=Me(o.action);return Boolean(t&&e.plan.transitionClass===t&&e.plan.scaleDecisionDigest===o.decisionDigest&&e.plan.sourceTopologyDigest===o.sourceTopologyDigest&&e.plan.targetTopologyDigest===o.targetTopologyDigest&&e.plan.dailyCostCeilingEurMicros<=e.policy.dailyCostCeilingEurMicros&&e.plan.observationDigests.length===o.observationDigests.length&&e.plan.observationDigests.every((i,a)=>i===o.observationDigests[a]))}function Me(e){return e==="resize_vertical"?"vertical_resize":e==="no_change"?void 0:e}var Ae=(e)=>({status:"conflict",code:e,evidenceRefs:[]});function Q(e,o,t,i,a){let r=new Map(t.metrics.map((g)=>[g.name,g.value])),n=Boolean(i&&Date.parse(a)-Date.parse(i.decidedAt)<o.cooldownSeconds*1000),s=o.thresholds.some((g)=>(r.get(g.metric)??-1)>=g.scaleUpAt),l=o.thresholds.every((g)=>(r.get(g.metric)??Number.POSITIVE_INFINITY)<g.scaleDownBelow),c=(r.get("concurrency")??Number.POSITIVE_INFINITY)===0,m=(r.get("queue_depth")??Number.POSITIVE_INFINITY)<=o.scaleDownBacklogCeiling,w=Math.min(o.maximumReplicas,o.providerQuotaCeiling,o.tenantConcurrencyCeiling);if(!n&&s&&o.freezeMode==="unfrozen"&&o.automaticMode!=="disabled"&&e.runtimeNodeReplicas<w)return H("scale_out",e.runtimeNodeReplicas,o.maximumStep,w,"threshold-scale-up");if(!n&&l&&c&&m&&o.freezeMode!=="all_frozen"&&o.automaticMode==="bidirectional"&&e.runtimeNodeReplicas>o.minimumReplicas)return H("scale_in",e.runtimeNodeReplicas,o.maximumStep,o.minimumReplicas,"threshold-scale-down");return{action:"no_change",targetReplicas:e.runtimeNodeReplicas,reasonCodes:[n?"cooldown-active":"within-hysteresis"]}}function H(e,o,t,i,a){let n=o+(e==="scale_out"?1:-1)*t;return{action:e,targetReplicas:e==="scale_out"?Math.min(n,i):Math.max(n,i),reasonCodes:[a]}}function W(e){if(!Number.isSafeInteger(e.decisionTtlMs)||e.decisionTtlMs<1||e.decisionTtlMs>300000)throw Error("topology.scale_configuration_invalid");return Object.freeze({clock:Object.freeze({now:e.clock.now.bind(e.clock)}),policyVerifier:Object.freeze({verify:e.policyVerifier.verify.bind(e.policyVerifier)}),targets:Object.freeze({resolve:e.targets.resolve.bind(e.targets)}),history:Object.freeze({getLatest:e.history.getLatest.bind(e.history),recordIfLatest:e.history.recordIfLatest.bind(e.history)}),decisionTtlMs:e.decisionTtlMs})}function U(e){if(!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(e)||new Date(e).toISOString()!==e)throw Error("invalid clock");return e}import{digestScaleDecisionV1 as Oe}from"@lssm-tech/lib.lssm-os-spec/runtime-topology";function X(e,o,t){return{decisionId:`no-change-${t.observationId}`,targetTopologyDigest:e.profileDigest,estimatedDailyCostEurMicros:0,signatureRef:o.signatureRef}}function G(e){let o={contractVersion:"1.0.0",scope:e.policy.scope,decisionId:e.target.decisionId,policyDigest:e.policy.policyDigest,observationDigests:[e.observation.observationDigest],sourceTopologyDigest:e.profile.profileDigest,targetTopologyDigest:e.target.targetTopologyDigest,action:e.action,targetReplicas:e.targetReplicas,estimatedDailyCostEurMicros:e.target.estimatedDailyCostEurMicros,reasonCodes:[...e.reasonCodes].sort(),authorityRef:e.policy.authorityRef,signatureRef:e.target.signatureRef,decidedAt:e.decidedAt,expiresAt:e.expiresAt,decisionDigest:e.profile.profileDigest};return{...o,decisionDigest:Oe(o)}}var C=(e,o)=>({status:"ok",value:{binding:e,value:o}}),J=(e,o)=>({status:"already_applied",value:{binding:e,value:o}}),f=(e)=>({status:"conflict",code:e,evidenceRefs:[]}),ee=(e)=>({status:"unavailable",code:e,evidenceRefs:[]});var S=(e,o)=>e.scope.tenantId===o.tenantId&&e.scope.workspaceId===o.workspaceId&&e.scope.environmentId===o.environmentId&&e.scope.productId===o.productId&&e.scope.applicationId===o.applicationId;function oe(e,o,t){let i=Date.parse(t),a=Date.parse(e.observedAt);return e.observedAt===e.windowEndedAt&&a<=i&&i-a<=o.sampleWindowSeconds*1000}import{CapacityObservationV1Schema as ze,hasValidCapacityObservationV1Digest as Ee,hasValidRuntimeTopologyProfileV1Digest as Be,hasValidScaleDecisionV1Digest as je,hasValidScalePolicyV1Digest as Ne,RuntimeTopologyProfileV1Schema as $e,ScaleDecisionV1Schema as Le,ScalePolicyV1Schema as Fe,validateScalePolicyV1 as qe}from"@lssm-tech/lib.lssm-os-spec/runtime-topology";function te(e,o,t,i){let a=$e.safeParse(o),r=Fe.safeParse(t);if(!a.success||!r.success||o.profileDigest!==e.topologyDigest||!t.allowedTargetKinds.includes(o.topologyKind)||t.sourceTopologyDigest!==e.topologyDigest||!S(o,e)||!S(t,e)||!Ne(t)||!Be(o)||qe(t).length>0||i.length!==1)return!1;let n=i[0];if(!ze.safeParse(n).success)return!1;return S(n,e)&&n.topologyDigest===e.topologyDigest&&Ee(n)&&Date.parse(n.windowEndedAt)-Date.parse(n.windowStartedAt)>=Math.max(t.sampleWindowSeconds,t.minimumStableSeconds)*1000}function ie(e,o,t){let i=Le.safeParse(e);if(!i.success||!je(i.data)||!S(i.data,o)||i.data.policyDigest!==t.policyDigest||i.data.sourceTopologyDigest!==o.topologyDigest)return;return Object.freeze(structuredClone(i.data))}function ae(e,o,t){if(!e||typeof e!=="object"||Array.isArray(e))return;if(Reflect.ownKeys(e).sort().join(",")!=="decisionId,estimatedDailyCostEurMicros,signatureRef,targetTopologyDigest")return;let i=structuredClone(e);if(/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/.test(i.decisionId)&&/^sha256:[a-f0-9]{64}$/.test(i.targetTopologyDigest)&&Number.isSafeInteger(i.estimatedDailyCostEurMicros)&&i.estimatedDailyCostEurMicros>=0&&i.estimatedDailyCostEurMicros<=o.dailyCostCeilingEurMicros&&/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/.test(i.signatureRef)&&(t==="no_change"||o.reversibleTransitionDigests.includes(i.targetTopologyDigest)))return Object.freeze(i)}function No(e){let o=W(e);return Object.freeze({evaluate:(t)=>Ke(o,t)})}async function Ke(e,o){try{if(o=structuredClone(o),!te(o,o.profile,o.policy,o.observations))return f("topology.scale_input_untrusted");let t=o.observations[0],i=U(e.clock.now());if(!oe(t,o.policy,i))return f("topology.scale_observation_stale");if(await e.policyVerifier.verify(structuredClone(o.policy))!==!0)return f("topology.scale_policy_untrusted");let a=await e.history.getLatest({binding:o,policyDigest:o.policy.policyDigest}),r=a?ie(a,o,o.policy):void 0;if(a&&(!r||Date.parse(r.decidedAt)>Date.parse(i)))return f("topology.scale_history_untrusted");let n=Q(o.profile,o.policy,t,r,i),s=n.action==="no_change"?X(o.profile,o.policy,t):await e.targets.resolve({binding:o,profile:o.profile,policy:o.policy,observation:t,action:n.action,targetReplicas:n.targetReplicas,decidedAt:i}),l=ae(s,o.policy,n.action);if(!l)return f("topology.scale_target_untrusted");let c=G({profile:o.profile,policy:o.policy,observation:t,...n,target:l,decidedAt:i,expiresAt:new Date(Date.parse(i)+e.decisionTtlMs).toISOString()});if(n.action==="no_change")return C(o,c);if(await e.history.recordIfLatest({binding:o,policyDigest:o.policy.policyDigest,expectedDecisionDigest:r?.decisionDigest,decision:c}))return C(o,c);let m=await e.history.getLatest({binding:o,policyDigest:o.policy.policyDigest});return m?.decisionDigest===c.decisionDigest?J(o,m):f("topology.scale_decision_race")}catch{return ee("topology.scale_dependency_unavailable")}}class Ye{dependencies;constructor(e){this.dependencies=e;if(!Number.isFinite(e.timeoutMs)||e.timeoutMs<=0)throw Error("Topology controller timeout must be positive.")}async evaluateScale(e){return D(this.dependencies,e)}async proposeScaleTransition(e){return Y(this.dependencies,e)}async recordObserved(e){return V(this.dependencies,e)}async recordObservedProfileTransition(e){if(P({plan:e.plan,source:e.sourceProfile,target:e.targetProfile}).length>0)return d("topology.invalid_transition_recipe");return V(this.dependencies,e)}async compareAndSetState(e){return N(this.dependencies,e)}async authorizeTransition(e){if(!u(e.plan,e.binding))return d("topology.invalid_plan");let o=await T(this.dependencies.topologyState,this.dependencies.timeoutMs,e.binding,e.plan);if(o.status!=="ok"&&o.status!=="already_applied")return o;if(o.value.value.state!=="simulated")return d("topology.state_conflict");let t=await x(this.dependencies,e,o.value.value);if(t.status!=="ok")return t;return y(()=>this.dependencies.topologyState.compareAndSetTransition({...e.binding,expectedState:"simulated",receipt:t.value}),this.dependencies.timeoutMs,e.binding,e.plan)}async recordVerifiedDisposition(e){if(!u(e.plan,e.binding)||!p(e.receipt,e.binding,e.plan))return d("topology.invalid_disposition");let o=await T(this.dependencies.topologyState,this.dependencies.timeoutMs,e.binding,e.plan);if(o.status!=="ok"&&o.status!=="already_applied")return o;if(o.value.value.state!==e.expectedState)return d("topology.state_conflict");let t=await L(this.dependencies,e,o.value.value);if(!t)return d("topology.disposition_unverified");return y(()=>this.dependencies.topologyState.compareAndSetTransition({...e.binding,expectedState:e.expectedState,receipt:t}),this.dependencies.timeoutMs,e.binding,e.plan)}async executeAuthorizedStep(e){if(!u(e.plan,e.binding))return d("topology.invalid_plan");let o=e.plan.steps.find((n)=>n.stepId===e.stepId);if(!o)return d("topology.step_not_found");let t=await T(this.dependencies.topologyState,this.dependencies.timeoutMs,e.binding,e.plan);if(t.status!=="ok"&&t.status!=="already_applied")return t;if(!z(t.value.value,o.stepId,o.prerequisiteStepIds))return d("topology.step_not_ready");let i=await Ze({clock:this.dependencies.clock,operations:this.dependencies.operations,connectVerifier:this.dependencies.connectVerifier,qualificationAuthority:this.dependencies.qualificationAuthority,executor:this.dependencies.executor,timeoutMs:this.dependencies.timeoutMs},e);if(i.status!=="ok"&&i.status!=="already_applied")return i;if(!O(t.value.value,i.value.value,e.plan,e.stepId)){let n=await I(this.dependencies,e,i.value.value.receiptId);return k(n?"topology.invalid_effect_receipt":"topology.effect_custody_unconfirmed",[i.value.value.receiptId])}let a=await y(()=>this.dependencies.topologyState.compareAndSetTransition({...e.binding,expectedState:t.value.value.state,receipt:i.value.value}),this.dependencies.timeoutMs,e.binding,e.plan);if(a.status==="ok"||a.status==="already_applied")return a;return await I(this.dependencies,e,i.value.value.receiptId)?k("topology.effect_persist_unconfirmed",[i.value.value.receiptId]):k("topology.effect_custody_unconfirmed",[i.value.value.receiptId])}}var d=(e)=>({status:"conflict",code:e,evidenceRefs:[]}),k=(e,o=[])=>({status:"indeterminate",code:e,evidenceRefs:o});export{Ye as LssmOsTopologyControllerV1,No as createDeterministicScalePlannerV1,P as validateTopologyTransitionRecipeV1};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CapacityObservationV1, RuntimeTopologyProfileV1, ScaleDecisionV1, ScalePolicyV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
export declare function chooseScaleAction(profile: RuntimeTopologyProfileV1, policy: ScalePolicyV1, observation: CapacityObservationV1, latest: ScaleDecisionV1 | undefined, now: string): {
|
|
3
|
+
action: 'no_change';
|
|
4
|
+
targetReplicas: number;
|
|
5
|
+
reasonCodes: string[];
|
|
6
|
+
} | {
|
|
7
|
+
action: "scale_in" | "scale_out";
|
|
8
|
+
targetReplicas: number;
|
|
9
|
+
reasonCodes: string[];
|
|
10
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DeterministicScalePlannerDependenciesV1 } from './topology-scale-planner-types.js';
|
|
2
|
+
export declare function captureScalePlannerDependencies(value: DeterministicScalePlannerDependenciesV1): DeterministicScalePlannerDependenciesV1;
|
|
3
|
+
export declare function exactPlannerTime(value: string): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CapacityObservationV1, RuntimeTopologyProfileV1, ScaleDecisionV1, ScalePolicyV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
2
|
+
import type { ScaleDecisionTargetV1 } from './topology-scale-planner-types.js';
|
|
3
|
+
export declare function noChangeTarget(profile: RuntimeTopologyProfileV1, policy: ScalePolicyV1, observation: CapacityObservationV1): ScaleDecisionTargetV1;
|
|
4
|
+
export declare function createScaleDecisionV1(input: {
|
|
5
|
+
profile: RuntimeTopologyProfileV1;
|
|
6
|
+
policy: ScalePolicyV1;
|
|
7
|
+
observation: CapacityObservationV1;
|
|
8
|
+
action: ScaleDecisionV1['action'];
|
|
9
|
+
targetReplicas: number;
|
|
10
|
+
target: ScaleDecisionTargetV1;
|
|
11
|
+
decidedAt: string;
|
|
12
|
+
expiresAt: string;
|
|
13
|
+
reasonCodes: readonly string[];
|
|
14
|
+
}): ScaleDecisionV1;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ScalabilityBindingV1, ScalabilityPortResultV1 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability';
|
|
2
|
+
import type { ScaleDecisionV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
3
|
+
export declare const okScaleDecision: (binding: ScalabilityBindingV1, value: ScaleDecisionV1) => {
|
|
4
|
+
status: 'ok';
|
|
5
|
+
value: {
|
|
6
|
+
binding: ScalabilityBindingV1;
|
|
7
|
+
value: {
|
|
8
|
+
contractVersion: "1.0.0";
|
|
9
|
+
scope: {
|
|
10
|
+
tenantId: string;
|
|
11
|
+
workspaceId: string;
|
|
12
|
+
productId: string;
|
|
13
|
+
applicationId: string;
|
|
14
|
+
environmentId: string;
|
|
15
|
+
};
|
|
16
|
+
decisionId: string;
|
|
17
|
+
policyDigest: string;
|
|
18
|
+
observationDigests: string[];
|
|
19
|
+
sourceTopologyDigest: string;
|
|
20
|
+
targetTopologyDigest: string;
|
|
21
|
+
action: "add_broker" | "add_cache" | "no_change" | "remove_broker" | "remove_cache" | "repartition" | "resize_vertical" | "scale_in" | "scale_out";
|
|
22
|
+
targetReplicas: number;
|
|
23
|
+
estimatedDailyCostEurMicros: number;
|
|
24
|
+
reasonCodes: string[];
|
|
25
|
+
authorityRef: string;
|
|
26
|
+
signatureRef: string;
|
|
27
|
+
decidedAt: string;
|
|
28
|
+
expiresAt: string;
|
|
29
|
+
decisionDigest: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export declare const alreadyScaleDecision: (binding: ScalabilityBindingV1, value: ScaleDecisionV1) => {
|
|
34
|
+
status: 'already_applied';
|
|
35
|
+
value: {
|
|
36
|
+
binding: ScalabilityBindingV1;
|
|
37
|
+
value: {
|
|
38
|
+
contractVersion: "1.0.0";
|
|
39
|
+
scope: {
|
|
40
|
+
tenantId: string;
|
|
41
|
+
workspaceId: string;
|
|
42
|
+
productId: string;
|
|
43
|
+
applicationId: string;
|
|
44
|
+
environmentId: string;
|
|
45
|
+
};
|
|
46
|
+
decisionId: string;
|
|
47
|
+
policyDigest: string;
|
|
48
|
+
observationDigests: string[];
|
|
49
|
+
sourceTopologyDigest: string;
|
|
50
|
+
targetTopologyDigest: string;
|
|
51
|
+
action: "add_broker" | "add_cache" | "no_change" | "remove_broker" | "remove_cache" | "repartition" | "resize_vertical" | "scale_in" | "scale_out";
|
|
52
|
+
targetReplicas: number;
|
|
53
|
+
estimatedDailyCostEurMicros: number;
|
|
54
|
+
reasonCodes: string[];
|
|
55
|
+
authorityRef: string;
|
|
56
|
+
signatureRef: string;
|
|
57
|
+
decidedAt: string;
|
|
58
|
+
expiresAt: string;
|
|
59
|
+
decisionDigest: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
export declare const conflictScaleDecision: (code: string) => ScalabilityPortResultV1<never>;
|
|
64
|
+
export declare const unavailableScaleDecision: (code: string) => ScalabilityPortResultV1<never>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ScalabilityBindingV1 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability';
|
|
2
|
+
import type { CapacityObservationV1, ScalePolicyV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
3
|
+
export declare const samePlannerScope: (value: {
|
|
4
|
+
readonly scope: CapacityObservationV1['scope'];
|
|
5
|
+
}, binding: ScalabilityBindingV1) => boolean;
|
|
6
|
+
export declare function validObservationTime(observation: CapacityObservationV1, policy: ScalePolicyV1, now: string): boolean;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ScalabilityBindingV1 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability';
|
|
2
|
+
import type { CapacityObservationV1, RuntimeTopologyProfileV1, ScaleDecisionV1, ScalePolicyV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
3
|
+
export interface ScaleDecisionTargetV1 {
|
|
4
|
+
readonly decisionId: string;
|
|
5
|
+
readonly targetTopologyDigest: `sha256:${string}`;
|
|
6
|
+
readonly estimatedDailyCostEurMicros: number;
|
|
7
|
+
readonly signatureRef: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ScaleDecisionTargetPortV1 {
|
|
10
|
+
resolve(input: {
|
|
11
|
+
readonly binding: ScalabilityBindingV1;
|
|
12
|
+
readonly profile: RuntimeTopologyProfileV1;
|
|
13
|
+
readonly policy: ScalePolicyV1;
|
|
14
|
+
readonly observation: CapacityObservationV1;
|
|
15
|
+
readonly action: 'scale_out' | 'scale_in';
|
|
16
|
+
readonly targetReplicas: number;
|
|
17
|
+
readonly decidedAt: string;
|
|
18
|
+
}): Promise<unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface ScaleDecisionHistoryPortV1 {
|
|
21
|
+
getLatest(input: {
|
|
22
|
+
readonly binding: ScalabilityBindingV1;
|
|
23
|
+
readonly policyDigest: `sha256:${string}`;
|
|
24
|
+
}): Promise<ScaleDecisionV1 | undefined>;
|
|
25
|
+
recordIfLatest(input: {
|
|
26
|
+
readonly binding: ScalabilityBindingV1;
|
|
27
|
+
readonly policyDigest: `sha256:${string}`;
|
|
28
|
+
readonly expectedDecisionDigest?: `sha256:${string}`;
|
|
29
|
+
readonly decision: ScaleDecisionV1;
|
|
30
|
+
}): Promise<boolean>;
|
|
31
|
+
}
|
|
32
|
+
export interface DeterministicScalePlannerDependenciesV1 {
|
|
33
|
+
readonly clock: {
|
|
34
|
+
now(): string;
|
|
35
|
+
};
|
|
36
|
+
readonly policyVerifier: {
|
|
37
|
+
verify(policy: ScalePolicyV1): Promise<boolean>;
|
|
38
|
+
};
|
|
39
|
+
readonly targets: ScaleDecisionTargetPortV1;
|
|
40
|
+
readonly history: ScaleDecisionHistoryPortV1;
|
|
41
|
+
readonly decisionTtlMs: number;
|
|
42
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ScalabilityBindingV1 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability';
|
|
2
|
+
import { type CapacityObservationV1, type RuntimeTopologyProfileV1, type ScaleDecisionV1, type ScalePolicyV1 } from '@lssm-tech/lib.lssm-os-spec/runtime-topology';
|
|
3
|
+
import type { ScaleDecisionTargetV1 } from './topology-scale-planner-types.js';
|
|
4
|
+
export declare function validPlannerInput(binding: ScalabilityBindingV1, profile: RuntimeTopologyProfileV1, policy: ScalePolicyV1, observations: readonly CapacityObservationV1[]): boolean;
|
|
5
|
+
export declare function parseScaleHistory(decision: ScaleDecisionV1, binding: ScalabilityBindingV1, policy: ScalePolicyV1): ScaleDecisionV1 | undefined;
|
|
6
|
+
export declare function parseScaleTarget(value: unknown, policy: ScalePolicyV1, action: ScaleDecisionV1['action']): ScaleDecisionTargetV1 | undefined;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ScalePlannerPortV1 } from '@lssm-tech/lib.lssm-os-runtime/runtime-node/scalability';
|
|
2
|
+
import type { DeterministicScalePlannerDependenciesV1 } from './topology-scale-planner-types.js';
|
|
3
|
+
export type * from './topology-scale-planner-types.js';
|
|
4
|
+
export declare function createDeterministicScalePlannerV1(dependencies: DeterministicScalePlannerDependenciesV1): ScalePlannerPortV1;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { PlatformHandoffPacket, PlatformHandoffReceipt } from '@lssm-tech/lib.builder-spec';
|
|
2
|
+
import type { ConnectAuthorizationRefV1, ExecutionRecordV1, RuntimePlanV1, RuntimeScopeV1 } from '@lssm-tech/lib.lssm-os-runtime';
|
|
3
|
+
export interface ScheduledWorkOrderV1 extends RuntimeScopeV1 {
|
|
4
|
+
readonly contractVersion: '1.0.0';
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly planId: string;
|
|
7
|
+
readonly planDigest: string;
|
|
8
|
+
readonly authorizationRef: ConnectAuthorizationRefV1;
|
|
9
|
+
readonly executionId: string;
|
|
10
|
+
readonly idempotencyKey: string;
|
|
11
|
+
readonly status: 'queued' | 'leased' | 'retry_wait' | 'completed' | 'failed' | 'indeterminate';
|
|
12
|
+
readonly attempts: number;
|
|
13
|
+
readonly maxAttempts: number;
|
|
14
|
+
readonly nextAttemptAt?: string;
|
|
15
|
+
readonly queuedAt: string;
|
|
16
|
+
readonly lease?: {
|
|
17
|
+
readonly holderId: string;
|
|
18
|
+
readonly fencingToken: number;
|
|
19
|
+
readonly expiresAt: string;
|
|
20
|
+
};
|
|
21
|
+
readonly executionStatus?: ExecutionRecordV1['status'];
|
|
22
|
+
}
|
|
23
|
+
/** Admission requires an exact current permit and state revisions after verifier I/O.
|
|
24
|
+
* Enqueueing is not execution authority; workers revalidate before effects.
|
|
25
|
+
*/
|
|
26
|
+
export interface ScheduleApplyInputV1 {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly plan: RuntimePlanV1;
|
|
29
|
+
readonly authorizationRef: ConnectAuthorizationRefV1;
|
|
30
|
+
readonly executionId: string;
|
|
31
|
+
readonly idempotencyKey: string;
|
|
32
|
+
readonly queuedAt: string;
|
|
33
|
+
readonly maxAttempts?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface ClaimedWorkOrderV1 {
|
|
36
|
+
readonly workOrder: ScheduledWorkOrderV1;
|
|
37
|
+
readonly holderId: string;
|
|
38
|
+
readonly fencingToken: number;
|
|
39
|
+
}
|
|
40
|
+
export interface BuilderHandoffAcceptanceV1 {
|
|
41
|
+
readonly packet: PlatformHandoffPacket;
|
|
42
|
+
readonly receipt: PlatformHandoffReceipt;
|
|
43
|
+
readonly acceptedPlanId?: string;
|
|
44
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RuntimeScopeV1 } from '@lssm-tech/lib.lssm-os-runtime';
|
|
2
|
+
import type { LssmOsControlPlane } from './application.js';
|
|
3
|
+
import type { ControlPlaneWorkOrderPort } from './ports.js';
|
|
4
|
+
/** Apply errors are ambiguous unless the executor supplies a terminal receipt.
|
|
5
|
+
* Retain indeterminate custody for reconciliation instead of blindly retrying effects.
|
|
6
|
+
*/
|
|
7
|
+
export declare class LssmOsControlPlaneWorker {
|
|
8
|
+
private readonly controlPlane;
|
|
9
|
+
private readonly workOrders;
|
|
10
|
+
constructor(controlPlane: LssmOsControlPlane, workOrders: ControlPlaneWorkOrderPort);
|
|
11
|
+
runNext(input: {
|
|
12
|
+
readonly scope: RuntimeScopeV1;
|
|
13
|
+
readonly holderId: string;
|
|
14
|
+
readonly now: string;
|
|
15
|
+
readonly leaseTtlMs: number;
|
|
16
|
+
}): Promise<import("./types").ScheduledWorkOrderV1 | undefined>;
|
|
17
|
+
}
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
class n{controlPlane;workOrders;constructor(e,r){this.controlPlane=e;this.workOrders=r}async runNext(e){let r=await this.workOrders.claim({scope:e.scope,holderId:e.holderId,now:e.now,ttlMs:e.leaseTtlMs});if(!r)return;let o="failed";try{let t=await this.controlPlane.apply({scope:e.scope,planId:r.workOrder.planId,planDigest:r.workOrder.planDigest,authorizationRef:r.workOrder.authorizationRef,executionId:r.workOrder.executionId,idempotencyKey:r.workOrder.idempotencyKey,holderId:e.holderId,leaseTtlMs:e.leaseTtlMs});o=d(t.status)}catch{o="indeterminate"}return await this.workOrders.complete({scope:e.scope,workOrderId:r.workOrder.id,holderId:r.holderId,fencingToken:r.fencingToken,executionStatus:o}),this.workOrders.get(e.scope,r.workOrder.id)}}function d(e){if(e==="failed"||e==="succeeded"||e==="rolled_back"||e==="indeterminate")return e;return"indeterminate"}export{n as LssmOsControlPlaneWorker};
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lssm-tech/module.lssm-os-control-plane",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Tenant-safe application services and scheduling for the LSSM OS control plane.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
|
-
"
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
10
11
|
],
|
|
11
12
|
"scripts": {
|
|
12
13
|
"publish:pkg": "bun publish --tolerate-republish --ignore-scripts --verbose",
|
|
@@ -23,20 +24,20 @@
|
|
|
23
24
|
"typecheck": "tsgo --noEmit"
|
|
24
25
|
},
|
|
25
26
|
"dependencies": {
|
|
26
|
-
"@lssm-tech/lib.builder-spec": "
|
|
27
|
-
"@lssm-tech/lib.contracts-spec": "
|
|
28
|
-
"@lssm-tech/lib.crypto-utils": "
|
|
29
|
-
"@lssm-tech/lib.lssm-os-runtime": "
|
|
30
|
-
"@lssm-tech/lib.lssm-os-spec": "
|
|
31
|
-
"@lssm-tech/lib.schema": "
|
|
32
|
-
"zod": "
|
|
33
|
-
"@lssm-tech/lib.builder-runtime": "
|
|
34
|
-
"@lssm-tech/lib.contractspec-connect": "
|
|
27
|
+
"@lssm-tech/lib.builder-spec": "^2.1.2",
|
|
28
|
+
"@lssm-tech/lib.contracts-spec": "^17.3.3",
|
|
29
|
+
"@lssm-tech/lib.crypto-utils": "^2.0.2",
|
|
30
|
+
"@lssm-tech/lib.lssm-os-runtime": "^2.1.2",
|
|
31
|
+
"@lssm-tech/lib.lssm-os-spec": "^2.0.2",
|
|
32
|
+
"@lssm-tech/lib.schema": "^6.0.3",
|
|
33
|
+
"zod": "^4.6.5",
|
|
34
|
+
"@lssm-tech/lib.builder-runtime": "^3.0.3",
|
|
35
|
+
"@lssm-tech/lib.contractspec-connect": "^0.1.3"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
|
-
"@lssm-tech/tool.bun": "
|
|
38
|
-
"@lssm-tech/tool.typescript": "
|
|
39
|
-
"typescript": "
|
|
38
|
+
"@lssm-tech/tool.bun": "5.0.4",
|
|
39
|
+
"@lssm-tech/tool.typescript": "5.0.2",
|
|
40
|
+
"typescript": "^7.0.2"
|
|
40
41
|
},
|
|
41
42
|
"exports": {
|
|
42
43
|
".": "./src/index.ts",
|