@weiliang0121/capix-resources 0.1.0 → 0.2.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/README.md CHANGED
@@ -17,4 +17,4 @@ This package is part of CAPiX. The npm distribution contains compiled JavaScript
17
17
 
18
18
  ## License
19
19
 
20
- MIT. Copyright (c) 2026 wei.liang. See [LICENSE](./LICENSE).
20
+ MIT. Copyright (c) 2026 wei.liang. See [LICENSE](LICENSE).
package/dist/access.js CHANGED
@@ -1,2 +1,2 @@
1
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};
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;if(this.#owner?.validate(),this.#closed)throw this.#closed;if(synchronous(this.#hooks.validate?.(),"Resource access validation"),this.#closed)throw this.#closed}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};
@@ -23,7 +23,9 @@ export declare class ResourceActivity {
23
23
  describe(error: unknown): unknown;
24
24
  close(reason: unknown): void;
25
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;
26
+ runSync<Output>(source: ResourceOperationSource, action: string, detail: ResourceOperationDescription<NoInfer<Output>>, execute: (operation: ResourceOperation) => Output): Output;
27
+ private operation;
28
+ private assertOperation;
27
29
  private returned;
28
30
  private checkReception;
29
31
  private combineWindowFailure;
package/dist/activity.js CHANGED
@@ -1,2 +1,2 @@
1
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};
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=this.operation(source,operationId,lifetime,delta=>{if(consume)try{const returned=consume(delta);Promise.resolve(returned).catch(()=>{consume=void 0})}catch{consume=void 0}});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();const lifetime=new ResourceOperationLifetime(this.window.signal);this.#operations.add(lifetime);const operation=this.operation(source,operationId,lifetime,()=>{});let outcome;try{outcome={status:"succeeded",value:execute(operation)}}catch(failure){outcome={status:"failed",failure}}finally{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}return 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.reject(outcome.failure,!0),outcome.value}operation(source,operationId,lifetime,emit){const owner=this.owner,origin=owner?Object.freeze({contextId:owner.contextId}):void 0;return Object.freeze({signal:this.window.signal,origin,onClose:__name(cleanup=>{try{return lifetime.onClose(cleanup)}catch(error){this.reject(error)}},"onClose"),emit:__name(delta=>{this.assertOperation(lifetime),emit(delta)},"emit"),facts:__name(type=>{if(this.assertOperation(lifetime),!!owner?.facts)return Object.freeze({publish:__name(event=>{this.assertOperation(lifetime);try{const fact=type.create(event),publication=Object.freeze({...source,contextId:owner.contextId,operationId,sequence:owner.nextSequence?owner.nextSequence():++this.#sequence,occurredAt:new Date().toISOString(),fact});this.assertOperation(lifetime);const error=owner.facts.publish(publication);if(error!==void 0)throw error}catch(error){this.rejectPort(error,"Required fact publication failed")}},"publish")})},"facts")})}assertOperation(lifetime){try{lifetime.assertOpen(),this.window.assertOpen(),lifetime.assertOpen()}catch(error){this.reject(error)}}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};
@@ -1,4 +1,3 @@
1
- import type { ResourceEventConsumer } from './facts.js';
2
1
  import type { ResourceActivity, ResourceOperationDescription } from './activity.js';
3
2
  import type { ResourceOperation } from './methods.js';
4
3
  import type { OperationOptions, OperationResult } from '@weiliang0121/capix-contracts';
@@ -21,44 +20,11 @@ export declare class ResourceEndpointActivity {
21
20
  parentContextId: string;
22
21
  childContextId: string;
23
22
  }>;
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
23
  bound(): void;
57
24
  available(describe: () => unknown): void;
58
25
  unavailable(error: unknown): void;
59
26
  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;
27
+ runSync<Output>(action: string, detail: ResourceOperationDescription<NoInfer<Output>>, execute: (operation: ResourceOperation) => Output): Output;
61
28
  runAsync<Output>(action: string, detail: ResourceOperationDescription<Output>, execute: () => Promise<Output>): Promise<Output>;
62
- private contentConsumer;
63
29
  private rejectPort;
64
30
  }
package/dist/endpoint.js CHANGED
@@ -1,2 +1,2 @@
1
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};
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")}}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)}rejectPort(error,message){this.activity.rejectPort(error,message)}}export{ResourceEndpointActivity};
package/dist/facts.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ import type { Fact } from '@weiliang0121/capix-changes';
1
2
  export interface ResourceEventConsumer<Event> {
2
- publish(event: Event): unknown | undefined;
3
+ readonly publish: (event: Event) => unknown | undefined;
3
4
  }
