wardens 0.6.0-rc.3 → 0.6.0-rc.4-2024-07-28.92dafd2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/wardens.cjs +1 -1
- package/dist/wardens.js +37 -41
- package/package.json +17 -40
- package/src/__tests__/root-lifecycle.test.ts +1 -1
- package/src/__tests__/roots.test.ts +1 -1
- package/src/__tests__/utility-types.test-d.ts +25 -1
- package/src/index.ts +1 -1
- package/src/resource-lifecycle.ts +4 -1
- package/src/utility-types.ts +5 -0
- package/CHANGELOG.md +0 -103
package/dist/wardens.cjs
CHANGED
@@ -1 +1 @@
|
|
1
|
-
"use strict";var
|
1
|
+
"use strict";var B=Object.defineProperty;var j=e=>{throw TypeError(e)};var M=(e,t,r)=>t in e?B(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var f=(e,t,r)=>M(e,typeof t!="symbol"?t+"":t,r),k=(e,t,r)=>t.has(e)||j("Cannot "+r);var s=(e,t,r)=>(k(e,t,"read from private field"),r?r.call(e):t.get(e)),d=(e,t,r)=>t.has(e)?j("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,r),h=(e,t,r,o)=>(k(e,t,"write to private field"),o?o.call(e,r):t.set(e,r),r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function A(e){const t=new WeakMap;return new Proxy(e,{get(r,o){const n=Reflect.get(r,o,r);if(typeof n=="function"){if(t.has(n)===!1){const a=n.bind(r);Object.defineProperties(a,Object.getOwnPropertyDescriptors(n)),t.set(n,a)}return t.get(n)}return n},set(r,o,n){return Reflect.set(r,o,n,r)}})}const g=new WeakMap,E=new WeakSet,P=new WeakSet;function T(e){return Proxy.revocable(e,{})}var C,w;class x{constructor(t){d(this,C,Symbol("Context ID"));d(this,w);h(this,w,t)}static getId(t){return s(t,C)}static getDefaultValue(t){var r;return s(r=t,w).call(r)}}C=new WeakMap,w=new WeakMap;const V=e=>new x(e);var y,l,p,i;class H{constructor(t,r,o){d(this,y,new WeakSet);d(this,l);d(this,p);d(this,i);f(this,"create",async(t,...r)=>{if(s(this,p).enforced)throw new Error("Cannot create new resources after teardown.");const o=Object.create(s(this,i)),n=await D(o,t,...r);return s(this,l).add(n),n});f(this,"destroy",async t=>{if(s(this,y).has(t))throw new Error("Resource already destroyed.");if(!s(this,l).has(t))throw new Error("You do not own this resource.");s(this,l).delete(t),s(this,y).add(t),await m(t)});f(this,"setContext",(t,r)=>(s(this,i)[x.getId(t)]=r,r));f(this,"getContext",t=>{const r=x.getId(t);return r in s(this,i)?s(this,i)[r]:x.getDefaultValue(t)});h(this,i,t),h(this,l,r),h(this,p,o)}}y=new WeakMap,l=new WeakMap,p=new WeakMap,i=new WeakMap;const D=async(e,t,...r)=>{const o={enforced:!1},n=new Set,a=new H(e,n,o);let c;try{c=await t(a,...r)}catch(S){const R=Array.from(n).reverse(),v=(await Promise.allSettled(R.map(u=>a.destroy(u)))).filter(u=>u.status==="rejected");throw v.length?W(v.map(u=>u.reason),{cause:S}):S}const I=c.value,{proxy:b,revoke:O}=T(I);return E.add(b),g.set(b,{curfew:o,resource:c,children:n,revoke:O}),b},m=async e=>{if(!E.has(e))throw new Error("Cannot destroy object. It is not a resource.");const t=g.get(e);if(t){g.delete(e),t.revoke();let r={status:"fulfilled",value:void 0};if(t.resource.destroy)try{await t.resource.destroy()}catch(c){r={status:"rejected",reason:c}}t.curfew.enforced=!0;const o=Array.from(t.children).reverse().map(m),n=await Promise.allSettled(o),a=[r].concat(n).filter(c=>c.status==="rejected");if(a.length)throw W(a.map(c=>c.reason))}},W=(e,t)=>e.length===1?e[0]:new U(e,t);class U extends Error{constructor(t,r){super("Some resources could not be destroyed. See the `failures` property for details.",r),this.failures=t}}const Y=async(e,...t)=>{const o=await D(Object.create(null),e,...t);return P.add(o),o},q=async e=>{if(g.has(e)&&!P.has(e))throw new Error("Cannot destroy child resource. It is owned by another scope.");return m(e)};exports.bindContext=A;exports.create=Y;exports.createContext=V;exports.destroy=q;
|
package/dist/wardens.js
CHANGED
@@ -1,15 +1,11 @@
|
|
1
|
-
var
|
2
|
-
var
|
3
|
-
|
4
|
-
if (!t.has(e))
|
5
|
-
throw TypeError("Cannot " + r);
|
1
|
+
var B = Object.defineProperty;
|
2
|
+
var j = (e) => {
|
3
|
+
throw TypeError(e);
|
6
4
|
};
|
7
|
-
var
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
}, f = (e, t, r, o) => (j(e, t, "write to private field"), o ? o.call(e, r) : t.set(e, r), r);
|
12
|
-
function U(e) {
|
5
|
+
var A = (e, t, r) => t in e ? B(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
|
6
|
+
var h = (e, t, r) => A(e, typeof t != "symbol" ? t + "" : t, r), k = (e, t, r) => t.has(e) || j("Cannot " + r);
|
7
|
+
var n = (e, t, r) => (k(e, t, "read from private field"), r ? r.call(e) : t.get(e)), d = (e, t, r) => t.has(e) ? j("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(e) : t.set(e, r), f = (e, t, r, o) => (k(e, t, "write to private field"), o ? o.call(e, r) : t.set(e, r), r);
|
8
|
+
function Y(e) {
|
13
9
|
const t = /* @__PURE__ */ new WeakMap();
|
14
10
|
return new Proxy(e, {
|
15
11
|
get(r, o) {
|
@@ -31,15 +27,15 @@ function U(e) {
|
|
31
27
|
}
|
32
28
|
});
|
33
29
|
}
|
34
|
-
const g = /* @__PURE__ */ new WeakMap(),
|
35
|
-
function
|
30
|
+
const g = /* @__PURE__ */ new WeakMap(), E = /* @__PURE__ */ new WeakSet(), D = /* @__PURE__ */ new WeakSet();
|
31
|
+
function M(e) {
|
36
32
|
return Proxy.revocable(e, {});
|
37
33
|
}
|
38
34
|
var m, w;
|
39
35
|
class x {
|
40
36
|
constructor(t) {
|
41
37
|
d(this, m, Symbol("Context ID"));
|
42
|
-
d(this, w
|
38
|
+
d(this, w);
|
43
39
|
f(this, w, t);
|
44
40
|
}
|
45
41
|
static getId(t) {
|
@@ -51,19 +47,19 @@ class x {
|
|
51
47
|
}
|
52
48
|
}
|
53
49
|
m = new WeakMap(), w = new WeakMap();
|
54
|
-
const
|
50
|
+
const q = (e) => new x(e);
|
55
51
|
var y, l, p, i;
|
56
|
-
class
|
52
|
+
class V {
|
57
53
|
constructor(t, r, o) {
|
58
54
|
d(this, y, /* @__PURE__ */ new WeakSet());
|
59
|
-
d(this, l
|
60
|
-
d(this, p
|
61
|
-
d(this, i
|
55
|
+
d(this, l);
|
56
|
+
d(this, p);
|
57
|
+
d(this, i);
|
62
58
|
/** Provision an owned resource and make sure it doesn't outlive us. */
|
63
59
|
h(this, "create", async (t, ...r) => {
|
64
60
|
if (n(this, p).enforced)
|
65
61
|
throw new Error("Cannot create new resources after teardown.");
|
66
|
-
const o = Object.create(n(this, i)), s = await
|
62
|
+
const o = Object.create(n(this, i)), s = await P(o, t, ...r);
|
67
63
|
return n(this, l).add(s), s;
|
68
64
|
});
|
69
65
|
/**
|
@@ -88,31 +84,31 @@ class M {
|
|
88
84
|
}
|
89
85
|
}
|
90
86
|
y = new WeakMap(), l = new WeakMap(), p = new WeakMap(), i = new WeakMap();
|
91
|
-
const
|
92
|
-
const o = { enforced: !1 }, s = /* @__PURE__ */ new Set(), a = new
|
87
|
+
const P = async (e, t, ...r) => {
|
88
|
+
const o = { enforced: !1 }, s = /* @__PURE__ */ new Set(), a = new V(e, s, o);
|
93
89
|
let c;
|
94
90
|
try {
|
95
91
|
c = await t(a, ...r);
|
96
92
|
} catch (S) {
|
97
|
-
const
|
98
|
-
|
93
|
+
const O = Array.from(s).reverse(), v = (await Promise.allSettled(
|
94
|
+
O.map((u) => a.destroy(u))
|
99
95
|
)).filter(
|
100
96
|
(u) => u.status === "rejected"
|
101
97
|
);
|
102
|
-
throw v.length ?
|
98
|
+
throw v.length ? W(
|
103
99
|
v.map((u) => u.reason),
|
104
100
|
{ cause: S }
|
105
101
|
) : S;
|
106
102
|
}
|
107
|
-
const
|
108
|
-
return
|
103
|
+
const I = c.value, { proxy: C, revoke: R } = M(I);
|
104
|
+
return E.add(C), g.set(C, {
|
109
105
|
curfew: o,
|
110
106
|
resource: c,
|
111
107
|
children: s,
|
112
|
-
revoke:
|
108
|
+
revoke: R
|
113
109
|
}), C;
|
114
110
|
}, b = async (e) => {
|
115
|
-
if (!
|
111
|
+
if (!E.has(e))
|
116
112
|
throw new Error("Cannot destroy object. It is not a resource.");
|
117
113
|
const t = g.get(e);
|
118
114
|
if (t) {
|
@@ -132,10 +128,10 @@ const D = async (e, t, ...r) => {
|
|
132
128
|
(c) => c.status === "rejected"
|
133
129
|
);
|
134
130
|
if (a.length)
|
135
|
-
throw
|
131
|
+
throw W(a.map((c) => c.reason));
|
136
132
|
}
|
137
|
-
},
|
138
|
-
class
|
133
|
+
}, W = (e, t) => e.length === 1 ? e[0] : new H(e, t);
|
134
|
+
class H extends Error {
|
139
135
|
constructor(t, r) {
|
140
136
|
super(
|
141
137
|
"Some resources could not be destroyed. See the `failures` property for details.",
|
@@ -143,19 +139,19 @@ class V extends Error {
|
|
143
139
|
), this.failures = t;
|
144
140
|
}
|
145
141
|
}
|
146
|
-
const
|
147
|
-
const o = await
|
148
|
-
return
|
149
|
-
},
|
150
|
-
if (g.has(e) && !
|
142
|
+
const z = async (e, ...t) => {
|
143
|
+
const o = await P(/* @__PURE__ */ Object.create(null), e, ...t);
|
144
|
+
return D.add(o), o;
|
145
|
+
}, F = async (e) => {
|
146
|
+
if (g.has(e) && !D.has(e))
|
151
147
|
throw new Error(
|
152
148
|
"Cannot destroy child resource. It is owned by another scope."
|
153
149
|
);
|
154
150
|
return b(e);
|
155
151
|
};
|
156
152
|
export {
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
153
|
+
Y as bindContext,
|
154
|
+
z as create,
|
155
|
+
q as createContext,
|
156
|
+
F as destroy
|
161
157
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "wardens",
|
3
|
-
"version": "0.6.0-rc.
|
3
|
+
"version": "0.6.0-rc.4-2024-07-28.92dafd2",
|
4
4
|
"description": "A framework for resource management",
|
5
5
|
"type": "module",
|
6
6
|
"main": "./dist/wardens.cjs",
|
@@ -31,12 +31,13 @@
|
|
31
31
|
],
|
32
32
|
"scripts": {
|
33
33
|
"prepack": "tsc && vite build",
|
34
|
-
"test": "./
|
34
|
+
"test": "./scripts/run-tests",
|
35
35
|
"test:lint": "eslint src --color",
|
36
|
-
"test:unit": "vitest --color",
|
37
|
-
"test:types": "vitest typecheck --color",
|
36
|
+
"test:unit": "vitest --color --typecheck",
|
38
37
|
"test:fmt": "prettier --check src --color",
|
39
|
-
"
|
38
|
+
"print-pkg-version": "echo ${npm_package_version}",
|
39
|
+
"release:candidate": "./scripts/publish-rc",
|
40
|
+
"release:stable": "./scripts/publish-stable"
|
40
41
|
},
|
41
42
|
"husky": {
|
42
43
|
"hooks": {
|
@@ -53,41 +54,17 @@
|
|
53
54
|
"singleQuote": true,
|
54
55
|
"trailingComma": "all"
|
55
56
|
},
|
56
|
-
"eslintConfig": {
|
57
|
-
"parser": "@typescript-eslint/parser",
|
58
|
-
"parserOptions": {
|
59
|
-
"sourceType": "module"
|
60
|
-
},
|
61
|
-
"overrides": [
|
62
|
-
{
|
63
|
-
"files": [
|
64
|
-
"./**/__tests__/*.ts{x,}"
|
65
|
-
],
|
66
|
-
"rules": {
|
67
|
-
"@typescript-eslint/no-explicit-any": "off"
|
68
|
-
}
|
69
|
-
}
|
70
|
-
],
|
71
|
-
"extends": [
|
72
|
-
"eslint:recommended",
|
73
|
-
"plugin:@typescript-eslint/recommended"
|
74
|
-
],
|
75
|
-
"rules": {
|
76
|
-
"@typescript-eslint/explicit-module-boundary-types": "off",
|
77
|
-
"@typescript-eslint/no-non-null-assertion": "off",
|
78
|
-
"@typescript-eslint/no-unused-vars": "error",
|
79
|
-
"no-prototype-builtins": "off"
|
80
|
-
}
|
81
|
-
},
|
82
57
|
"devDependencies": {
|
83
|
-
"@
|
84
|
-
"@
|
85
|
-
"
|
86
|
-
"
|
87
|
-
"
|
88
|
-
"
|
89
|
-
"
|
90
|
-
"
|
91
|
-
"
|
58
|
+
"@eslint/js": "^9.7.0",
|
59
|
+
"@types/eslint__js": "^8.42.3",
|
60
|
+
"@types/node": "^22.0.0",
|
61
|
+
"eslint": "^9.7.0",
|
62
|
+
"husky": "^9.1.3",
|
63
|
+
"lint-staged": "^15.2.7",
|
64
|
+
"prettier": "^3.3.3",
|
65
|
+
"typescript": "^5.5.4",
|
66
|
+
"typescript-eslint": "^8.0.0-alpha.54",
|
67
|
+
"vite": "^5.3.5",
|
68
|
+
"vitest": "^2.0.0"
|
92
69
|
}
|
93
70
|
}
|
@@ -1,4 +1,10 @@
|
|
1
|
-
import {
|
1
|
+
import {
|
2
|
+
create,
|
3
|
+
ResourceScope,
|
4
|
+
ResourceHandle,
|
5
|
+
createContext,
|
6
|
+
ContextType,
|
7
|
+
} from '../';
|
2
8
|
|
3
9
|
describe('Utility types', () => {
|
4
10
|
describe('ResourceHandle', () => {
|
@@ -29,4 +35,22 @@ describe('Utility types', () => {
|
|
29
35
|
});
|
30
36
|
});
|
31
37
|
});
|
38
|
+
|
39
|
+
describe('ContextType', () => {
|
40
|
+
it('returns the type contained in context', async () => {
|
41
|
+
const Context = createContext(() => ({
|
42
|
+
hello: 'world',
|
43
|
+
}));
|
44
|
+
|
45
|
+
async function Test({ getContext }: ResourceScope) {
|
46
|
+
return { value: getContext(Context) };
|
47
|
+
}
|
48
|
+
|
49
|
+
const value = await create(Test);
|
50
|
+
|
51
|
+
expectTypeOf(value).toEqualTypeOf<ContextType<typeof Context>>({
|
52
|
+
hello: 'any string, really',
|
53
|
+
});
|
54
|
+
});
|
55
|
+
});
|
32
56
|
});
|
package/src/index.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
export { default as bindContext } from './bind-context';
|
2
2
|
export { createRoot as create, destroyRoot as destroy } from './root-lifecycle';
|
3
3
|
export { createContext } from './inherited-context';
|
4
|
-
export type { Resource, ResourceHandle } from './utility-types';
|
4
|
+
export type { Resource, ResourceHandle, ContextType } from './utility-types';
|
5
5
|
export type { default as ResourceScope } from './resource-scope';
|
@@ -119,7 +119,10 @@ const reduceToSingleError = (errors: Array<Error>, options?: ErrorOptions) => {
|
|
119
119
|
|
120
120
|
/** Happens when 2 or more child resources cannot be destroyed. */
|
121
121
|
class BulkDestroyError extends Error {
|
122
|
-
constructor(
|
122
|
+
constructor(
|
123
|
+
public failures: Array<unknown>,
|
124
|
+
options?: ErrorOptions,
|
125
|
+
) {
|
123
126
|
super(
|
124
127
|
'Some resources could not be destroyed. See the `failures` property for details.',
|
125
128
|
options,
|
package/src/utility-types.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2
|
+
import type { ContextHandle } from './inherited-context';
|
2
3
|
import type ResourceScope from './resource-scope';
|
3
4
|
|
4
5
|
/**
|
@@ -29,3 +30,7 @@ export interface Resource<Value extends object> {
|
|
29
30
|
export type ResourceHandle<
|
30
31
|
Factory extends ParametrizedResourceFactory<object, Array<any>>,
|
31
32
|
> = Awaited<ReturnType<Factory>>['value'];
|
33
|
+
|
34
|
+
/** The type returned when you call `getContext`. */
|
35
|
+
export type ContextType<Handle extends ContextHandle<unknown>> =
|
36
|
+
Handle extends ContextHandle<infer Value> ? Value : never;
|
package/CHANGELOG.md
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
# Changelog
|
2
|
-
|
3
|
-
All notable changes to this project will be documented in this file.
|
4
|
-
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
-
|
7
|
-
## [Unreleased]
|
8
|
-
|
9
|
-
### Added
|
10
|
-
|
11
|
-
- New context API carries state down the tree without plumbing through arguments.
|
12
|
-
|
13
|
-
### Changed
|
14
|
-
|
15
|
-
- Renamed public type `ResourceContext` to `ResourceScope`.
|
16
|
-
- `destroy(...)` is no longer allowed to destroy child resources, only roots.
|
17
|
-
- Added tree-shaking metadata. This is useful for bundle analysis tools.
|
18
|
-
|
19
|
-
## [0.5.1] - 2023-08-12
|
20
|
-
|
21
|
-
### Fixed
|
22
|
-
|
23
|
-
- Added support for parametrized resources in `ResourceHandle<T>`.
|
24
|
-
|
25
|
-
## [0.5.0] - 2023-08-12
|
26
|
-
|
27
|
-
### Changed
|
28
|
-
|
29
|
-
- Wardens is now published with ESM (`type=module`). It should be backwards compatible.
|
30
|
-
- Now `destroy(...)` throws if you pass an object that wasn't constructed with `create(...)`.
|
31
|
-
|
32
|
-
### Fixed
|
33
|
-
|
34
|
-
- If a resource fails while initializing, now all intermediate child resources are destroyed as well.
|
35
|
-
- If a resource fails while being destroyed, now its child resources are destroyed as well.
|
36
|
-
- Resources can no longer provision child resources after teardown. This closes a loophole where resources could escape destruction.
|
37
|
-
|
38
|
-
### Added
|
39
|
-
|
40
|
-
- New `ResourceHandle<T>` utility type represents the value returned when creating a resource.
|
41
|
-
|
42
|
-
## [0.4.1] - 2023-01-14
|
43
|
-
|
44
|
-
### Fixed
|
45
|
-
|
46
|
-
- Newer versions of TypeScript complained about signatures in `bindContext(...)`.
|
47
|
-
|
48
|
-
## [0.4.0] - 2022-06-19
|
49
|
-
|
50
|
-
### Added
|
51
|
-
|
52
|
-
- Support for provisioning resources through async functions instead of `Resource` subclasses. This offers better type safety around null conditions.
|
53
|
-
- A new `Resource` utility type is exported. The new functional API expects you to return this interface.
|
54
|
-
|
55
|
-
### Removed
|
56
|
-
|
57
|
-
- The `Resource` abstract class was removed. Use async functions instead.
|
58
|
-
- The `Controls<...>` utility type was removed. Import the type you need from the module instead.
|
59
|
-
|
60
|
-
## [0.3.0] - 2022-06-04
|
61
|
-
|
62
|
-
### Changed
|
63
|
-
|
64
|
-
- Prevent use of `allocate(...)`/`deallocate(...)` outside a resource subclass.
|
65
|
-
- Renamed `enter()` and `leave()` to `create()` and `destroy()`.
|
66
|
-
- Renamed `mount()` and `unmount()` to `create()` and `destroy()`.
|
67
|
-
|
68
|
-
### Removed
|
69
|
-
|
70
|
-
- Second type parameter to `Resource` is gone. Arguments to `enter(...)` are now inferred.
|
71
|
-
- No more default implementations for `enter(...)`/`leave(...)` on resources.
|
72
|
-
|
73
|
-
## [0.2.0] - 2022-05-24
|
74
|
-
|
75
|
-
### Fixed
|
76
|
-
|
77
|
-
- `mount(...)` and `allocate(...)` no longer require a config argument if the resource doesn't explicitly define one.
|
78
|
-
|
79
|
-
### Added
|
80
|
-
|
81
|
-
- `enter(...)` now supports variable arguments.
|
82
|
-
|
83
|
-
### Changed
|
84
|
-
|
85
|
-
- The second generic parameter of `Resource` was a config parameter, but now it's an argument tuple.
|
86
|
-
- The `ExternalControls` utility type was renamed to `Controls`.
|
87
|
-
|
88
|
-
## [0.1.0] - 2022-05-22
|
89
|
-
|
90
|
-
### Added
|
91
|
-
|
92
|
-
- Resource class for modeling asynchronously provisioned resources
|
93
|
-
- `mount`/`unmount` hooks to provision resources
|
94
|
-
- `allocate`/`deallocate` for creating hierarchies of resources
|
95
|
-
|
96
|
-
[Unreleased]: https://github.com/PsychoLlama/wardens/compare/v0.5.1...HEAD
|
97
|
-
[0.5.1]: https://github.com/PsychoLlama/wardens/compare/v0.5.0...v0.5.1
|
98
|
-
[0.5.0]: https://github.com/PsychoLlama/wardens/compare/v0.4.1...v0.5.0
|
99
|
-
[0.4.1]: https://github.com/PsychoLlama/wardens/compare/v0.4.0...v0.4.1
|
100
|
-
[0.4.0]: https://github.com/PsychoLlama/wardens/compare/v0.3.0...v0.4.0
|
101
|
-
[0.3.0]: https://github.com/PsychoLlama/wardens/compare/v0.2.0...v0.3.0
|
102
|
-
[0.2.0]: https://github.com/PsychoLlama/wardens/compare/v0.1.0...v0.2.0
|
103
|
-
[0.1.0]: https://github.com/PsychoLlama/wardens/releases/tag/v0.1.0
|