@occultist/occultist 0.0.5 → 0.0.6
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/accept.js +0 -1
- package/dist/actions/actionSets.d.ts +3 -3
- package/dist/actions/actions.d.ts +69 -48
- package/dist/actions/actions.js +39 -4
- package/dist/actions/context.d.ts +15 -11
- package/dist/actions/context.js +5 -0
- package/dist/actions/meta.d.ts +18 -12
- package/dist/actions/meta.js +114 -38
- package/dist/actions/spec.d.ts +3 -3
- package/dist/actions/types.d.ts +45 -16
- package/dist/actions/writer.d.ts +1 -1
- package/dist/actions/writer.test.js +2 -2
- package/dist/cache/cache.d.ts +3 -3
- package/dist/cache/cache.js +111 -42
- package/dist/cache/etag.test.js +1 -1
- package/dist/cache/file.d.ts +32 -1
- package/dist/cache/file.js +89 -10
- package/dist/cache/memory.d.ts +12 -2
- package/dist/cache/memory.js +63 -1
- package/dist/cache/types.d.ts +51 -22
- package/dist/errors.d.ts +1 -1
- package/dist/jsonld.d.ts +1 -1
- package/dist/makeTypeDefs.d.ts +2 -2
- package/dist/mod.d.ts +17 -15
- package/dist/mod.js +17 -15
- package/dist/processAction.d.ts +2 -2
- package/dist/processAction.js +1 -1
- package/dist/registry.d.ts +74 -8
- package/dist/registry.js +70 -8
- package/dist/registry.test.js +1 -1
- package/dist/scopes.d.ts +8 -8
- package/dist/scopes.js +8 -5
- package/dist/utils/contextBuilder.d.ts +1 -1
- package/dist/utils/getActionContext.d.ts +2 -2
- package/dist/utils/getPropertyValueSpecifications.d.ts +1 -1
- package/dist/utils/getRequestBodyValues.d.ts +3 -3
- package/dist/utils/getRequestIRIValues.d.ts +2 -2
- package/dist/utils/isPopulatedObject.js +1 -1
- package/dist/utils/makeAppendProblemDetails.d.ts +1 -1
- package/dist/utils/makeURLPattern.js +1 -0
- package/dist/utils/parseSearchParams.d.ts +2 -2
- package/dist/validators.d.ts +2 -2
- package/dist/validators.js +2 -2
- package/lib/accept.test.ts +1 -1
- package/lib/accept.ts +0 -2
- package/lib/actions/actionSets.ts +4 -4
- package/lib/actions/actions.ts +159 -99
- package/lib/actions/context.ts +22 -10
- package/lib/actions/meta.ts +140 -55
- package/lib/actions/path.test.ts +1 -1
- package/lib/actions/path.ts +1 -1
- package/lib/actions/spec.ts +3 -3
- package/lib/actions/types.ts +60 -15
- package/lib/actions/writer.test.ts +2 -2
- package/lib/actions/writer.ts +1 -1
- package/lib/cache/cache.ts +138 -52
- package/lib/cache/etag.test.ts +1 -1
- package/lib/cache/file.ts +109 -13
- package/lib/cache/memory.ts +85 -3
- package/lib/cache/types.ts +70 -23
- package/lib/errors.ts +1 -1
- package/lib/jsonld.ts +1 -1
- package/lib/makeTypeDefs.ts +5 -5
- package/lib/mod.ts +17 -15
- package/lib/processAction.ts +14 -14
- package/lib/registry.test.ts +1 -1
- package/lib/registry.ts +96 -19
- package/lib/request.ts +1 -1
- package/lib/scopes.test.ts +2 -2
- package/lib/scopes.ts +14 -11
- package/lib/utils/contextBuilder.ts +3 -3
- package/lib/utils/getActionContext.ts +4 -4
- package/lib/utils/getInternalName.ts +1 -1
- package/lib/utils/getPropertyValueSpecifications.ts +4 -4
- package/lib/utils/getRequestBodyValues.ts +5 -5
- package/lib/utils/getRequestIRIValues.ts +4 -4
- package/lib/utils/isPopulatedObject.ts +1 -1
- package/lib/utils/makeAppendProblemDetails.ts +1 -1
- package/lib/utils/makeURLPattern.ts +1 -0
- package/lib/utils/parseSearchParams.ts +2 -2
- package/lib/validators.ts +5 -5
- package/package.json +4 -2
package/lib/actions/context.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {HandlerDefinition} from "../mod.
|
|
2
|
-
import type {Registry} from "../registry.
|
|
3
|
-
import type {ActionPayload, ActionSpec, ContextState, ParsedIRIValues} from "./spec.
|
|
4
|
-
import type {ImplementedAction} from "./types.
|
|
5
|
-
import type {ResponseBody} from "./writer.
|
|
1
|
+
import type {HandlerDefinition} from "../mod.ts";
|
|
2
|
+
import type {Registry} from "../registry.ts";
|
|
3
|
+
import type {ActionPayload, ActionSpec, ContextState, ParsedIRIValues} from "./spec.ts";
|
|
4
|
+
import type {AuthState, ImplementedAction} from "./types.ts";
|
|
5
|
+
import type {ResponseBody} from "./writer.ts";
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class EditableContext {
|
|
@@ -12,22 +12,26 @@ class EditableContext {
|
|
|
12
12
|
body?: ResponseBody;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
export type CacheContextArgs
|
|
15
|
+
export type CacheContextArgs<
|
|
16
|
+
Auth extends AuthState = AuthState,
|
|
17
|
+
> = {
|
|
16
18
|
req: Request;
|
|
17
19
|
url: string;
|
|
18
20
|
contentType: string;
|
|
19
21
|
public: boolean;
|
|
20
22
|
authKey?: string;
|
|
23
|
+
auth: Auth;
|
|
21
24
|
handler: HandlerDefinition;
|
|
22
25
|
params: ParsedIRIValues;
|
|
23
26
|
query: ParsedIRIValues;
|
|
24
27
|
};
|
|
25
28
|
|
|
26
|
-
|
|
27
29
|
/**
|
|
28
30
|
* Request context object.
|
|
29
31
|
*/
|
|
30
|
-
export class CacheContext
|
|
32
|
+
export class CacheContext<
|
|
33
|
+
Auth extends AuthState = AuthState,
|
|
34
|
+
> {
|
|
31
35
|
#editable = new EditableContext();
|
|
32
36
|
req: Request;
|
|
33
37
|
method: string;
|
|
@@ -35,18 +39,20 @@ export class CacheContext {
|
|
|
35
39
|
contentType: string;
|
|
36
40
|
public: boolean = false
|
|
37
41
|
authKey?: string;
|
|
42
|
+
auth: Auth;
|
|
38
43
|
action: ImplementedAction;
|
|
39
44
|
registry: Registry;
|
|
40
45
|
params: ParsedIRIValues;
|
|
41
46
|
query: ParsedIRIValues;
|
|
42
47
|
headers: Headers = new Headers();
|
|
43
48
|
|
|
44
|
-
constructor(args: CacheContextArgs) {
|
|
49
|
+
constructor(args: CacheContextArgs<Auth>) {
|
|
45
50
|
this.req = args.req;
|
|
46
51
|
this.url = args.url;
|
|
47
52
|
this.contentType = args.contentType;
|
|
48
53
|
this.public = args.public;
|
|
49
54
|
this.authKey = args.authKey;
|
|
55
|
+
this.auth = args.auth;
|
|
50
56
|
this.action = args.handler.action;
|
|
51
57
|
this.method = args.handler.action.method;
|
|
52
58
|
this.registry = args.handler.action.registry;
|
|
@@ -96,6 +102,7 @@ export class CacheContext {
|
|
|
96
102
|
|
|
97
103
|
export type ContextArgs<
|
|
98
104
|
State extends ContextState = ContextState,
|
|
105
|
+
Auth extends AuthState = AuthState,
|
|
99
106
|
Spec extends ActionSpec = ActionSpec,
|
|
100
107
|
> = {
|
|
101
108
|
req: Request;
|
|
@@ -103,6 +110,7 @@ export type ContextArgs<
|
|
|
103
110
|
contentType: string;
|
|
104
111
|
public: boolean;
|
|
105
112
|
authKey?: string;
|
|
113
|
+
auth: Auth;
|
|
106
114
|
handler: HandlerDefinition<State, Spec>;
|
|
107
115
|
params: ParsedIRIValues;
|
|
108
116
|
query: ParsedIRIValues;
|
|
@@ -114,6 +122,7 @@ export type ContextArgs<
|
|
|
114
122
|
*/
|
|
115
123
|
export class Context<
|
|
116
124
|
State extends ContextState = ContextState,
|
|
125
|
+
Auth extends AuthState = AuthState,
|
|
117
126
|
Spec extends ActionSpec = ActionSpec,
|
|
118
127
|
> {
|
|
119
128
|
#editable = new EditableContext();
|
|
@@ -123,6 +132,7 @@ export class Context<
|
|
|
123
132
|
contentType: string;
|
|
124
133
|
public: boolean = false
|
|
125
134
|
authKey?: string;
|
|
135
|
+
auth: Auth;
|
|
126
136
|
state: State = {} as State;
|
|
127
137
|
action: ImplementedAction<State, Spec>;
|
|
128
138
|
registry: Registry;
|
|
@@ -131,12 +141,13 @@ export class Context<
|
|
|
131
141
|
payload: ActionPayload<Spec>;
|
|
132
142
|
headers: Headers = new Headers();
|
|
133
143
|
|
|
134
|
-
constructor(args: ContextArgs<State, Spec>) {
|
|
144
|
+
constructor(args: ContextArgs<State, Auth, Spec>) {
|
|
135
145
|
this.req = args.req;
|
|
136
146
|
this.url = args.url;
|
|
137
147
|
this.contentType = args.contentType;
|
|
138
148
|
this.public = args.public;
|
|
139
149
|
this.authKey = args.authKey;
|
|
150
|
+
this.auth = args.auth;
|
|
140
151
|
this.action = args.handler.action;
|
|
141
152
|
this.method = args.handler.action.method;
|
|
142
153
|
this.registry = args.handler.action.registry;
|
|
@@ -145,6 +156,7 @@ export class Context<
|
|
|
145
156
|
this.payload = args.payload;
|
|
146
157
|
|
|
147
158
|
Object.freeze(this);
|
|
159
|
+
Object.freeze(this.auth);
|
|
148
160
|
}
|
|
149
161
|
|
|
150
162
|
get status(): undefined | number {
|
package/lib/actions/meta.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import type {
|
|
6
|
-
import type
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
1
|
+
import {Accept} from '../accept.ts';
|
|
2
|
+
import {CacheMiddleware} from '../cache/cache.ts';
|
|
3
|
+
import type {CacheEntryDescriptor, CacheInstanceArgs, CacheSemantics} from '../cache/types.ts';
|
|
4
|
+
import {ProblemDetailsError} from '../errors.ts';
|
|
5
|
+
import type {JSONValue} from '../jsonld.ts';
|
|
6
|
+
import {processAction, type ProcessActionResult} from '../processAction.ts';
|
|
7
|
+
import type {Registry} from '../registry.ts';
|
|
8
|
+
import {WrappedRequest} from '../request.ts';
|
|
9
|
+
import type {Scope} from "../scopes.ts";
|
|
10
|
+
import {joinPaths} from '../utils/joinPaths.ts';
|
|
11
|
+
import {HandlerDefinition} from './actions.ts';
|
|
12
|
+
import {ActionSet} from './actionSets.ts';
|
|
13
|
+
import {CacheContext, Context} from './context.ts';
|
|
14
|
+
import {Path} from "./path.ts";
|
|
15
|
+
import type {ActionSpec, ContextState, FileValue, NextFn, TransformerFn} from './spec.ts';
|
|
16
|
+
import type {AuthMiddleware, AuthState, CacheHitHeader, HintArgs, ImplementedAction} from './types.ts';
|
|
17
|
+
import {ResponseWriter, type HTTPWriter, type ResponseTypes} from "./writer.ts";
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
export const BeforeDefinition = 0;
|
|
@@ -20,6 +24,7 @@ const cacheMiddleware = new CacheMiddleware();
|
|
|
20
24
|
|
|
21
25
|
export class ActionMeta<
|
|
22
26
|
State extends ContextState = ContextState,
|
|
27
|
+
Auth extends AuthState = AuthState,
|
|
23
28
|
Spec extends ActionSpec = ActionSpec,
|
|
24
29
|
> {
|
|
25
30
|
rootIRI: string;
|
|
@@ -38,6 +43,7 @@ export class ActionMeta<
|
|
|
38
43
|
acceptCache = new Set<string>();
|
|
39
44
|
compressBeforeCache: boolean = false;
|
|
40
45
|
cacheOccurance: 0 | 1 = BeforeDefinition;
|
|
46
|
+
auth?: AuthMiddleware<Auth>;
|
|
41
47
|
cache: CacheInstanceArgs[] = [];
|
|
42
48
|
serverTiming: boolean = false;
|
|
43
49
|
|
|
@@ -67,18 +73,44 @@ export class ActionMeta<
|
|
|
67
73
|
this.#setAcceptCache();
|
|
68
74
|
}
|
|
69
75
|
|
|
76
|
+
async perform(req: Request): Promise<Response> {
|
|
77
|
+
const actionSet = new ActionSet(this.rootIRI, this.method, this.path.normalized, [this]);
|
|
78
|
+
const wrapped = new WrappedRequest(this.rootIRI, req);
|
|
79
|
+
const writer = new ResponseWriter();
|
|
80
|
+
const accept = Accept.from(req);
|
|
81
|
+
const url = new URL(wrapped.url);
|
|
82
|
+
const result = actionSet.matches(wrapped.method, url.pathname, accept);
|
|
83
|
+
|
|
84
|
+
if (result.type === 'match') {
|
|
85
|
+
const handler = this.action.handlerFor(result.contentType);
|
|
86
|
+
|
|
87
|
+
return this.handleRequest({
|
|
88
|
+
startTime: performance.now(),
|
|
89
|
+
contentType: result.contentType,
|
|
90
|
+
url: url.toString(),
|
|
91
|
+
req: wrapped,
|
|
92
|
+
writer,
|
|
93
|
+
spec: this.action.spec as Spec,
|
|
94
|
+
handler,
|
|
95
|
+
}) as Promise<Response>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return new Response(null, { status: 404 });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
*
|
|
103
|
+
*/
|
|
70
104
|
async handleRequest({
|
|
71
|
-
startTime,
|
|
72
105
|
contentType,
|
|
73
|
-
language: _language,
|
|
74
|
-
encoding: _encoding,
|
|
75
106
|
url,
|
|
76
107
|
req,
|
|
77
108
|
writer,
|
|
78
109
|
spec,
|
|
79
110
|
handler,
|
|
111
|
+
cacheHitHeader,
|
|
112
|
+
startTime,
|
|
80
113
|
}: {
|
|
81
|
-
startTime: number;
|
|
82
114
|
contentType?: string;
|
|
83
115
|
language?: string;
|
|
84
116
|
encoding?: string;
|
|
@@ -87,22 +119,28 @@ export class ActionMeta<
|
|
|
87
119
|
writer: HTTPWriter;
|
|
88
120
|
spec?: Spec;
|
|
89
121
|
handler?: HandlerDefinition<State, Spec>,
|
|
122
|
+
cacheHitHeader?: CacheHitHeader;
|
|
123
|
+
startTime?: number;
|
|
90
124
|
}): Promise<ResponseTypes> {
|
|
91
125
|
const state: State = {} as State;
|
|
92
126
|
const headers = new Headers();
|
|
93
|
-
|
|
94
|
-
let
|
|
127
|
+
|
|
128
|
+
let authKey: string | undefined;
|
|
129
|
+
let auth: Auth = {} as Auth;
|
|
130
|
+
let ctx: CacheContext<Auth> | Context<State, Auth, Spec>;
|
|
131
|
+
let cacheCtx: CacheContext<Auth>;
|
|
95
132
|
let prevTime = startTime;
|
|
133
|
+
let performServerTiming = this.serverTiming && startTime != null;
|
|
96
134
|
|
|
97
135
|
const serverTiming = (name: string) => {
|
|
98
136
|
const nextTime = performance.now();
|
|
99
137
|
const duration = nextTime - prevTime;
|
|
100
138
|
|
|
101
|
-
headers.append('Server-Timing', `${name};dur=${duration.
|
|
139
|
+
headers.append('Server-Timing', `${name};dur=${duration.toFixed(2)}`);
|
|
102
140
|
prevTime = nextTime;
|
|
103
141
|
}
|
|
104
142
|
|
|
105
|
-
if (
|
|
143
|
+
if (performServerTiming) serverTiming('enter');
|
|
106
144
|
|
|
107
145
|
// add auth check
|
|
108
146
|
if (this.hints.length !== 0) {
|
|
@@ -113,72 +151,86 @@ export class ActionMeta<
|
|
|
113
151
|
|
|
114
152
|
let next: NextFn = async () => {
|
|
115
153
|
if (typeof handler.handler === 'function') {
|
|
116
|
-
await handler.handler(ctx as Context<State, Spec>);
|
|
154
|
+
await handler.handler(ctx as Context<State, Auth, Spec>);
|
|
117
155
|
} else {
|
|
118
156
|
ctx.status = 200;
|
|
119
157
|
ctx.body = handler.handler;
|
|
120
158
|
}
|
|
121
159
|
|
|
122
|
-
if (
|
|
160
|
+
if (performServerTiming) serverTiming('handle');
|
|
123
161
|
};
|
|
124
162
|
|
|
125
163
|
{
|
|
126
164
|
const upstream: NextFn = next;
|
|
127
165
|
next = async () => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
166
|
+
let processed: ProcessActionResult<Spec>;
|
|
167
|
+
|
|
168
|
+
if (spec != null) {
|
|
169
|
+
processed = await processAction<State, Spec>({
|
|
170
|
+
iri: url,
|
|
171
|
+
req,
|
|
172
|
+
spec: spec ?? {} as Spec,
|
|
173
|
+
state,
|
|
174
|
+
action: this.action,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
135
177
|
|
|
136
|
-
ctx = new Context<State, Spec>({
|
|
178
|
+
ctx = new Context<State, Auth, Spec>({
|
|
137
179
|
req,
|
|
138
180
|
url,
|
|
139
181
|
contentType,
|
|
140
|
-
public: this.public,
|
|
182
|
+
public: this.public && authKey == null,
|
|
183
|
+
auth,
|
|
184
|
+
authKey,
|
|
141
185
|
handler,
|
|
142
|
-
params:
|
|
143
|
-
query:
|
|
144
|
-
payload:
|
|
186
|
+
params: processed.params ?? {},
|
|
187
|
+
query: processed.query ?? {},
|
|
188
|
+
payload: processed.payload ?? {} as ProcessActionResult<Spec>['payload'],
|
|
145
189
|
});
|
|
146
190
|
|
|
147
191
|
if (contentType != null) {
|
|
148
192
|
ctx.headers.set('Content-Type', contentType)
|
|
149
193
|
}
|
|
150
194
|
|
|
151
|
-
if (
|
|
195
|
+
if (performServerTiming) serverTiming('payload');
|
|
152
196
|
|
|
153
197
|
await upstream();
|
|
154
198
|
}
|
|
155
199
|
}
|
|
156
200
|
|
|
157
201
|
if (this.cache.length > 0) {
|
|
158
|
-
cacheCtx = new CacheContext({
|
|
159
|
-
req,
|
|
160
|
-
url,
|
|
161
|
-
contentType,
|
|
162
|
-
public: this.public,
|
|
163
|
-
handler,
|
|
164
|
-
params: {},
|
|
165
|
-
query: {},
|
|
166
|
-
});
|
|
167
|
-
const descriptors: CacheEntryDescriptor[] = this.cache.map(args => {
|
|
168
|
-
return {
|
|
169
|
-
contentType,
|
|
170
|
-
action: this.action as ImplementedAction,
|
|
171
|
-
request: req,
|
|
172
|
-
args,
|
|
173
|
-
};
|
|
174
|
-
});
|
|
175
|
-
|
|
176
202
|
const upstream = next;
|
|
177
203
|
next = async () => {
|
|
204
|
+
cacheCtx = new CacheContext({
|
|
205
|
+
req,
|
|
206
|
+
url,
|
|
207
|
+
contentType,
|
|
208
|
+
public: this.public && authKey == null,
|
|
209
|
+
auth,
|
|
210
|
+
authKey,
|
|
211
|
+
handler,
|
|
212
|
+
params: {},
|
|
213
|
+
query: {},
|
|
214
|
+
});
|
|
215
|
+
const descriptors: CacheEntryDescriptor[] = this.cache.map(args => {
|
|
216
|
+
return {
|
|
217
|
+
contentType,
|
|
218
|
+
semantics: args.semantics ?? req.method.toLowerCase() as CacheSemantics,
|
|
219
|
+
action: this.action as ImplementedAction,
|
|
220
|
+
request: req,
|
|
221
|
+
args,
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
|
|
178
225
|
await cacheMiddleware.use(
|
|
179
226
|
descriptors,
|
|
180
227
|
cacheCtx,
|
|
181
228
|
async () => {
|
|
229
|
+
// write any cache headers to the response headers.
|
|
230
|
+
// this should be reviewed as it may be unsafe to
|
|
231
|
+
// allow a handler to override these headers.
|
|
232
|
+
writer.mergeHeaders(cacheCtx.headers);
|
|
233
|
+
|
|
182
234
|
// cache was not hit if in this function
|
|
183
235
|
await upstream();
|
|
184
236
|
|
|
@@ -202,11 +254,44 @@ export class ActionMeta<
|
|
|
202
254
|
}
|
|
203
255
|
}
|
|
204
256
|
|
|
257
|
+
if (this.auth != null) {
|
|
258
|
+
const upstream = next;
|
|
259
|
+
next = async () => {
|
|
260
|
+
const res = await this.auth(req);
|
|
261
|
+
|
|
262
|
+
if (Array.isArray(res) &&
|
|
263
|
+
typeof res[0] === 'string' &&
|
|
264
|
+
res.length > 0) {
|
|
265
|
+
authKey = res[0];
|
|
266
|
+
auth = res[1];
|
|
267
|
+
|
|
268
|
+
await upstream();
|
|
269
|
+
} else if (this.public) {
|
|
270
|
+
await upstream();
|
|
271
|
+
} else {
|
|
272
|
+
|
|
273
|
+
// Failed authentication on a private endpoint.
|
|
274
|
+
throw new ProblemDetailsError(404, {
|
|
275
|
+
title: 'Not found',
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
|
|
205
282
|
try {
|
|
206
283
|
await next();
|
|
207
284
|
|
|
208
285
|
if (cacheCtx?.hit) {
|
|
209
|
-
if (
|
|
286
|
+
if (performServerTiming) serverTiming('hit');
|
|
287
|
+
|
|
288
|
+
if (Array.isArray(cacheHitHeader)) {
|
|
289
|
+
cacheCtx.headers.set(cacheHitHeader[0], cacheHitHeader[1]);
|
|
290
|
+
} else if (typeof cacheHitHeader === 'string') {
|
|
291
|
+
cacheCtx.headers.set(cacheHitHeader, 'HIT');
|
|
292
|
+
} else if (cacheHitHeader) {
|
|
293
|
+
cacheCtx.headers.set('X-Cache', 'HIT');
|
|
294
|
+
}
|
|
210
295
|
|
|
211
296
|
// set the ctx so the writer has access to the cached values.
|
|
212
297
|
ctx = cacheCtx;
|
package/lib/actions/path.test.ts
CHANGED
package/lib/actions/path.ts
CHANGED
package/lib/actions/spec.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { JSONPrimitive, JSONValue, OrArray, RecursiveDigit, RecursiveIncrement, TypeDef } from "../jsonld.
|
|
2
|
-
import {Action} from "./actions.
|
|
3
|
-
import type { Context } from './context.
|
|
1
|
+
import type { JSONPrimitive, JSONValue, OrArray, RecursiveDigit, RecursiveIncrement, TypeDef } from "../jsonld.ts";
|
|
2
|
+
import {Action} from "./actions.ts";
|
|
3
|
+
import type { Context } from './context.ts';
|
|
4
4
|
|
|
5
5
|
export type EmptyState = Record<string, unknown>;
|
|
6
6
|
export type EmptySpec = Map<PropertyKey, never>;
|
package/lib/actions/types.ts
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
|
-
import type { HTTPWriter } from "./writer.
|
|
2
|
-
import type { Registry } from '../registry.
|
|
3
|
-
import type { Scope } from "../scopes.
|
|
4
|
-
import type { ContextState, ActionSpec } from "./spec.
|
|
5
|
-
import type { Context } from "./context.
|
|
1
|
+
import type { HTTPWriter } from "./writer.ts";
|
|
2
|
+
import type { Registry } from '../registry.ts';
|
|
3
|
+
import type { Scope } from "../scopes.ts";
|
|
4
|
+
import type { ContextState, ActionSpec } from "./spec.ts";
|
|
5
|
+
import type { Context } from "./context.ts";
|
|
6
6
|
import type { ServerResponse } from "node:http";
|
|
7
|
-
import type { JSONObject, TypeDef } from "../jsonld.
|
|
8
|
-
import type {HandlerDefinition} from "../mod.
|
|
7
|
+
import type { JSONObject, TypeDef } from "../jsonld.ts";
|
|
8
|
+
import type {HandlerDefinition} from "../mod.ts";
|
|
9
|
+
|
|
10
|
+
export type CacheHitHeader = boolean | string | [header: string, value: string];
|
|
11
|
+
|
|
12
|
+
export type AuthState = Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Middleware that identifies the authenticating agent from the request
|
|
16
|
+
* and confirms they have access to the resource.
|
|
17
|
+
*
|
|
18
|
+
* When successfully authenticated the middleware should return with
|
|
19
|
+
* an array of two values. The first being a key unique to the user, or
|
|
20
|
+
* group, which can access this resource. This key is used for varying
|
|
21
|
+
* private cache so should alway vary on the user if personalized information
|
|
22
|
+
* would be returned in the response.
|
|
23
|
+
*
|
|
24
|
+
* The second response item is optional and should be an object holding identifying
|
|
25
|
+
* information such as permissions or details of the user or group that might be used
|
|
26
|
+
* when forming the response.
|
|
27
|
+
*
|
|
28
|
+
* @param req The request.
|
|
29
|
+
*/
|
|
30
|
+
export type AuthMiddleware<
|
|
31
|
+
Auth extends AuthState = AuthState,
|
|
32
|
+
> = (req: Request) =>
|
|
33
|
+
| void
|
|
34
|
+
| Promise<void>
|
|
35
|
+
| [authKey: string, auth?: Auth]
|
|
36
|
+
| Promise<[authKey: string, auth?: Auth]>
|
|
37
|
+
;
|
|
9
38
|
|
|
10
39
|
export type HintLink = {
|
|
11
40
|
href: string;
|
|
@@ -57,8 +86,9 @@ export type HandlerValue = Exclude<BodyInit, ReadableStream>;
|
|
|
57
86
|
*/
|
|
58
87
|
export type HandlerFn<
|
|
59
88
|
State extends ContextState = ContextState,
|
|
89
|
+
Auth extends AuthState = AuthState,
|
|
60
90
|
Spec extends ActionSpec = ActionSpec,
|
|
61
|
-
> = (ctx: Context<State, Spec>) => void | Promise<void>;
|
|
91
|
+
> = (ctx: Context<State, Auth, Spec>) => void | Promise<void>;
|
|
62
92
|
|
|
63
93
|
/**
|
|
64
94
|
* A handler object argument.
|
|
@@ -68,10 +98,11 @@ export type HandlerFn<
|
|
|
68
98
|
*/
|
|
69
99
|
export interface HandlerObj<
|
|
70
100
|
State extends ContextState = ContextState,
|
|
101
|
+
Auth extends AuthState = AuthState,
|
|
71
102
|
Spec extends ActionSpec = ActionSpec,
|
|
72
103
|
> {
|
|
73
104
|
contentType: string | string[];
|
|
74
|
-
handler: HandlerFn<State, Spec> | HandlerValue;
|
|
105
|
+
handler: HandlerFn<State, Auth, Spec> | HandlerValue;
|
|
75
106
|
meta?: HandlerMeta;
|
|
76
107
|
hints?: HintArgs;
|
|
77
108
|
};
|
|
@@ -81,25 +112,28 @@ export interface HandlerObj<
|
|
|
81
112
|
*/
|
|
82
113
|
export type HandlerArgs<
|
|
83
114
|
State extends ContextState = ContextState,
|
|
115
|
+
Auth extends AuthState = AuthState,
|
|
84
116
|
Spec extends ActionSpec = ActionSpec,
|
|
85
117
|
> =
|
|
86
118
|
| HandlerValue
|
|
87
|
-
| HandlerFn<State, Spec>
|
|
88
|
-
| HandlerObj<State, Spec>
|
|
119
|
+
| HandlerFn<State, Auth, Spec>
|
|
120
|
+
| HandlerObj<State, Auth, Spec>
|
|
89
121
|
;
|
|
90
122
|
|
|
91
123
|
export type HandleRequestArgs = {
|
|
92
|
-
startTime: number;
|
|
93
124
|
contentType?: string;
|
|
94
125
|
language?: string;
|
|
95
126
|
encoding?: string;
|
|
96
127
|
url: string;
|
|
97
128
|
req: Request;
|
|
98
129
|
writer: HTTPWriter;
|
|
130
|
+
startTime?: number;
|
|
131
|
+
cacheHitHeader?: CacheHitHeader;
|
|
99
132
|
};
|
|
100
133
|
|
|
101
134
|
export interface ImplementedAction<
|
|
102
135
|
State extends ContextState = ContextState,
|
|
136
|
+
Auth extends AuthState = AuthState,
|
|
103
137
|
Spec extends ActionSpec = ActionSpec,
|
|
104
138
|
> {
|
|
105
139
|
readonly public: boolean;
|
|
@@ -113,16 +147,27 @@ export interface ImplementedAction<
|
|
|
113
147
|
readonly spec: Spec;
|
|
114
148
|
readonly registry: Registry;
|
|
115
149
|
readonly scope?: Scope;
|
|
116
|
-
readonly handlers: HandlerDefinition<State, Spec>[];
|
|
150
|
+
readonly handlers: HandlerDefinition<State, Auth, Spec>[];
|
|
117
151
|
readonly contentTypes: string[];
|
|
118
152
|
readonly context: JSONObject;
|
|
119
153
|
|
|
120
154
|
/**
|
|
121
|
-
* @todo
|
|
122
|
-
*
|
|
123
155
|
* Creates a URL compatible with this action.
|
|
124
156
|
*/
|
|
125
157
|
url(): string;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Retrives the handler configured for the given content type.
|
|
161
|
+
*
|
|
162
|
+
* @param contentType The content type.
|
|
163
|
+
*/
|
|
164
|
+
handlerFor(contentType: string): HandlerDefinition<State, Auth, Spec> | undefined;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Performs this action using the given fetch Request
|
|
168
|
+
* returning a Response.
|
|
169
|
+
*/
|
|
170
|
+
perform(req: Request): Promise<Response>;
|
|
126
171
|
|
|
127
172
|
/**
|
|
128
173
|
* @todo
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {createServer} from 'node:http';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import test from 'node:test';
|
|
4
|
-
import {ResponseWriter} from './writer.
|
|
4
|
+
import {ResponseWriter} from './writer.ts';
|
|
5
5
|
import {AddressInfo} from 'node:net';
|
|
6
6
|
|
|
7
7
|
|
|
@@ -20,7 +20,7 @@ test('Writer writes hints', () => {
|
|
|
20
20
|
fetchPriority: 'high',
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
href: 'https://example.com/main.
|
|
23
|
+
href: 'https://example.com/main.ts',
|
|
24
24
|
as: 'script',
|
|
25
25
|
preload: true,
|
|
26
26
|
fetchPriority: 'low',
|
package/lib/actions/writer.ts
CHANGED