wardens 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -1
- package/README.md +15 -12
- package/dist/wardens.mjs +87 -0
- package/dist/wardens.umd.js +1 -1
- package/package.json +14 -14
- package/src/bind-context.ts +2 -3
- package/dist/wardens.es.d.ts +0 -1
- package/dist/wardens.es.js +0 -102
- package/dist/wardens.umd.d.ts +0 -1
package/CHANGELOG.md
CHANGED
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [0.4.1] - 2023-01-14
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
|
13
|
+
- Newer versions of TypeScript complained about signatures in `bindContext(...)`.
|
14
|
+
|
9
15
|
## [0.4.0] - 2022-06-19
|
10
16
|
|
11
17
|
### Added
|
@@ -54,7 +60,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
54
60
|
- `mount`/`unmount` hooks to provision resources
|
55
61
|
- `allocate`/`deallocate` for creating hierarchies of resources
|
56
62
|
|
57
|
-
[Unreleased]: https://github.com/PsychoLlama/wardens/compare/v0.4.
|
63
|
+
[Unreleased]: https://github.com/PsychoLlama/wardens/compare/v0.4.1...HEAD
|
64
|
+
[0.4.1]: https://github.com/PsychoLlama/wardens/compare/v0.4.0...v0.4.1
|
58
65
|
[0.4.0]: https://github.com/PsychoLlama/wardens/compare/v0.3.0...v0.4.0
|
59
66
|
[0.3.0]: https://github.com/PsychoLlama/wardens/compare/v0.2.0...v0.3.0
|
60
67
|
[0.2.0]: https://github.com/PsychoLlama/wardens/compare/v0.1.0...v0.2.0
|
package/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
<div align="center">
|
2
2
|
<h1>Wardens</h1>
|
3
3
|
<p>A tiny framework for managing resources.</p>
|
4
|
-
<img alt="Build status" src="https://img.shields.io/github/workflow/status/PsychoLlama/wardens/
|
4
|
+
<img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/PsychoLlama/wardens/test.yml?branch=main" />
|
5
5
|
<img alt="TypeScript" src="https://img.shields.io/npm/types/wardens" />
|
6
6
|
<img alt="npm version" src="https://img.shields.io/npm/v/wardens" />
|
7
7
|
</div>
|
@@ -14,7 +14,7 @@ Here's an example: let's say you've got a thread pool, one per CPU. Each thread
|
|
14
14
|
|
15
15
|
```typescript
|
16
16
|
async function Worker() {
|
17
|
-
const thread = await spawn()
|
17
|
+
const thread = await spawn();
|
18
18
|
|
19
19
|
return {
|
20
20
|
// The value returned after initialization completes
|
@@ -22,24 +22,27 @@ async function Worker() {
|
|
22
22
|
|
23
23
|
// Called when the resource is destroyed
|
24
24
|
destroy: () => thread.close(),
|
25
|
-
}
|
25
|
+
};
|
26
26
|
}
|
27
27
|
```
|
28
28
|
|
29
29
|
Now define a pool that creates and manages workers:
|
30
30
|
|
31
31
|
```typescript
|
32
|
-
async function WorkerPool(
|
33
|
-
|
34
|
-
|
32
|
+
async function WorkerPool(
|
33
|
+
{ create }: ResourceContext,
|
34
|
+
config: { poolSize: number },
|
35
|
+
) {
|
36
|
+
const promises = Array(config.poolSize).fill(Worker).map(create);
|
37
|
+
const threads = await Promise.all(promises);
|
35
38
|
|
36
39
|
return {
|
37
40
|
// ... External API goes here ...
|
38
41
|
value: {
|
39
42
|
doSomeWork() {},
|
40
43
|
doSomethingElse() {},
|
41
|
-
}
|
42
|
-
}
|
44
|
+
},
|
45
|
+
};
|
43
46
|
}
|
44
47
|
```
|
45
48
|
|
@@ -48,17 +51,17 @@ Finally, create the pool:
|
|
48
51
|
```typescript
|
49
52
|
const pool = await create(WorkerPool, {
|
50
53
|
poolSize: cpus().length,
|
51
|
-
})
|
54
|
+
});
|
52
55
|
|
53
56
|
// Provisioned and ready to go!
|
54
|
-
pool.doSomeWork()
|
55
|
-
pool.doSomethingElse()
|
57
|
+
pool.doSomeWork();
|
58
|
+
pool.doSomethingElse();
|
56
59
|
```
|
57
60
|
|
58
61
|
The magic of this framework is that resources never outlive their owners. If you tear down the pool, it will deallocate everything beneath it first:
|
59
62
|
|
60
63
|
```typescript
|
61
|
-
await destroy(pool)
|
64
|
+
await destroy(pool);
|
62
65
|
|
63
66
|
// [info] closing worker
|
64
67
|
// [info] closing worker
|
package/dist/wardens.mjs
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
var p = Object.defineProperty;
|
2
|
+
var x = (n, e, t) => e in n ? p(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
|
3
|
+
var a = (n, e, t) => (x(n, typeof e != "symbol" ? e + "" : e, t), t), f = (n, e, t) => {
|
4
|
+
if (!e.has(n))
|
5
|
+
throw TypeError("Cannot " + t);
|
6
|
+
};
|
7
|
+
var i = (n, e, t) => (f(n, e, "read from private field"), t ? t.call(n) : e.get(n)), y = (n, e, t) => {
|
8
|
+
if (e.has(n))
|
9
|
+
throw TypeError("Cannot add the same private member more than once");
|
10
|
+
e instanceof WeakSet ? e.add(n) : e.set(n, t);
|
11
|
+
}, l = (n, e, t, o) => (f(n, e, "write to private field"), o ? o.call(n, t) : e.set(n, t), t);
|
12
|
+
function g(n) {
|
13
|
+
const e = /* @__PURE__ */ new WeakMap();
|
14
|
+
return new Proxy(n, {
|
15
|
+
get(t, o) {
|
16
|
+
const r = Reflect.get(t, o, t);
|
17
|
+
if (typeof r == "function") {
|
18
|
+
if (e.has(r) === !1) {
|
19
|
+
const c = r.bind(t);
|
20
|
+
Object.defineProperties(
|
21
|
+
c,
|
22
|
+
Object.getOwnPropertyDescriptors(r)
|
23
|
+
), e.set(r, c);
|
24
|
+
}
|
25
|
+
return e.get(r);
|
26
|
+
}
|
27
|
+
return r;
|
28
|
+
},
|
29
|
+
set(t, o, r) {
|
30
|
+
return Reflect.set(t, o, r, t);
|
31
|
+
}
|
32
|
+
});
|
33
|
+
}
|
34
|
+
const u = /* @__PURE__ */ new WeakMap();
|
35
|
+
function m(n) {
|
36
|
+
return Proxy.revocable(n, {});
|
37
|
+
}
|
38
|
+
var s;
|
39
|
+
class v {
|
40
|
+
constructor(e) {
|
41
|
+
y(this, s, void 0);
|
42
|
+
/** Provision an owned resource and make sure it doesn't outlive us. */
|
43
|
+
a(this, "create", async (e, ...t) => {
|
44
|
+
const o = await P(e, ...t);
|
45
|
+
return i(this, s).add(o), o;
|
46
|
+
});
|
47
|
+
/**
|
48
|
+
* Tear down a resource. Happens automatically when resource owners are
|
49
|
+
* deallocated.
|
50
|
+
*/
|
51
|
+
a(this, "destroy", async (e) => {
|
52
|
+
if (!i(this, s).has(e))
|
53
|
+
throw new Error("You do not own this resource.");
|
54
|
+
try {
|
55
|
+
await w(e);
|
56
|
+
} finally {
|
57
|
+
i(this, s).delete(e);
|
58
|
+
}
|
59
|
+
});
|
60
|
+
l(this, s, e);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
s = new WeakMap();
|
64
|
+
async function P(n, ...e) {
|
65
|
+
const t = /* @__PURE__ */ new Set(), o = new v(t), r = await n(o, ...e), c = r.value, { proxy: d, revoke: h } = m(c);
|
66
|
+
return u.set(d, {
|
67
|
+
resource: r,
|
68
|
+
children: t,
|
69
|
+
revoke: h
|
70
|
+
}), d;
|
71
|
+
}
|
72
|
+
async function w(n) {
|
73
|
+
const e = u.get(n);
|
74
|
+
if (e) {
|
75
|
+
u.delete(n), e.revoke();
|
76
|
+
const t = Array.from(e.children).map(w), o = await Promise.allSettled(t);
|
77
|
+
e.resource.destroy && await e.resource.destroy(), o.forEach((r) => {
|
78
|
+
if (r.status === "rejected")
|
79
|
+
throw r.reason;
|
80
|
+
});
|
81
|
+
}
|
82
|
+
}
|
83
|
+
export {
|
84
|
+
g as bindContext,
|
85
|
+
P as create,
|
86
|
+
w as destroy
|
87
|
+
};
|
package/dist/wardens.umd.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
var P=Object.defineProperty;var g=(e,t,n)=>t in e?P(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var
|
1
|
+
var P=Object.defineProperty;var g=(e,t,n)=>t in e?P(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var l=(e,t,n)=>(g(e,typeof t!="symbol"?t+"":t,n),n),p=(e,t,n)=>{if(!t.has(e))throw TypeError("Cannot "+n)};var f=(e,t,n)=>(p(e,t,"read from private field"),n?n.call(e):t.get(e)),b=(e,t,n)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,n)},m=(e,t,n,d)=>(p(e,t,"write to private field"),d?d.call(e,n):t.set(e,n),n);(function(e,t){typeof exports=="object"&&typeof module<"u"?t(exports):typeof define=="function"&&define.amd?define(["exports"],t):(e=typeof globalThis<"u"?globalThis:e||self,t(e.wardens={}))})(this,function(e){var a;"use strict";function t(c){const o=new WeakMap;return new Proxy(c,{get(s,i){const r=Reflect.get(s,i,s);if(typeof r=="function"){if(o.has(r)===!1){const u=r.bind(s);Object.defineProperties(u,Object.getOwnPropertyDescriptors(r)),o.set(r,u)}return o.get(r)}return r},set(s,i,r){return Reflect.set(s,i,r,s)}})}const n=new WeakMap;function d(c){return Proxy.revocable(c,{})}class x{constructor(o){b(this,a,void 0);l(this,"create",async(o,...s)=>{const i=await h(o,...s);return f(this,a).add(i),i});l(this,"destroy",async o=>{if(!f(this,a).has(o))throw new Error("You do not own this resource.");try{await y(o)}finally{f(this,a).delete(o)}});m(this,a,o)}}a=new WeakMap;async function h(c,...o){const s=new Set,i=new x(s),r=await c(i,...o),u=r.value,{proxy:w,revoke:v}=d(u);return n.set(w,{resource:r,children:s,revoke:v}),w}async function y(c){const o=n.get(c);if(o){n.delete(c),o.revoke();const s=Array.from(o.children).map(y),i=await Promise.allSettled(s);o.resource.destroy&&await o.resource.destroy(),i.forEach(r=>{if(r.status==="rejected")throw r.reason})}}e.bindContext=t,e.create=h,e.destroy=y,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
{
|
2
2
|
"name": "wardens",
|
3
|
-
"version": "0.4.
|
3
|
+
"version": "0.4.1",
|
4
4
|
"description": "A framework for resource management",
|
5
5
|
"main": "./dist/wardens.umd.js",
|
6
6
|
"module": "./dist/wardens.es.js",
|
7
|
+
"types": "./src/index.ts",
|
7
8
|
"repository": "git@github.com:PsychoLlama/wardens.git",
|
8
9
|
"author": "Jesse Gibson <JesseTheGibson@gmail.com>",
|
9
10
|
"license": "MIT",
|
@@ -31,7 +32,7 @@
|
|
31
32
|
"exports": {
|
32
33
|
".": {
|
33
34
|
"require": "./dist/wardens.umd.js",
|
34
|
-
"import": "./dist/wardens.
|
35
|
+
"import": "./dist/wardens.mjs"
|
35
36
|
}
|
36
37
|
},
|
37
38
|
"husky": {
|
@@ -82,17 +83,16 @@
|
|
82
83
|
"preset": "ts-jest"
|
83
84
|
},
|
84
85
|
"devDependencies": {
|
85
|
-
"@types/jest": "
|
86
|
-
"@typescript-eslint/eslint-plugin": "5.
|
87
|
-
"@typescript-eslint/parser": "5.
|
88
|
-
"eslint": "8.
|
89
|
-
"husky": "8.0.
|
90
|
-
"jest": "
|
91
|
-
"lint-staged": "13.0
|
92
|
-
"prettier": "2.
|
93
|
-
"ts-jest": "
|
94
|
-
"typescript": "4.
|
95
|
-
"vite": "
|
96
|
-
"vite-dts": "1.0.4"
|
86
|
+
"@types/jest": "29.2.5",
|
87
|
+
"@typescript-eslint/eslint-plugin": "5.48.1",
|
88
|
+
"@typescript-eslint/parser": "5.48.1",
|
89
|
+
"eslint": "8.31.0",
|
90
|
+
"husky": "8.0.3",
|
91
|
+
"jest": "29.3.1",
|
92
|
+
"lint-staged": "13.1.0",
|
93
|
+
"prettier": "2.8.3",
|
94
|
+
"ts-jest": "29.0.5",
|
95
|
+
"typescript": "4.9.4",
|
96
|
+
"vite": "4.0.4"
|
97
97
|
}
|
98
98
|
}
|
package/src/bind-context.ts
CHANGED
@@ -15,7 +15,7 @@
|
|
15
15
|
*
|
16
16
|
*/
|
17
17
|
export default function bindContext<T extends object>(value: T) {
|
18
|
-
const methodBindings = new WeakMap<
|
18
|
+
const methodBindings = new WeakMap<object, AnyMethod>();
|
19
19
|
|
20
20
|
return new Proxy(value, {
|
21
21
|
get(target, property) {
|
@@ -48,5 +48,4 @@ export default function bindContext<T extends object>(value: T) {
|
|
48
48
|
});
|
49
49
|
}
|
50
50
|
|
51
|
-
|
52
|
-
type Fn = (...args: any) => any;
|
51
|
+
type AnyMethod = (...args: Array<unknown>) => unknown;
|
package/dist/wardens.es.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export * from "../src/index"
|
package/dist/wardens.es.js
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
var __defProp = Object.defineProperty;
|
2
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
3
|
-
var __publicField = (obj, key, value) => {
|
4
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
5
|
-
return value;
|
6
|
-
};
|
7
|
-
var __accessCheck = (obj, member, msg) => {
|
8
|
-
if (!member.has(obj))
|
9
|
-
throw TypeError("Cannot " + msg);
|
10
|
-
};
|
11
|
-
var __privateGet = (obj, member, getter) => {
|
12
|
-
__accessCheck(obj, member, "read from private field");
|
13
|
-
return getter ? getter.call(obj) : member.get(obj);
|
14
|
-
};
|
15
|
-
var __privateAdd = (obj, member, value) => {
|
16
|
-
if (member.has(obj))
|
17
|
-
throw TypeError("Cannot add the same private member more than once");
|
18
|
-
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
19
|
-
};
|
20
|
-
var __privateSet = (obj, member, value, setter) => {
|
21
|
-
__accessCheck(obj, member, "write to private field");
|
22
|
-
setter ? setter.call(obj, value) : member.set(obj, value);
|
23
|
-
return value;
|
24
|
-
};
|
25
|
-
var _resources;
|
26
|
-
function bindContext(value) {
|
27
|
-
const methodBindings = /* @__PURE__ */ new WeakMap();
|
28
|
-
return new Proxy(value, {
|
29
|
-
get(target, property) {
|
30
|
-
const value2 = Reflect.get(target, property, target);
|
31
|
-
if (typeof value2 === "function") {
|
32
|
-
if (methodBindings.has(value2) === false) {
|
33
|
-
const methodBinding = value2.bind(target);
|
34
|
-
Object.defineProperties(methodBinding, Object.getOwnPropertyDescriptors(value2));
|
35
|
-
methodBindings.set(value2, methodBinding);
|
36
|
-
}
|
37
|
-
return methodBindings.get(value2);
|
38
|
-
}
|
39
|
-
return value2;
|
40
|
-
},
|
41
|
-
set(target, property, newValue) {
|
42
|
-
return Reflect.set(target, property, newValue, target);
|
43
|
-
}
|
44
|
-
});
|
45
|
-
}
|
46
|
-
const resources = /* @__PURE__ */ new WeakMap();
|
47
|
-
function wrapWithProxy(value) {
|
48
|
-
return Proxy.revocable(value, {});
|
49
|
-
}
|
50
|
-
class ResourceContext {
|
51
|
-
constructor(ownedResources) {
|
52
|
-
__privateAdd(this, _resources, void 0);
|
53
|
-
__publicField(this, "create", async (factory, ...args) => {
|
54
|
-
const controls = await create(factory, ...args);
|
55
|
-
__privateGet(this, _resources).add(controls);
|
56
|
-
return controls;
|
57
|
-
});
|
58
|
-
__publicField(this, "destroy", async (resource) => {
|
59
|
-
if (!__privateGet(this, _resources).has(resource)) {
|
60
|
-
throw new Error("You do not own this resource.");
|
61
|
-
}
|
62
|
-
try {
|
63
|
-
await destroy(resource);
|
64
|
-
} finally {
|
65
|
-
__privateGet(this, _resources).delete(resource);
|
66
|
-
}
|
67
|
-
});
|
68
|
-
__privateSet(this, _resources, ownedResources);
|
69
|
-
}
|
70
|
-
}
|
71
|
-
_resources = new WeakMap();
|
72
|
-
async function create(provision, ...args) {
|
73
|
-
const children = /* @__PURE__ */ new Set();
|
74
|
-
const context = new ResourceContext(children);
|
75
|
-
const resource = await provision(context, ...args);
|
76
|
-
const controls = resource.value;
|
77
|
-
const { proxy, revoke } = wrapWithProxy(controls);
|
78
|
-
resources.set(proxy, {
|
79
|
-
resource,
|
80
|
-
children,
|
81
|
-
revoke
|
82
|
-
});
|
83
|
-
return proxy;
|
84
|
-
}
|
85
|
-
async function destroy(controls) {
|
86
|
-
const entry = resources.get(controls);
|
87
|
-
if (entry) {
|
88
|
-
resources.delete(controls);
|
89
|
-
entry.revoke();
|
90
|
-
const recursiveUnmounts = Array.from(entry.children).map(destroy);
|
91
|
-
const results = await Promise.allSettled(recursiveUnmounts);
|
92
|
-
if (entry.resource.destroy) {
|
93
|
-
await entry.resource.destroy();
|
94
|
-
}
|
95
|
-
results.forEach((result) => {
|
96
|
-
if (result.status === "rejected") {
|
97
|
-
throw result.reason;
|
98
|
-
}
|
99
|
-
});
|
100
|
-
}
|
101
|
-
}
|
102
|
-
export { bindContext, create, destroy };
|
package/dist/wardens.umd.d.ts
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
export * from "../src/index"
|