4
5
  export interface ResourceObservation {
5
6
  readonly contextId: string;
@@ -12,3 +13,13 @@ export interface ResourceObservation {
12
13
  readonly interactionId?: string;
13
14
  readonly describe: () => unknown;
14
15
  }
16
+ export interface ResourceFact {
17
+ readonly contextId: string;
18
+ readonly offerId: string;
19
+ readonly access: string;
20
+ readonly supplyId: string;
21
+ readonly operationId: string;
22
+ readonly sequence: number;
23
+ readonly occurredAt: string;
24
+ readonly fact: Fact;
25
+ }
package/dist/index.d.ts CHANGED
@@ -10,4 +10,4 @@ export { ResourceSupply, type ResourceSupplyEntry } from './supply.js';
10
10
  export { ResourceActivity, type ResourceOperationDescription } from './activity.js';
11
11
  export { ResourceEndpointActivity } from './endpoint.js';
12
12
  export { captureResourceOwner, ResourceAccessClosed, ResourcePortError, type ResourceOwner, type ResourceFailurePolicy, type ResourceWindow } from './ports.js';
13
- export type { ResourceEventConsumer, ResourceObservation } from './facts.js';
13
+ export type { ResourceEventConsumer, ResourceObservation, ResourceFact } from './facts.js';
package/dist/methods.d.ts CHANGED
@@ -1,7 +1,11 @@
1
- import type { OperationOptions, OperationResult } from '@weiliang0121/capix-contracts';
1
+ import type { FactType } from '@weiliang0121/capix-changes';
2
+ import type { ResourceEventConsumer } from './facts.js';
3
+ import type { InvocationOrigin, OperationOptions, OperationResult } from '@weiliang0121/capix-contracts';
2
4
  import type { ResourceEndpointActivity } from './endpoint.js';
3
5
  export interface ResourceOperation<Delta = never> {
4
6
  readonly signal: AbortSignal | undefined;
7
+ readonly origin: InvocationOrigin | undefined;
8
+ facts<Event>(type: FactType<Event>): ResourceEventConsumer<Event> | undefined;
5
9
  emit(delta: Delta): void;
6
10
  onClose(cleanup: (reason: unknown) => void): () => void;
7
11
  }
package/dist/ports.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import type { TranscriptEvent, MemoryEvent } from '@weiliang0121/capix-protocol';
2
- import type { ResourceEventConsumer, ResourceObservation } from './facts.js';
1
+ import type { ResourceEventConsumer, ResourceObservation, ResourceFact } from './facts.js';
3
2
  export interface ResourceFailurePolicy {
4
3
  isProtected(error: unknown): boolean;
5
4
  isCancellation(error: unknown, signal: AbortSignal): boolean;
@@ -15,8 +14,7 @@ export interface ResourceOwner {
15
14
  }>;
16
15
  readonly nextSequence?: () => number;
17
16
  readonly observation?: ResourceEventConsumer<ResourceObservation>;
18
- readonly transcript?: ResourceEventConsumer<TranscriptEvent>;
19
- readonly memory?: ResourceEventConsumer<MemoryEvent>;
17
+ readonly facts?: ResourceEventConsumer<ResourceFact>;
20
18
  readonly validate: () => void;
21
19
  readonly error?: (error: unknown, allowException?: boolean) => void;
22
20
  }
package/dist/ports.js CHANGED
@@ -1,2 +1,2 @@
1
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};
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),facts:captureConsumer(owner.facts)})}__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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weiliang0121/capix-resources",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -14,8 +14,8 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "@weiliang0121/capix-protocol": "0.1.0",
18
- "@weiliang0121/capix-contracts": "0.1.0"
17
+ "@weiliang0121/capix-contracts": "0.2.0",
18
+ "@weiliang0121/capix-changes": "0.2.0"
19
19
  },
20
20
  "description": "Resource definitions, fixed supplies, and controlled access endpoints for CAPiX.",
21
21
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  "repository": {
24
24
  "type": "git",
25
25
  "url": "git+https://github.com/weiliang0121/capix.git",
26
- "directory": "server/resources"
26
+ "directory": "packages/resources"
27
27
  },
28
28
  "engines": {
29
29
  "node": ">=22.23.2"
@@ -42,6 +42,7 @@
42
42
  },
43
43
  "scripts": {
44
44
  "build": "tsc -p tsconfig.json",
45
- "typecheck": "tsc -p tsconfig.json --noEmit"
45
+ "typecheck": "tsc -p tsconfig.json --noEmit",
46
+ "test": "node ../../scripts/test/run.mjs --package ."
46
47
  }
47
48
  }