@weiliang0121/capix-resources 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +19 -2
- package/dist/access.d.ts +22 -0
- package/dist/access.js +2 -0
- package/dist/activity.d.ts +32 -0
- package/dist/activity.js +2 -0
- package/dist/binding.d.ts +13 -0
- package/dist/binding.js +2 -0
- package/dist/endpoint.d.ts +64 -0
- package/dist/endpoint.js +2 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +2 -0
- package/dist/facts.d.ts +14 -0
- package/dist/facts.js +1 -0
- package/dist/failure.d.ts +1 -0
- package/dist/failure.js +2 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +2 -0
- package/dist/internal/initializer.d.ts +7 -0
- package/dist/internal/initializer.js +2 -0
- package/dist/internal/synchronous.d.ts +1 -0
- package/dist/internal/synchronous.js +2 -0
- package/dist/methods.d.ts +37 -0
- package/dist/methods.js +2 -0
- package/dist/offer.d.ts +51 -0
- package/dist/offer.js +2 -0
- package/dist/operation/lifetime.d.ts +17 -0
- package/dist/operation/lifetime.js +2 -0
- package/dist/operation/receive.d.ts +4 -0
- package/dist/operation/receive.js +2 -0
- package/dist/operation.d.ts +2 -0
- package/dist/operation.js +2 -0
- package/dist/ports.d.ts +28 -0
- package/dist/ports.js +2 -0
- package/dist/provider.d.ts +12 -0
- package/dist/provider.js +2 -0
- package/dist/request.d.ts +20 -0
- package/dist/request.js +2 -0
- package/dist/resource.d.ts +4 -0
- package/dist/resource.js +2 -0
- package/dist/resources.d.ts +9 -0
- package/dist/resources.js +2 -0
- package/dist/supply.d.ts +17 -0
- package/dist/supply.js +2 -0
- package/package.json +44 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wei.liang (https://github.com/weiliang0121)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @weiliang0121/capix-resources
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Resource definitions, fixed supplies, and controlled access endpoints for CAPiX.
|
|
4
|
+
|
|
5
|
+
ES modules and TypeScript declarations. Requires Node.js 22.23.2 or newer.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @weiliang0121/capix-resources
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Public entry points
|
|
12
|
+
|
|
13
|
+
- `@weiliang0121/capix-resources`
|
|
14
|
+
- `@weiliang0121/capix-resources/operation`
|
|
15
|
+
|
|
16
|
+
This package is part of CAPiX. The npm distribution contains compiled JavaScript, type declarations, and this package's MIT license. Reference services and client applications are not included in this package or the initial npm release.
|
|
17
|
+
|
|
18
|
+
## License
|
|
19
|
+
|
|
20
|
+
MIT. Copyright (c) 2026 wei.liang. See [LICENSE](./LICENSE).
|
package/dist/access.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ResourceOwner, type ResourceWindow } from './ports.js';
|
|
2
|
+
import type { ResourceRequirements } from './request.js';
|
|
3
|
+
import { ResourceSupply, type ResourceSupplyEntry } from './supply.js';
|
|
4
|
+
export interface ResourceAccessHooks {
|
|
5
|
+
readonly validate?: () => void;
|
|
6
|
+
readonly bound?: (entry: ResourceSupplyEntry) => boolean;
|
|
7
|
+
readonly available?: (entry: ResourceSupplyEntry) => boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class ResourceAccess<Resources extends object = object> implements ResourceWindow {
|
|
10
|
+
#private;
|
|
11
|
+
readonly endpoints: Readonly<Resources>;
|
|
12
|
+
readonly supply: ResourceSupply;
|
|
13
|
+
constructor(deps: ResourceRequirements<Resources>, supply: ResourceSupply | (() => ResourceSupply), owner?: ResourceOwner, hooks?: ResourceAccessHooks);
|
|
14
|
+
get signal(): AbortSignal | undefined;
|
|
15
|
+
assertOpen(): void;
|
|
16
|
+
view<Selected extends object>(deps: ResourceRequirements<Selected>): Readonly<Selected>;
|
|
17
|
+
start(): void;
|
|
18
|
+
close(): void;
|
|
19
|
+
private failOpening;
|
|
20
|
+
private local;
|
|
21
|
+
private shouldPublish;
|
|
22
|
+
}
|
package/dist/access.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{ResourceActivity}from"./activity.js";import{Initializer}from"./internal/initializer.js";import{synchronous}from"./internal/synchronous.js";import{captureResourceOwner,ResourceAccessClosed}from"./ports.js";import"./supply.js";class ResourceAccess{static{__name(this,"ResourceAccess")}endpoints;supply;#owner;#hooks;#activity;#locals=new Map;#closed;#started=!1;constructor(deps,supply,owner,hooks={}){this.#owner=captureResourceOwner(owner),this.#hooks=Object.freeze({validate:hooks.validate?.bind(hooks),bound:hooks.bound?.bind(hooks),available:hooks.available?.bind(hooks)}),this.#activity=new ResourceActivity(this,this.#owner);try{this.#activity.validate(),this.supply=(typeof supply=="function"?supply():supply).select(deps),this.#activity.validate(),this.endpoints=this.view(deps)}catch(error){this.failOpening(error)}}get signal(){return this.#owner?.signal}assertOpen(){if(this.#closed)throw this.#closed;this.#owner?.validate(),synchronous(this.#hooks.validate?.(),"Resource access validation")}view(deps){const entries=Object.keys(deps).map(name=>[name,this.supply.require(deps[name].offer)]),values={};for(const[name,entry]of entries)Object.defineProperty(values,name,{enumerable:!0,get:__name(()=>(this.#activity.validate(),this.#started||this.#activity.reject(new Error("Resource access requires a started window")),this.local(entry).endpoint.get()),"get")});return Object.freeze(values)}start(){if(this.#activity.validate(),this.#started)throw new Error("Resource access has already started");this.#started=!0;try{for(const entry of this.supply.entries){const local=this.local(entry);entry.offer.timing==="binding"&&local.endpoint.get()}this.#activity.validate()}catch(error){this.failOpening(error)}}close(){this.#closed||(this.#closed=new ResourceAccessClosed,this.#activity.close(this.#closed))}failOpening(error){let failure=error;try{this.close()}catch(closing){failure=new AggregateError([error,closing],"Resource opening and cleanup both failed",{cause:error})}this.#activity.reject(failure)}local(entry){const existing=this.#locals.get(entry);if(existing)return existing;const activity=this.#activity.forResource(entry),endpoint=new Initializer(()=>{this.#activity.validate();let material,value;try{if(material=entry.readMaterial(),this.#activity.validate(),value=entry.offer.createEndpoint(material,activity),value===void 0)throw new Error(`Unfulfilled resource request: ${entry.offer.name}`);this.#activity.validate()}catch(error){this.#activity.error(error);try{activity.unavailable(error)}catch(observation){this.#activity.reject(new AggregateError([error,observation],"Resource construction and observation both failed",{cause:error}))}throw error}return this.shouldPublish(this.#hooks.available,entry)&&activity.available(()=>entry.offer.describe(material)),this.#activity.validate(),value}),local={activity,endpoint};return this.#locals.set(entry,local),this.shouldPublish(this.#hooks.bound,entry)&&activity.bound(),this.#activity.validate(),local}shouldPublish(hook,entry){if(!hook)return!0;try{const result=synchronous(hook(entry),"Resource publication hook");if(typeof result!="boolean")throw new TypeError("Resource publication hook must return a boolean");return result}catch(error){this.#activity.reject(error)}}}export{ResourceAccess};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { OperationOptions, OperationResult } from '@weiliang0121/capix-contracts';
|
|
2
|
+
import type { ResourceOperation } from './methods.js';
|
|
3
|
+
import type { ResourceObservation } from './facts.js';
|
|
4
|
+
import { type ResourceOwner, type ResourceWindow } from './ports.js';
|
|
5
|
+
import type { ResourceSupplyEntry } from './supply.js';
|
|
6
|
+
import { ResourceEndpointActivity, type ResourceOperationSource } from './endpoint.js';
|
|
7
|
+
export type { ResourceOwner, ResourceFailurePolicy } from './ports.js';
|
|
8
|
+
export interface ResourceOperationDescription<Output> {
|
|
9
|
+
readonly input?: () => unknown;
|
|
10
|
+
readonly output?: (result: Output) => unknown;
|
|
11
|
+
}
|
|
12
|
+
export declare class ResourceActivity {
|
|
13
|
+
#private;
|
|
14
|
+
private readonly window;
|
|
15
|
+
readonly owner?: ResourceOwner | undefined;
|
|
16
|
+
constructor(window: ResourceWindow, owner?: ResourceOwner | undefined);
|
|
17
|
+
forResource(entry: ResourceSupplyEntry): ResourceEndpointActivity;
|
|
18
|
+
validate(): void;
|
|
19
|
+
error(error: unknown, allowException?: boolean): void;
|
|
20
|
+
reject(error: unknown, allowException?: boolean): never;
|
|
21
|
+
rejectPort(error: unknown, message: string): never;
|
|
22
|
+
publish(source: ResourceOperationSource, phase: ResourceObservation['phase'], describe: () => unknown, operationId?: string): void;
|
|
23
|
+
describe(error: unknown): unknown;
|
|
24
|
+
close(reason: unknown): void;
|
|
25
|
+
operate<Output, Delta = never, const Options extends OperationOptions<Output, unknown, unknown, Delta> = {}>(source: ResourceOperationSource, action: string, detail: ResourceOperationDescription<Output>, execute: (operation: ResourceOperation<Delta>) => Output | PromiseLike<Output>, options?: Options): Promise<OperationResult<Output, Options>>;
|
|
26
|
+
runSync<Output>(source: ResourceOperationSource, action: string, detail: ResourceOperationDescription<Output>, execute: () => Output): Output;
|
|
27
|
+
private returned;
|
|
28
|
+
private checkReception;
|
|
29
|
+
private combineWindowFailure;
|
|
30
|
+
private isProtected;
|
|
31
|
+
private classify;
|
|
32
|
+
}
|
package/dist/activity.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{randomUUID}from"node:crypto";import{receiveOperation}from"./operation/receive.js";import{ResourcePortError}from"./ports.js";import{ResourceEndpointActivity}from"./endpoint.js";import{isResourceAccessFailure}from"./failure.js";import{ResourceOperationLifetime}from"./operation/lifetime.js";class ResourceActivity{static{__name(this,"ResourceActivity")}window;owner;#sequence=0;#operations=new Set;constructor(window,owner){this.window=window,this.owner=owner}forResource(entry){return new ResourceEndpointActivity(this,Object.freeze({offerId:entry.offer.id,access:entry.offer.name,supplyId:entry.supplyId}))}validate(){try{this.window.assertOpen()}catch(error){this.reject(error)}}error(error,allowException=!1){try{this.owner?.error?.(error,allowException)}catch(report){throw report===error?error:new AggregateError([error,report],"Resource failure and its owner notification both failed",{cause:error})}}reject(error,allowException=!1){throw this.error(error,allowException),error}rejectPort(error,message){this.isProtected(error)&&this.reject(error),this.reject(new ResourcePortError(message,{cause:error}))}publish(source,phase,describe,operationId){const owner=this.owner;if(owner?.observation)try{const fact=Object.freeze({contextId:owner.contextId,...source,sequence:owner.nextSequence?owner.nextSequence():++this.#sequence,occurredAt:new Date().toISOString(),phase,...operationId?{interactionId:operationId}:{},describe}),error=owner.observation.publish(fact);if(error!==void 0)throw error}catch(error){this.reject(error)}}describe(error){return this.owner?.failures.describe(error)??{message:"Resource operation failed"}}close(reason){const operations=[...this.#operations];this.#operations.clear();const failures=[];for(const operation of operations)operation.close(reason),operation.failure&&failures.push(operation.failure);failures.length&&this.reject(failures.length===1?failures[0]:new AggregateError(failures,"Resource operation cleanup failures"))}async operate(source,action,detail,execute,options){this.validate();let reception,consume;try{const receiver=options?.result;if(options?.delta!==void 0&&typeof options.delta!="function")throw new TypeError("Delta receiver must be a function");if(receiver?.succeeded!==void 0&&typeof receiver.succeeded!="function")throw new TypeError("Success receiver must be a function");if(receiver?.failed!==void 0&&typeof receiver.failed!="function")throw new TypeError("Failure receiver must be a function");reception=options&&{...options,result:{succeeded:receiver?.succeeded?.bind(receiver),failed:receiver?.failed?.bind(receiver)}},consume=options?.delta?.bind(options)}catch(error){this.reject(error)}const operationId=randomUUID();this.publish(source,"started",()=>({action,input:detail.input?.()??null}),operationId),this.validate();const lifetime=new ResourceOperationLifetime(this.window.signal);this.#operations.add(lifetime);const operation=Object.freeze({signal:this.window.signal,onClose:__name(cleanup=>{try{return lifetime.onClose(cleanup)}catch(error){this.reject(error)}},"onClose"),emit:__name(delta=>{try{lifetime.assertOpen()}catch(error){this.reject(error)}if(this.validate(),!!consume)try{const returned=consume(delta);Promise.resolve(returned).catch(()=>{consume=void 0})}catch{consume=void 0}},"emit")});let outcome;try{outcome={status:"succeeded",value:await execute(operation)}}catch(failure){outcome={status:"failed",failure}}finally{consume=void 0,lifetime.finish(),this.#operations.delete(lifetime)}try{this.returned(source,action,detail,operationId,outcome)}catch(error){throw lifetime.failure&&error!==lifetime.failure&&this.reject(new AggregateError([error,lifetime.failure],"Resource observation and cleanup both failed",{cause:error})),error}lifetime.failure&&(outcome={status:"failed",failure:outcome.status==="failed"&&outcome.failure!==lifetime.failure?new AggregateError([outcome.failure,lifetime.failure],"Resource operation and cleanup both failed",{cause:outcome.failure}):lifetime.failure}),this.checkReception(outcome),lifetime.interruption&&this.reject(outcome.status==="failed"&&outcome.failure!==lifetime.interruption.reason?new AggregateError([outcome.failure,lifetime.interruption.reason],"Resource operation failed after local consumption ended",{cause:outcome.failure}):lifetime.interruption.reason),outcome.status==="failed"&&(this.isProtected(outcome.failure)||!reception?.result?.failed)&&this.reject(outcome.failure,!0);let received;try{received=await receiveOperation(outcome,reception)}catch(error){this.reject(error,!0)}return this.checkReception(outcome),received}runSync(source,action,detail,execute){this.validate();const operationId=randomUUID();this.publish(source,"started",()=>({action,input:detail.input?.()??null}),operationId),this.validate();let outcome;try{outcome={status:"succeeded",value:execute()}}catch(failure){outcome={status:"failed",failure}}return this.returned(source,action,detail,operationId,outcome),this.checkReception(outcome),outcome.status==="failed"&&this.reject(outcome.failure,!0),outcome.value}returned(source,action,detail,operationId,outcome){try{outcome.status==="succeeded"?this.publish(source,"returned",()=>({action,output:detail.output?.(outcome.value)??null}),operationId):this.publish(source,"threw",()=>({action,error:this.describe(outcome.failure)}),operationId)}catch(observation){throw outcome.status==="failed"&&observation!==outcome.failure&&this.reject(new AggregateError([outcome.failure,observation],"Resource operation and failure observation both failed",{cause:outcome.failure})),observation}}checkReception(outcome){try{this.window.assertOpen()}catch(windowFailure){this.reject(outcome.status==="failed"?this.combineWindowFailure(outcome.failure,windowFailure):windowFailure)}}combineWindowFailure(failure,windowFailure){const signal=this.window.signal;return windowFailure===failure||signal&&this.classify(failure,()=>this.owner?.failures.isCancellation(failure,signal)??!1)&&this.classify(windowFailure,()=>this.owner?.failures.isCancellation(windowFailure,signal)??!1)?failure:new AggregateError([failure,windowFailure],"Resource operation failed after its access window became unavailable",{cause:failure})}isProtected(error){return isResourceAccessFailure(error)||this.classify(error,()=>this.owner?.failures.isProtected(error)??!1)}classify(error,classify){try{const result=classify();if(typeof result!="boolean")throw Promise.resolve(result).catch(()=>{}),new TypeError("Resource failure classification must return a boolean");return result}catch(failure){this.reject(new AggregateError([error,failure],"Resource operation and failure classification both failed",{cause:error}))}}}export{ResourceActivity};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ResourceAccess, type ResourceAccessHooks } from './access.js';
|
|
2
|
+
import type { ResourceOwner } from './ports.js';
|
|
3
|
+
import { type ResourceProvider } from './provider.js';
|
|
4
|
+
import { type ResourceRequirements } from './request.js';
|
|
5
|
+
import { ResourceSupply } from './supply.js';
|
|
6
|
+
export declare class ResourceBinding<Resources extends object = object> {
|
|
7
|
+
#private;
|
|
8
|
+
private readonly supply;
|
|
9
|
+
private constructor();
|
|
10
|
+
static fromSupply<Resources extends object>(deps: ResourceRequirements<Resources>, supply: ResourceSupply): ResourceBinding<Resources>;
|
|
11
|
+
static fromProviders<Source, Resources extends object>(deps: ResourceRequirements<Resources>, providers: readonly ResourceProvider<Source>[], source: Source): ResourceBinding<Resources>;
|
|
12
|
+
open(owner?: ResourceOwner, hooks?: ResourceAccessHooks): ResourceAccess<Resources>;
|
|
13
|
+
}
|
package/dist/binding.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{ResourceAccess}from"./access.js";import{checkResourceProviders}from"./provider.js";import{resourceRequests}from"./request.js";import{ResourceSupply}from"./supply.js";class ResourceBinding{static{__name(this,"ResourceBinding")}supply;#deps;constructor(deps,supply){this.supply=supply,this.#deps=Object.freeze({...deps}),Object.freeze(this)}static fromSupply(deps,supply){const requests=Object.freeze({...deps}),selected=supply.select(requests);return new ResourceBinding(requests,()=>selected)}static fromProviders(deps,providers,source){const dependencies=Object.freeze({...deps}),requests=resourceRequests(dependencies);checkResourceProviders(requests,providers);const offers=new Set(requests.map(request=>request.offer)),selected=providers.filter(provider=>offers.has(provider.offer)).map(provider=>Object.freeze({offer:provider.offer,readMaterial:provider.readMaterial.bind(provider)}));return new ResourceBinding(dependencies,()=>ResourceSupply.capture(selected,source))}open(owner,hooks){const access=new ResourceAccess(this.#deps,this.supply,owner,hooks);try{return access.start(),access}catch(error){throw access.close(),error}}}export{ResourceBinding};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ResourceEventConsumer } from './facts.js';
|
|
2
|
+
import type { ResourceActivity, ResourceOperationDescription } from './activity.js';
|
|
3
|
+
import type { ResourceOperation } from './methods.js';
|
|
4
|
+
import type { OperationOptions, OperationResult } from '@weiliang0121/capix-contracts';
|
|
5
|
+
export interface ResourceOperationSource {
|
|
6
|
+
readonly offerId: string;
|
|
7
|
+
readonly access: string;
|
|
8
|
+
readonly supplyId: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class ResourceEndpointActivity {
|
|
11
|
+
private readonly activity;
|
|
12
|
+
private readonly source;
|
|
13
|
+
constructor(activity: ResourceActivity, source: ResourceOperationSource);
|
|
14
|
+
get access(): string;
|
|
15
|
+
get supplyId(): string;
|
|
16
|
+
get origin(): {
|
|
17
|
+
readonly contextId: string;
|
|
18
|
+
} | undefined;
|
|
19
|
+
validate(): void;
|
|
20
|
+
reception(): Readonly<{
|
|
21
|
+
parentContextId: string;
|
|
22
|
+
childContextId: string;
|
|
23
|
+
}>;
|
|
24
|
+
get transcriptObservation(): ResourceEventConsumer<Readonly<{
|
|
25
|
+
type: "transcript";
|
|
26
|
+
transcriptId: string;
|
|
27
|
+
revision: number;
|
|
28
|
+
occurredAt: string;
|
|
29
|
+
origin?: import("@weiliang0121/capix-protocol").InvocationOrigin;
|
|
30
|
+
change: Readonly<{
|
|
31
|
+
kind: "messages-appended";
|
|
32
|
+
start: number;
|
|
33
|
+
messages: readonly Readonly<import("@weiliang0121/capix-protocol").Message>[];
|
|
34
|
+
}> | Readonly<{
|
|
35
|
+
kind: "segment-started";
|
|
36
|
+
previousStart: number;
|
|
37
|
+
start: number;
|
|
38
|
+
end: number;
|
|
39
|
+
}>;
|
|
40
|
+
}>> | undefined;
|
|
41
|
+
get memoryObservation(): ResourceEventConsumer<Readonly<{
|
|
42
|
+
type: "memory";
|
|
43
|
+
memoriesId: string;
|
|
44
|
+
sequence: number;
|
|
45
|
+
occurredAt: string;
|
|
46
|
+
origin?: import("@weiliang0121/capix-protocol").InvocationOrigin;
|
|
47
|
+
change: Readonly<{
|
|
48
|
+
action: "create" | "update";
|
|
49
|
+
memoryId: string;
|
|
50
|
+
explanation: string;
|
|
51
|
+
sourceIndexes: readonly number[];
|
|
52
|
+
sourceResults?: readonly import("@weiliang0121/capix-protocol").MemoryResultSource[];
|
|
53
|
+
result: import("@weiliang0121/capix-protocol").MemoryContent;
|
|
54
|
+
}>;
|
|
55
|
+
}>> | undefined;
|
|
56
|
+
bound(): void;
|
|
57
|
+
available(describe: () => unknown): void;
|
|
58
|
+
unavailable(error: unknown): void;
|
|
59
|
+
operate<Output, Delta = never, const Options extends OperationOptions<Output, unknown, unknown, Delta> = {}>(action: string, detail: ResourceOperationDescription<Output>, execute: (operation: ResourceOperation<Delta>) => Output | PromiseLike<Output>, options?: Options): Promise<OperationResult<Output, Options>>;
|
|
60
|
+
runSync<Output>(action: string, detail: ResourceOperationDescription<Output>, execute: () => Output): Output;
|
|
61
|
+
runAsync<Output>(action: string, detail: ResourceOperationDescription<Output>, execute: () => Promise<Output>): Promise<Output>;
|
|
62
|
+
private contentConsumer;
|
|
63
|
+
private rejectPort;
|
|
64
|
+
}
|
package/dist/endpoint.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{ResourcePortError}from"./errors.js";class ResourceEndpointActivity{static{__name(this,"ResourceEndpointActivity")}activity;source;constructor(activity,source){this.activity=activity,this.source=source,Object.freeze(this)}get access(){return this.source.access}get supplyId(){return this.source.supplyId}get origin(){const owner=this.activity.owner;return owner?Object.freeze({contextId:owner.contextId}):void 0}validate(){this.activity.validate()}reception(){this.validate();try{if(!this.activity.owner?.reception)throw new ResourcePortError("Fixed operations require a parent reception binding");return this.activity.owner.reception()}catch(error){this.rejectPort(error,"Resource reception provenance failed")}}get transcriptObservation(){return this.contentConsumer(this.activity.owner?.transcript)}get memoryObservation(){return this.contentConsumer(this.activity.owner?.memory)}bound(){this.activity.publish(this.source,"bound",()=>null)}available(describe){this.activity.publish(this.source,"available",describe)}unavailable(error){this.activity.publish(this.source,"unavailable",()=>({error:this.activity.describe(error)}))}operate(action,detail,execute,options){return this.activity.operate(this.source,action,detail,execute,options)}runSync(action,detail,execute){return this.activity.runSync(this.source,action,detail,execute)}runAsync(action,detail,execute){return this.activity.operate(this.source,action,detail,execute)}contentConsumer(consumer){if(consumer)return Object.freeze({publish:__name(event=>{try{const error=consumer.publish(event);if(error!==void 0)throw error}catch(error){this.rejectPort(error,"Required content publication failed")}},"publish")})}rejectPort(error,message){this.activity.rejectPort(error,message)}}export{ResourceEndpointActivity};
|
package/dist/errors.d.ts
ADDED
package/dist/errors.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});class ResourceAccessClosed extends Error{static{__name(this,"ResourceAccessClosed")}constructor(message="Resource access window is closed"){super(message),this.name="ResourceAccessClosed"}}class ResourcePortError extends TypeError{static{__name(this,"ResourcePortError")}constructor(message,options){super(message,options),this.name="ResourcePortError"}}export{ResourceAccessClosed,ResourcePortError};
|
package/dist/facts.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ResourceEventConsumer<Event> {
|
|
2
|
+
publish(event: Event): unknown | undefined;
|
|
3
|
+
}
|
|
4
|
+
export interface ResourceObservation {
|
|
5
|
+
readonly contextId: string;
|
|
6
|
+
readonly offerId: string;
|
|
7
|
+
readonly access: string;
|
|
8
|
+
readonly supplyId: string;
|
|
9
|
+
readonly sequence: number;
|
|
10
|
+
readonly occurredAt: string;
|
|
11
|
+
readonly phase: 'bound' | 'available' | 'unavailable' | 'started' | 'returned' | 'threw';
|
|
12
|
+
readonly interactionId?: string;
|
|
13
|
+
readonly describe: () => unknown;
|
|
14
|
+
}
|
package/dist/facts.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isResourceAccessFailure(error: unknown): boolean;
|
package/dist/failure.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{ResourceAccessClosed,ResourcePortError}from"./errors.js";function isResourceAccessFailure(error){const pending=[error],visited=new Set;for(;pending.length;){const current=pending.pop();if(!(current===null||typeof current!="object"&&typeof current!="function"||visited.has(current))){visited.add(current);try{if(current instanceof ResourceAccessClosed||current instanceof ResourcePortError)return!0;if(!(current instanceof AggregateError))continue;const errors=Object.getOwnPropertyDescriptor(current,"errors");if(!errors||!("value"in errors)||!Array.isArray(errors.value))return!0;for(const[key,item]of Object.entries(Object.getOwnPropertyDescriptors(errors.value)))if(/^(0|[1-9]\d*)$/.test(key)){if(!("value"in item))return!0;pending.push(item.value)}}catch{return!0}}}return!1}__name(isResourceAccessFailure,"isResourceAccessFailure");export{isResourceAccessFailure};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { Resource } from './resource.js';
|
|
2
|
+
export { Resources } from './resources.js';
|
|
3
|
+
export { ResourceOffer, type ResourceRefinement, type ResourceCapture, type ResourceExposureDeclaration, type ResourceOfferConstructor, isResourceRefinement, applyResourceRefinement } from './offer.js';
|
|
4
|
+
export { ResourceRequest, type ResourceIdentity, type ResourceRequests, type ResourcesOf, type ResourceRequirements, resourceRequests, checkResourceRequests } from './request.js';
|
|
5
|
+
export { type ResourceProvider, type ResourceEndpointDefinition, checkResourceProviders } from './provider.js';
|
|
6
|
+
export { type ResourceOperation, type ResourceMethodDeclarations, type ResourceMethodsSource, type ResourceMethods, type ResourceMethodsDeclaration, type ResourceMethodsObservation } from './methods.js';
|
|
7
|
+
export { ResourceBinding } from './binding.js';
|
|
8
|
+
export { ResourceAccess, type ResourceAccessHooks } from './access.js';
|
|
9
|
+
export { ResourceSupply, type ResourceSupplyEntry } from './supply.js';
|
|
10
|
+
export { ResourceActivity, type ResourceOperationDescription } from './activity.js';
|
|
11
|
+
export { ResourceEndpointActivity } from './endpoint.js';
|
|
12
|
+
export { captureResourceOwner, ResourceAccessClosed, ResourcePortError, type ResourceOwner, type ResourceFailurePolicy, type ResourceWindow } from './ports.js';
|
|
13
|
+
export type { ResourceEventConsumer, ResourceObservation } from './facts.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
import{Resource}from"./resource.js";import{Resources}from"./resources.js";import{ResourceOffer,isResourceRefinement,applyResourceRefinement}from"./offer.js";import{ResourceRequest,resourceRequests,checkResourceRequests}from"./request.js";import{checkResourceProviders}from"./provider.js";import{}from"./methods.js";import{ResourceBinding}from"./binding.js";import{ResourceAccess}from"./access.js";import{ResourceSupply}from"./supply.js";import{ResourceActivity}from"./activity.js";import{ResourceEndpointActivity}from"./endpoint.js";import{captureResourceOwner,ResourceAccessClosed,ResourcePortError}from"./ports.js";export{Resource,ResourceAccess,ResourceAccessClosed,ResourceActivity,ResourceBinding,ResourceEndpointActivity,ResourceOffer,ResourcePortError,ResourceRequest,ResourceSupply,Resources,applyResourceRefinement,captureResourceOwner,checkResourceProviders,checkResourceRequests,isResourceRefinement,resourceRequests};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});class Initializer{static{__name(this,"Initializer")}create;#state={status:"idle"};constructor(create){this.create=create}get initialized(){return this.#state.status==="ready"}get(){const state=this.#state;if(state.status==="ready")return state.value;if(state.status==="failed")throw state.error;if(state.status==="creating")throw new Error("Recursive initialization");this.#state={status:"creating"};try{const value=this.create();return this.#state={status:"ready",value},value}catch(error){throw this.#state={status:"failed",error},error}}}export{Initializer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function synchronous<Value>(value: Value, label: string): Value;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{ResourcePortError}from"../errors.js";function synchronous(value,label){if(value!==null&&(typeof value=="object"||typeof value=="function")&&typeof value.then=="function")throw Promise.resolve(value).catch(()=>{}),new ResourcePortError(`${label} must complete synchronously`);return value}__name(synchronous,"synchronous");export{synchronous};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { OperationOptions, OperationResult } from '@weiliang0121/capix-contracts';
|
|
2
|
+
import type { ResourceEndpointActivity } from './endpoint.js';
|
|
3
|
+
export interface ResourceOperation<Delta = never> {
|
|
4
|
+
readonly signal: AbortSignal | undefined;
|
|
5
|
+
emit(delta: Delta): void;
|
|
6
|
+
onClose(cleanup: (reason: unknown) => void): () => void;
|
|
7
|
+
}
|
|
8
|
+
export type ResourceMethodDeclarations = Readonly<Record<string, (origin: never, input: never, operation: never) => unknown>>;
|
|
9
|
+
type MethodArguments<Method> = Method extends (...args: infer Arguments) => unknown ? Arguments : never;
|
|
10
|
+
type UnionToIntersection<Value> = (Value extends unknown ? (value: Value) => void : never) extends (value: infer Intersection) => void ? Intersection : never;
|
|
11
|
+
export type ResourceMethodsSource<Methods extends ResourceMethodDeclarations> = UnionToIntersection<MethodArguments<Methods[keyof Methods]>[0]>;
|
|
12
|
+
type MethodInput<Method> = MethodArguments<Method> extends [unknown, infer Input, ...unknown[]] ? Input : void;
|
|
13
|
+
type MethodOutput<Method> = Method extends (...args: never[]) => infer Output ? Awaited<Output> : never;
|
|
14
|
+
type MethodDelta<Method> = MethodArguments<Method> extends [unknown, unknown, ResourceOperation<infer Delta>, ...unknown[]] ? Delta : never;
|
|
15
|
+
export type ResourceMethods<Methods extends ResourceMethodDeclarations> = {
|
|
16
|
+
readonly [Name in keyof Methods]: <const Options extends OperationOptions<MethodOutput<Methods[Name]>, unknown, unknown, MethodDelta<Methods[Name]>> = {}>(input: MethodInput<Methods[Name]>, options?: Options & OperationOptions<MethodOutput<Methods[Name]>, unknown, unknown, MethodDelta<Methods[Name]>>) => Promise<OperationResult<MethodOutput<Methods[Name]>, Options>>;
|
|
17
|
+
};
|
|
18
|
+
export interface ResourceMethodsDeclaration<Methods extends ResourceMethodDeclarations, Source = ResourceMethodsSource<Methods>, Selection = never> {
|
|
19
|
+
readonly name?: string;
|
|
20
|
+
readonly methods: Methods;
|
|
21
|
+
readonly expose?: never;
|
|
22
|
+
readonly timing?: 'binding' | 'access';
|
|
23
|
+
readonly capture?: (source: Source) => ResourceMethodsSource<Methods>;
|
|
24
|
+
readonly refine?: (captured: ResourceMethodsSource<Methods>, selection: Selection) => ResourceMethodsSource<Methods>;
|
|
25
|
+
readonly observation?: ResourceMethodsObservation<Methods>;
|
|
26
|
+
}
|
|
27
|
+
export interface ResourceMethodsObservation<Methods extends ResourceMethodDeclarations> {
|
|
28
|
+
readonly source?: (source: ResourceMethodsSource<Methods>) => unknown;
|
|
29
|
+
readonly methods?: {
|
|
30
|
+
readonly [Name in keyof Methods]?: {
|
|
31
|
+
readonly input?: (input: MethodInput<Methods[Name]>) => unknown;
|
|
32
|
+
readonly output?: (output: MethodOutput<Methods[Name]>) => unknown;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export declare function resourceMethods<Methods extends ResourceMethodDeclarations>(methods: Methods, observation?: ResourceMethodsObservation<Methods>): (origin: ResourceMethodsSource<Methods>, activity: ResourceEndpointActivity) => ResourceMethods<Methods>;
|
|
37
|
+
export {};
|
package/dist/methods.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});function resourceMethods(methods,observation){const entries=Object.entries(methods).map(([name,method])=>{if(typeof method!="function")throw new TypeError(`Resource method must be a function: ${name}`);const description=observation?.methods?.[name];return{name,execute:method.bind(methods),input:description?.input?.bind(description),output:description?.output?.bind(description)}});return(origin,activity)=>Object.freeze(Object.fromEntries(entries.map(method=>[method.name,(input,options)=>activity.operate(method.name,{input:__name(()=>method.input?.(input),"input"),output:__name(output=>method.output?.(output),"output")},operation=>method.execute(origin,input,operation),options)])))}__name(resourceMethods,"resourceMethods");export{resourceMethods};
|
package/dist/offer.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ResourceEndpointActivity } from './endpoint.js';
|
|
2
|
+
import { type ResourceMethodDeclarations, type ResourceMethods, type ResourceMethodsDeclaration, type ResourceMethodsSource } from './methods.js';
|
|
3
|
+
import { ResourceRequest, type ResourceIdentity } from './request.js';
|
|
4
|
+
import type { ResourceProvider } from './provider.js';
|
|
5
|
+
export { ResourceRequest, type ResourceIdentity, type ResourceRequests, type ResourcesOf } from './request.js';
|
|
6
|
+
export type { ResourceProvider } from './provider.js';
|
|
7
|
+
declare const refinementInput: unique symbol;
|
|
8
|
+
export interface ResourceRefinement<Input> {
|
|
9
|
+
readonly offer: ResourceIdentity;
|
|
10
|
+
readonly [refinementInput]: (input: Input) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function isResourceRefinement(value: object): boolean;
|
|
13
|
+
export declare function applyResourceRefinement<Input>(refinement: ResourceRefinement<Input>, offer: ResourceIdentity, captured: unknown, input: Input): unknown;
|
|
14
|
+
export interface ResourceCapture<Source, Captured, Selection = never> {
|
|
15
|
+
readonly capture?: (source: Source) => Captured;
|
|
16
|
+
readonly describe?: (captured: Captured) => unknown;
|
|
17
|
+
readonly refine?: (captured: Captured, selection: Selection) => Captured;
|
|
18
|
+
}
|
|
19
|
+
export interface ResourceExposureDeclaration<Source, Value, Captured = Source, Selection = never> extends ResourceCapture<Source, Captured, Selection> {
|
|
20
|
+
readonly name?: string;
|
|
21
|
+
readonly expose: (captured: Captured, activity: ResourceEndpointActivity) => Value;
|
|
22
|
+
readonly methods?: never;
|
|
23
|
+
readonly timing?: 'binding' | 'access';
|
|
24
|
+
}
|
|
25
|
+
type ResourceDeclaration = ResourceMethodsDeclaration<ResourceMethodDeclarations, any, any> | ResourceExposureDeclaration<any, any, any, any>;
|
|
26
|
+
declare class ResourceOfferImplementation<Source, Value, Captured = Source, Selection = never> {
|
|
27
|
+
#private;
|
|
28
|
+
constructor(declaration: ResourceDeclaration);
|
|
29
|
+
get id(): string;
|
|
30
|
+
get name(): string;
|
|
31
|
+
get timing(): 'binding' | 'access';
|
|
32
|
+
request(): ResourceRequest<Value>;
|
|
33
|
+
refine<Input>(select: (input: Input) => Selection): ResourceRefinement<Input>;
|
|
34
|
+
provide<ProviderSource>(select: (source: ProviderSource) => Source): ResourceProvider<ProviderSource>;
|
|
35
|
+
}
|
|
36
|
+
export type ResourceOffer<Source, Value, Captured = Source, Selection = never> = ResourceOfferImplementation<Source, Value, Captured, Selection>;
|
|
37
|
+
export interface ResourceOfferConstructor {
|
|
38
|
+
new <const Methods extends ResourceMethodDeclarations, Source, Selection = never>(declaration: ResourceMethodsDeclaration<Methods, Source, Selection> & {
|
|
39
|
+
readonly capture: (source: Source) => ResourceMethodsSource<Methods>;
|
|
40
|
+
}): ResourceOffer<Source, ResourceMethods<Methods>, ResourceMethodsSource<Methods>, Selection>;
|
|
41
|
+
new <const Methods extends ResourceMethodDeclarations, Selection = never>(declaration: ResourceMethodsDeclaration<Methods, ResourceMethodsSource<Methods>, Selection> & {
|
|
42
|
+
readonly capture?: never;
|
|
43
|
+
}): ResourceOffer<ResourceMethodsSource<Methods>, ResourceMethods<Methods>, ResourceMethodsSource<Methods>, Selection>;
|
|
44
|
+
new <Source, Value, Selection = never>(declaration: ResourceExposureDeclaration<Source, Value, Source, Selection> & {
|
|
45
|
+
readonly capture?: never;
|
|
46
|
+
}): ResourceOffer<Source, Value, Source, Selection>;
|
|
47
|
+
new <Source, Value, Captured = Source, Selection = never>(declaration: ResourceExposureDeclaration<Source, Value, Captured, Selection> & {
|
|
48
|
+
readonly capture: (source: Source) => Captured;
|
|
49
|
+
}): ResourceOffer<Source, Value, Captured, Selection>;
|
|
50
|
+
}
|
|
51
|
+
export declare const ResourceOffer: ResourceOfferConstructor;
|
package/dist/offer.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{randomUUID}from"node:crypto";import{resourceMethods}from"./methods.js";import{ResourceRequest}from"./request.js";import{ResourceRequest as ResourceRequest2}from"./request.js";class IssuedResourceRefinement{static{__name(this,"IssuedResourceRefinement")}offer;constructor(offer){this.offer=offer,Object.freeze(this)}}const refinements=new WeakMap;function isResourceRefinement(value){return refinements.has(value)}__name(isResourceRefinement,"isResourceRefinement");function applyResourceRefinement(refinement,offer,captured,input){const issued=refinements.get(refinement);if(!issued||issued.offer!==offer)throw new Error("Resource refinement was not issued by this offer");return issued.apply(captured,input)}__name(applyResourceRefinement,"applyResourceRefinement");class ResourceOfferImplementation{static{__name(this,"ResourceOfferImplementation")}#identity;#createEndpoint;#capture;#refine;#describe;constructor(declaration){if(!declaration||typeof declaration!="object"||Array.isArray(declaration))throw new TypeError("Resource access requires a configuration object");const id=randomUUID(),name=declaration.name??`resource:${id}`;if(typeof name!="string"||!/\S/.test(name))throw new TypeError("Resource access name must be nonempty");if(declaration.methods&&declaration.expose)throw new TypeError("Resource declaration must use either methods or precise exposure");if(declaration.methods)this.#createEndpoint=resourceMethods(declaration.methods,declaration.observation),this.#describe=declaration.observation?.source?.bind(declaration.observation);else{if(typeof declaration.expose!="function")throw new TypeError("Resource access requires an endpoint declaration");this.#createEndpoint=declaration.expose.bind(declaration),this.#describe=declaration.describe?.bind(declaration)}this.#capture=declaration.capture?.bind(declaration),this.#refine=declaration.refine?.bind(declaration),this.#identity=Object.freeze({id,name,timing:declaration.timing??"access",createEndpoint:__name((material,activity)=>this.#createEndpoint(material,activity),"createEndpoint"),describe:__name(material=>this.#describe?.(material)??null,"describe")}),Object.freeze(this)}get id(){return this.#identity.id}get name(){return this.#identity.name}get timing(){return this.#identity.timing}request(){return new ResourceRequest(this.#identity)}refine(select){const refine=this.#refine;if(!refine)throw new Error(`Resource does not support refinement: ${this.#identity.name}`);const refinement=new IssuedResourceRefinement(this.#identity);return refinements.set(refinement,{offer:this.#identity,apply:__name((captured,input)=>refine(captured,select(input)),"apply")}),refinement}provide(select){if(typeof select!="function")throw new TypeError("Resource source selection must be a function");return Object.freeze({offer:this.#identity,readMaterial:__name(source=>{const value=select(source);return this.#capture?this.#capture(value):value},"readMaterial")})}}const ResourceOffer=ResourceOfferImplementation;export{ResourceOffer,ResourceRequest2 as ResourceRequest,applyResourceRefinement,isResourceRefinement};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ResourcePortError } from '../errors.js';
|
|
2
|
+
export declare class ResourceOperationLifetime {
|
|
3
|
+
#private;
|
|
4
|
+
private readonly signal;
|
|
5
|
+
constructor(signal: AbortSignal | undefined);
|
|
6
|
+
get interruption(): {
|
|
7
|
+
readonly reason: unknown;
|
|
8
|
+
} | undefined;
|
|
9
|
+
get failure(): ResourcePortError | undefined;
|
|
10
|
+
assertOpen(): void;
|
|
11
|
+
onClose(cleanup: (reason: unknown) => void): () => void;
|
|
12
|
+
close(reason: unknown): void;
|
|
13
|
+
finish(): void;
|
|
14
|
+
private seal;
|
|
15
|
+
private invoke;
|
|
16
|
+
private record;
|
|
17
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{ResourceAccessClosed,ResourcePortError}from"../errors.js";class ResourceOperationLifetime{static{__name(this,"ResourceOperationLifetime")}signal;#cleanups=new Set;#closed;#interruption;#failure;#cancel;constructor(signal){this.signal=signal,this.#cancel=()=>this.close(signal?.reason),signal?.addEventListener("abort",this.#cancel,{once:!0}),signal?.aborted&&this.#cancel()}get interruption(){return this.#interruption}get failure(){return this.#failure}assertOpen(){if(this.#closed)throw new ResourceAccessClosed("Resource operation output is closed")}onClose(cleanup){if(typeof cleanup!="function"){const failure=new ResourcePortError("Resource operation cleanup must be a function");throw this.record(failure),failure}if(this.#closed){const failure=this.invoke(cleanup,this.#closed.reason);if(failure)throw failure}else this.#cleanups.add(cleanup);return()=>{this.#cleanups.delete(cleanup)}}close(reason){this.#closed||(this.#interruption={reason},this.seal(reason))}finish(){this.seal(new ResourceAccessClosed("Resource operation has completed"))}seal(reason){if(!this.#closed){this.#closed={reason},this.signal?.removeEventListener("abort",this.#cancel);for(const cleanup of this.#cleanups)this.#cleanups.delete(cleanup),this.invoke(cleanup,reason)}}invoke(cleanup,reason){try{const returned=cleanup(reason);if(returned!==void 0)throw Promise.resolve(returned).catch(()=>{}),new TypeError("Resource operation cleanup must return undefined synchronously");return}catch(cause){const failure=new ResourcePortError("Resource operation cleanup failed",{cause});return this.record(failure),failure}}record(failure){this.#failure=this.#failure?new ResourcePortError("Multiple resource operation cleanups failed",{cause:new AggregateError([this.#failure,failure])}):failure}}export{ResourceOperationLifetime};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { OperationOutcome, OperationResult, Reception } from '@weiliang0121/capix-contracts';
|
|
2
|
+
export declare function receiveOperation<Value, Failure, Options extends {
|
|
3
|
+
readonly result?: Reception<Value, Failure, unknown>;
|
|
4
|
+
} = {}>(outcome: OperationOutcome<Value, Failure>, options?: Options): Promise<OperationResult<Value, Options>>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});async function receiveOperation(outcome,options){if(outcome.status==="succeeded")return options?.result?.succeeded?await options.result.succeeded(outcome.value):outcome.value;if(options?.result?.failed)return await options.result.failed(outcome.failure);throw outcome.failure}__name(receiveOperation,"receiveOperation");export{receiveOperation};
|
package/dist/ports.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TranscriptEvent, MemoryEvent } from '@weiliang0121/capix-protocol';
|
|
2
|
+
import type { ResourceEventConsumer, ResourceObservation } from './facts.js';
|
|
3
|
+
export interface ResourceFailurePolicy {
|
|
4
|
+
isProtected(error: unknown): boolean;
|
|
5
|
+
isCancellation(error: unknown, signal: AbortSignal): boolean;
|
|
6
|
+
describe(error: unknown): unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface ResourceOwner {
|
|
9
|
+
readonly contextId: string;
|
|
10
|
+
readonly failures: ResourceFailurePolicy;
|
|
11
|
+
readonly signal?: AbortSignal;
|
|
12
|
+
readonly reception?: () => Readonly<{
|
|
13
|
+
parentContextId: string;
|
|
14
|
+
childContextId: string;
|
|
15
|
+
}>;
|
|
16
|
+
readonly nextSequence?: () => number;
|
|
17
|
+
readonly observation?: ResourceEventConsumer<ResourceObservation>;
|
|
18
|
+
readonly transcript?: ResourceEventConsumer<TranscriptEvent>;
|
|
19
|
+
readonly memory?: ResourceEventConsumer<MemoryEvent>;
|
|
20
|
+
readonly validate: () => void;
|
|
21
|
+
readonly error?: (error: unknown, allowException?: boolean) => void;
|
|
22
|
+
}
|
|
23
|
+
export interface ResourceWindow {
|
|
24
|
+
readonly signal?: AbortSignal;
|
|
25
|
+
assertOpen(): void;
|
|
26
|
+
}
|
|
27
|
+
export { ResourceAccessClosed, ResourcePortError } from './errors.js';
|
|
28
|
+
export declare function captureResourceOwner(owner?: ResourceOwner): ResourceOwner | undefined;
|
package/dist/ports.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{synchronous}from"./internal/synchronous.js";import{ResourceAccessClosed,ResourcePortError}from"./errors.js";function captureResourceOwner(owner){if(!owner)return;const policy=owner.failures;if(!policy||typeof policy.isProtected!="function"||typeof policy.isCancellation!="function"||typeof policy.describe!="function")throw new TypeError("Resource owner requires a complete failure policy");if(typeof owner.validate!="function")throw new TypeError("Resource owner requires an access validator");const describe=policy.describe.bind(policy),validate=owner.validate.bind(owner),error=owner.error?.bind(owner),reception=owner.reception?.bind(owner),nextSequence=owner.nextSequence?.bind(owner);return Object.freeze({contextId:owner.contextId,signal:owner.signal,failures:Object.freeze({isProtected:policy.isProtected.bind(policy),isCancellation:policy.isCancellation.bind(policy),describe:__name(failure=>synchronous(describe(failure),"Resource failure description"),"describe")}),validate:__name(()=>{synchronous(validate(),"Resource owner validation")},"validate"),error:error?(failure,allowException)=>{synchronous(error(failure,allowException),"Resource failure reporting")}:void 0,reception:reception?()=>synchronous(reception(),"Resource reception provenance"):void 0,nextSequence:nextSequence?()=>synchronous(nextSequence(),"Resource observation sequence"):void 0,observation:captureConsumer(owner.observation),transcript:captureConsumer(owner.transcript),memory:captureConsumer(owner.memory)})}__name(captureResourceOwner,"captureResourceOwner");function captureConsumer(consumer){if(!consumer)return;const publish=consumer.publish.bind(consumer);return Object.freeze({publish:__name(event=>synchronous(publish(event),"Resource event publication"),"publish")})}__name(captureConsumer,"captureConsumer");export{ResourceAccessClosed,ResourcePortError,captureResourceOwner};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ResourceEndpointActivity } from './endpoint.js';
|
|
2
|
+
import type { ResourceIdentity, ResourceRequest } from './request.js';
|
|
3
|
+
export interface ResourceEndpointDefinition extends ResourceIdentity {
|
|
4
|
+
readonly timing: 'binding' | 'access';
|
|
5
|
+
createEndpoint(material: unknown, activity: ResourceEndpointActivity): unknown;
|
|
6
|
+
describe(material: unknown): unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface ResourceProvider<Source> {
|
|
9
|
+
readonly offer: ResourceEndpointDefinition;
|
|
10
|
+
readMaterial(source: Source): unknown;
|
|
11
|
+
}
|
|
12
|
+
export declare function checkResourceProviders<Source>(requested: readonly ResourceRequest<unknown>[], providers: readonly ResourceProvider<Source>[]): void;
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});function checkResourceProviders(requested,providers){for(const request of requested){const matches=providers.filter(provider=>provider.offer===request.offer);if(matches.length!==1)throw new Error(`Expected one resource provider for ${request.offer.name}, received ${matches.length}`)}}__name(checkResourceProviders,"checkResourceProviders");export{checkResourceProviders};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ResourceIdentity {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly name: string;
|
|
4
|
+
}
|
|
5
|
+
declare const resourceValue: unique symbol;
|
|
6
|
+
export declare class ResourceRequest<Value> {
|
|
7
|
+
readonly offer: ResourceIdentity;
|
|
8
|
+
readonly [resourceValue]: Value;
|
|
9
|
+
constructor(offer: ResourceIdentity);
|
|
10
|
+
}
|
|
11
|
+
export type ResourceRequirements<Resources extends object = object> = {
|
|
12
|
+
readonly [Key in keyof Resources]: ResourceRequest<Resources[Key]>;
|
|
13
|
+
};
|
|
14
|
+
export type ResourceRequests = Readonly<Record<string, ResourceRequest<unknown>>>;
|
|
15
|
+
export type ResourcesOf<Deps extends ResourceRequests> = {
|
|
16
|
+
readonly [Key in keyof Deps]: Deps[Key] extends ResourceRequest<infer Value> ? Value : never;
|
|
17
|
+
};
|
|
18
|
+
export declare function resourceRequests<Resources extends object>(deps: ResourceRequirements<Resources>): readonly ResourceRequest<unknown>[];
|
|
19
|
+
export declare function checkResourceRequests(available: ResourceRequirements, requested: readonly ResourceRequest<unknown>[]): void;
|
|
20
|
+
export {};
|
package/dist/request.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});class ResourceRequest{static{__name(this,"ResourceRequest")}offer;constructor(offer){this.offer=offer,Object.freeze(this)}}function resourceRequests(deps){return Object.keys(deps).map(name=>deps[name])}__name(resourceRequests,"resourceRequests");function checkResourceRequests(available,requested){const offers=new Set(resourceRequests(available).map(request=>request.offer));for(const request of requested)if(!offers.has(request.offer))throw new Error(`Child resource request is not provided: ${request.offer.name}`)}__name(checkResourceRequests,"checkResourceRequests");export{ResourceRequest,checkResourceRequests,resourceRequests};
|
package/dist/resource.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});class Resource{static{__name(this,"Resource")}origin;constructor(origin){this.origin=origin,Object.freeze(this)}}export{Resource};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ResourceBinding } from './binding.js';
|
|
2
|
+
import { ResourceOffer } from './offer.js';
|
|
3
|
+
import { Resource } from './resource.js';
|
|
4
|
+
import type { ResourceRequirements } from './request.js';
|
|
5
|
+
export declare class Resources {
|
|
6
|
+
#private;
|
|
7
|
+
register<Source, Value, Captured, Selection>(resource: Resource<NoInfer<Source>>, offer: ResourceOffer<Source, Value, Captured, Selection>): this;
|
|
8
|
+
bind<Values extends object>(deps: ResourceRequirements<Values>): ResourceBinding<Values>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{ResourceBinding}from"./binding.js";import{ResourceOffer}from"./offer.js";import{Resource}from"./resource.js";class Resources{static{__name(this,"Resources")}#providers=[];register(resource,offer){if(!(resource instanceof Resource))throw new TypeError("Resource registration requires a Resource");if(!(offer instanceof ResourceOffer))throw new TypeError("Resource registration requires an access offer");const provider=offer.provide(()=>resource.origin);if(this.#providers.some(entry=>entry.offer===provider.offer))throw new Error(`Duplicate resource registration: ${provider.offer.name}`);return this.#providers.push(provider),this}bind(deps){return ResourceBinding.fromProviders(deps,this.#providers,void 0)}}export{Resources};
|
package/dist/supply.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ResourceRefinement } from './offer.js';
|
|
2
|
+
import type { ResourceEndpointDefinition, ResourceProvider } from './provider.js';
|
|
3
|
+
import { type ResourceIdentity, type ResourceRequirements } from './request.js';
|
|
4
|
+
export interface ResourceSupplyEntry {
|
|
5
|
+
readonly offer: ResourceEndpointDefinition;
|
|
6
|
+
readonly supplyId: string;
|
|
7
|
+
readMaterial(): unknown;
|
|
8
|
+
}
|
|
9
|
+
export declare class ResourceSupply {
|
|
10
|
+
readonly entries: readonly ResourceSupplyEntry[];
|
|
11
|
+
constructor(entries?: readonly ResourceSupplyEntry[]);
|
|
12
|
+
static capture<Source>(providers: readonly ResourceProvider<Source>[], source: Source): ResourceSupply;
|
|
13
|
+
require(offer: ResourceIdentity): ResourceSupplyEntry;
|
|
14
|
+
select(deps: ResourceRequirements): ResourceSupply;
|
|
15
|
+
overlay(local: ResourceSupply): ResourceSupply;
|
|
16
|
+
refine<Input>(input: Input, rules: readonly ResourceRefinement<Input>[]): ResourceSupply;
|
|
17
|
+
}
|
package/dist/supply.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{randomUUID}from"node:crypto";import{Initializer}from"./internal/initializer.js";import{applyResourceRefinement,isResourceRefinement}from"./offer.js";import{resourceRequests}from"./request.js";class ResourceSupply{static{__name(this,"ResourceSupply")}entries;constructor(entries=[]){const offers=new Set;for(const entry of entries){if(offers.has(entry.offer))throw new Error(`Ambiguous resource supply: ${entry.offer.name}`);offers.add(entry.offer)}this.entries=Object.freeze([...entries]),Object.freeze(this)}static capture(providers,source){const offers=new Set;for(const provider of providers){if(offers.has(provider.offer))throw new Error(`Ambiguous resource supply: ${provider.offer.name}`);if(typeof provider.readMaterial!="function")throw new TypeError("Resource provider requires material selection");offers.add(provider.offer)}const entries=providers.map(provider=>{const readMaterial=provider.readMaterial.bind(provider),material=new Initializer(()=>readMaterial(source));return provider.offer.timing==="binding"&&material.get(),Object.freeze({offer:provider.offer,supplyId:randomUUID(),readMaterial:__name(()=>material.get(),"readMaterial")})});return new ResourceSupply(entries)}require(offer){const entry=this.entries.find(candidate=>candidate.offer===offer);if(!entry)throw new Error(`Unfulfilled resource request: ${offer.name}`);return entry}select(deps){const entries=[];for(const request of resourceRequests(deps)){const entry=this.require(request.offer);entries.includes(entry)||entries.push(entry)}return new ResourceSupply(entries)}overlay(local){const replaced=new Set(local.entries.map(entry=>entry.offer));return new ResourceSupply([...this.entries.filter(entry=>!replaced.has(entry.offer)),...local.entries])}refine(input,rules){const refinements=new Map;for(const rule of rules){if(!isResourceRefinement(rule))throw new Error("Resource refinement was not issued by an offer");if(!this.entries.some(entry=>entry.offer===rule.offer))throw new Error(`Refined resource is not requested: ${rule.offer.name}`);if(refinements.has(rule.offer))throw new Error(`Duplicate resource refinement: ${rule.offer.name}`);refinements.set(rule.offer,rule)}return new ResourceSupply(this.entries.map(entry=>{const rule=refinements.get(entry.offer);if(!rule)return entry;const material=applyResourceRefinement(rule,entry.offer,entry.readMaterial(),input);return Object.freeze({offer:entry.offer,supplyId:randomUUID(),readMaterial:__name(()=>material,"readMaterial")})}))}}export{ResourceSupply};
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weiliang0121/capix-resources",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./operation": {
|
|
12
|
+
"types": "./dist/operation.d.ts",
|
|
13
|
+
"import": "./dist/operation.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@weiliang0121/capix-protocol": "0.1.0",
|
|
18
|
+
"@weiliang0121/capix-contracts": "0.1.0"
|
|
19
|
+
},
|
|
20
|
+
"description": "Resource definitions, fixed supplies, and controlled access endpoints for CAPiX.",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "wei.liang (https://github.com/weiliang0121)",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/weiliang0121/capix.git",
|
|
26
|
+
"directory": "server/resources"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22.23.2"
|
|
30
|
+
},
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist/**/*.js",
|
|
35
|
+
"dist/**/*.d.ts",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"registry": "https://registry.npmjs.org"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc -p tsconfig.json",
|
|
45
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
46
|
+
}
|
|
6
47
|
}
|