@occultist/occultist 0.0.1 → 0.0.3

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.
@@ -0,0 +1,14 @@
1
+ import type { CacheDetails, CacheHitHandle, CacheMeta, CacheStorage, CacheMissHandle } from './types.js';
2
+ export declare class FileCacheMeta implements CacheMeta {
3
+ #private;
4
+ constructor(filePath: string);
5
+ get(key: string): Promise<CacheHitHandle | CacheMissHandle>;
6
+ set(key: string, details: CacheDetails): Promise<void>;
7
+ }
8
+ export declare class FileSystemCacheStorage implements CacheStorage {
9
+ #private;
10
+ hash(key: string): string;
11
+ get(key: string): Promise<Blob>;
12
+ set(key: string, value: Blob): Promise<void>;
13
+ invalidate(key: string): Promise<void>;
14
+ }
@@ -0,0 +1,62 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { open, readFile, writeFile, rm } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ export class FileCacheMeta {
5
+ #filePath;
6
+ #handle;
7
+ #details = {};
8
+ constructor(filePath) {
9
+ this.#filePath = filePath;
10
+ }
11
+ async #init() {
12
+ this.#handle = await open(this.#filePath, 'w+');
13
+ const content = await this.#handle.readFile({ encoding: 'utf-8' });
14
+ this.#details = JSON.parse(content);
15
+ }
16
+ async get(key) {
17
+ if (this.#handle == null) {
18
+ this.#init();
19
+ }
20
+ const details = this.#details[key];
21
+ async function set(details) {
22
+ this.#details.set(key, details);
23
+ }
24
+ if (details == null) {
25
+ return {
26
+ type: 'cache-miss',
27
+ set,
28
+ };
29
+ }
30
+ return {
31
+ ...details,
32
+ type: 'cache-hit',
33
+ set,
34
+ };
35
+ }
36
+ async set(key, details) {
37
+ this.#details[key] = details;
38
+ this.#handle.writeFile(JSON.stringify(details));
39
+ }
40
+ }
41
+ export class FileSystemCacheStorage {
42
+ #directory;
43
+ #hashes = new Map();
44
+ hash(key) {
45
+ let hash = this.#hashes.get(key);
46
+ if (hash != null)
47
+ return hash;
48
+ hash = createHash('md5').update(key).digest('hex');
49
+ this.#hashes.set(key, hash);
50
+ return hash;
51
+ }
52
+ async get(key) {
53
+ const buffer = await readFile(join(this.#directory, this.hash(key)));
54
+ return new Blob([buffer]);
55
+ }
56
+ async set(key, value) {
57
+ await writeFile(join(this.#directory, this.hash(key)), value.stream());
58
+ }
59
+ async invalidate(key) {
60
+ await rm(join(this.#directory, this.hash(key)));
61
+ }
62
+ }
@@ -6,16 +6,15 @@ import { isNil } from "./utils/isNil.js";
6
6
  import { isObject } from "./utils/isObject.js";
7
7
  import { isPopulatedObject } from "./utils/isPopulatedObject.js";
8
8
  import { makeAppendProblemDetails } from "./utils/makeAppendProblemDetails.js";
9
- import { failsRequiredRequirement, failsTypeRequirement, failsContentTypeRequirement, failsMaxValue, failsMinValue, failValueMinLength, failValueMaxLength, failsStepValue, failsPatternValue, failsValidator, isObjectArraySpec, isObjectSpec, isArraySpec } from "./validators.js";
9
+ import { failsRequiredRequirement, failsTypeRequirement, failsContentTypeRequirement, failsMaxValue, failsMinValue, failsValueMinLength, failsValueMaxLength, failsStepValue, failsPatternValue, failsValidator, isObjectArraySpec, isObjectSpec, isArraySpec } from "./validators.js";
10
10
  import { InvalidActionParamsError, ProblemDetailsError } from "./errors.js";
11
11
  import { alwaysArray } from "./utils/alwaysArray.js";
12
12
  export async function processAction({ iri, req, spec, state, action, }) {
13
13
  let httpStatus = null;
14
- const payload = {};
15
- const transformers = {};
16
- const refs = {};
14
+ const payload = Object.create(null);
15
+ const transformers = Object.create(null);
16
+ const refs = Object.create(null);
17
17
  const appendProblemDetailsParam = makeAppendProblemDetails(refs);
18
- console.log('SPEC', spec);
19
18
  let params;
20
19
  let query;
21
20
  let iriValues;
@@ -117,7 +116,7 @@ export async function processAction({ iri, req, spec, state, action, }) {
117
116
  });
118
117
  return null;
119
118
  }
120
- else if (failValueMinLength(value, specValue)) {
119
+ else if (failsValueMinLength(value, specValue)) {
121
120
  appendProblemDetailsParam({
122
121
  status: 400,
123
122
  param: {
@@ -128,7 +127,7 @@ export async function processAction({ iri, req, spec, state, action, }) {
128
127
  });
129
128
  return null;
130
129
  }
131
- else if (failValueMaxLength(value, specValue)) {
130
+ else if (failsValueMaxLength(value, specValue)) {
132
131
  appendProblemDetailsParam({
133
132
  status: 400,
134
133
  param: {
@@ -221,7 +220,6 @@ export async function processAction({ iri, req, spec, state, action, }) {
221
220
  return [];
222
221
  }
223
222
  if (failsTypeRequirement(parentValue, specValue)) {
224
- throw new Error('Nope');
225
223
  appendProblemDetailsParam({
226
224
  param: {
227
225
  name: paramName,
@@ -233,7 +231,7 @@ export async function processAction({ iri, req, spec, state, action, }) {
233
231
  return null;
234
232
  }
235
233
  const arrayValue = alwaysArray(parentValue);
236
- if (failValueMinLength(arrayValue, specValue)) {
234
+ if (failsValueMinLength(arrayValue, specValue)) {
237
235
  appendProblemDetailsParam({
238
236
  param: {
239
237
  name: paramName,
@@ -244,7 +242,7 @@ export async function processAction({ iri, req, spec, state, action, }) {
244
242
  });
245
243
  return null;
246
244
  }
247
- else if (failValueMaxLength(arrayValue, specValue)) {
245
+ else if (failsValueMaxLength(arrayValue, specValue)) {
248
246
  appendProblemDetailsParam({
249
247
  param: {
250
248
  name: paramName,
@@ -337,7 +335,7 @@ export async function processAction({ iri, req, spec, state, action, }) {
337
335
  return null;
338
336
  }
339
337
  const arrayValue = alwaysArray(parentValue);
340
- if (failValueMinLength(arrayValue, specValue)) {
338
+ if (failsValueMinLength(arrayValue, specValue)) {
341
339
  appendProblemDetailsParam({
342
340
  param: {
343
341
  name: paramName,
@@ -348,7 +346,7 @@ export async function processAction({ iri, req, spec, state, action, }) {
348
346
  });
349
347
  return null;
350
348
  }
351
- else if (failValueMaxLength(arrayValue, specValue)) {
349
+ else if (failsValueMaxLength(arrayValue, specValue)) {
352
350
  appendProblemDetailsParam({
353
351
  param: {
354
352
  name: paramName,
@@ -1,7 +1,7 @@
1
1
  import { ProblemDetailsError } from "../errors.js";
2
2
  import jsonld from 'jsonld';
3
3
  export async function getRequestBodyValues({ req, action, }) {
4
- let bodyValues = {};
4
+ let bodyValues = Object.create(null);
5
5
  const contentType = req.headers.get('content-type');
6
6
  const mappedTypes = Object.entries(action.spec)
7
7
  .reduce((acc, [term, propertySpec]) => {
@@ -118,5 +118,6 @@ export async function getRequestBodyValues({ req, action, }) {
118
118
  delete compacted['@context'];
119
119
  bodyValues = compacted;
120
120
  }
121
+ Object.freeze(bodyValues);
121
122
  return { bodyValues };
122
123
  }
@@ -1,12 +1,12 @@
1
1
  import { ProblemDetailsError } from "../errors.js";
2
2
  import { getParamLocation } from "./getParamLocation.js";
3
3
  export function getRequestIRIValues({ iri, action, }) {
4
- const pathValues = {};
5
- const queryValues = {};
4
+ const pathValues = Object.create(null);
5
+ const queryValues = Object.create(null);
6
6
  // deno-lint-ignore no-explicit-any
7
- const iriValues = {};
7
+ const iriValues = Object.create(null);
8
8
  const urlPatternResult = action.pattern.exec(iri);
9
- const pathParams = urlPatternResult?.pathname.groups || {};
9
+ const pathParams = urlPatternResult?.pathname.groups || Object.create(null);
10
10
  const searchParams = new URL(iri).searchParams;
11
11
  const valueNames = Object.values(action.spec)
12
12
  .filter((specItem) => typeof specItem.valueName === 'string')
@@ -11,6 +11,6 @@ export declare function failsMinValue(value: JSONValue, specValue: PropertySpec)
11
11
  export declare function failsMaxValue(value: JSONValue, specValue: PropertySpec): boolean;
12
12
  export declare function failsStepValue(value: JSONValue, specValue: PropertySpec): boolean;
13
13
  export declare function failsPatternValue(value: JSONValue, specValue: PropertySpec): boolean;
14
- export declare function failValueMinLength(value: JSONValue, specValue: PropertySpec): boolean;
15
- export declare function failValueMaxLength(value: JSONValue, specValue: PropertySpec): boolean;
14
+ export declare function failsValueMinLength(value: JSONValue, specValue: PropertySpec): boolean;
15
+ export declare function failsValueMaxLength(value: JSONValue, specValue: PropertySpec): boolean;
16
16
  export declare function failsValidator(value: JSONValue | File, specValue: PropertySpec): boolean;
@@ -20,7 +20,7 @@ export function isArraySpec(spec) {
20
20
  return !isObject(spec.properties) && Boolean(spec.multipleValues);
21
21
  }
22
22
  export function failsRequiredRequirement(value, specValue) {
23
- return specValue.valueRequired && (typeof value === 'undefined' || value === null);
23
+ return specValue.valueRequired && value == null;
24
24
  }
25
25
  export function failsTypeRequirement(value, specValue) {
26
26
  const dataType = specValue.dataType;
@@ -107,7 +107,7 @@ export function failsPatternValue(value, specValue) {
107
107
  const regexp = new RegExp(specValue.valuePattern);
108
108
  return !regexp.test(value);
109
109
  }
110
- export function failValueMinLength(value, specValue) {
110
+ export function failsValueMinLength(value, specValue) {
111
111
  if (typeof specValue.valueMinLength !== 'number') {
112
112
  return false;
113
113
  }
@@ -116,7 +116,7 @@ export function failValueMinLength(value, specValue) {
116
116
  }
117
117
  return true;
118
118
  }
119
- export function failValueMaxLength(value, specValue) {
119
+ export function failsValueMaxLength(value, specValue) {
120
120
  if (typeof specValue.valueMaxLength !== 'number') {
121
121
  return false;
122
122
  }
@@ -0,0 +1,86 @@
1
+ import {createHash} from 'node:crypto';
2
+ import type {CacheDetails, CacheHitHandle, CacheMeta, CacheStorage, CacheMissHandle} from './types.js';
3
+ import {FileHandle, open, readFile, writeFile, rm} from 'node:fs/promises';
4
+ import {join} from 'node:path';
5
+
6
+
7
+
8
+ export class FileCacheMeta implements CacheMeta {
9
+
10
+ #filePath: string;
11
+ #handle: FileHandle | undefined;
12
+ #details: Record<string, CacheDetails> = {};
13
+
14
+ constructor(filePath: string) {
15
+ this.#filePath = filePath;
16
+ }
17
+
18
+ async #init(): Promise<void> {
19
+ this.#handle = await open(this.#filePath, 'w+');
20
+ const content = await this.#handle.readFile({ encoding: 'utf-8' });
21
+
22
+ this.#details = JSON.parse(content);
23
+ }
24
+
25
+ async get(key: string): Promise<CacheHitHandle| CacheMissHandle> {
26
+ if (this.#handle == null) {
27
+ this.#init();
28
+ }
29
+
30
+ const details = this.#details[key];
31
+ async function set(details: CacheDetails) {
32
+ this.#details.set(key, details);
33
+ }
34
+
35
+ if (details == null) {
36
+ return {
37
+ type: 'cache-miss',
38
+ set,
39
+ };
40
+ }
41
+
42
+ return {
43
+ ...details,
44
+ type: 'cache-hit',
45
+ set,
46
+ };
47
+ }
48
+
49
+ async set(key: string, details: CacheDetails) {
50
+ this.#details[key] = details;
51
+ this.#handle.writeFile(JSON.stringify(details));
52
+ }
53
+
54
+ }
55
+
56
+ export class FileSystemCacheStorage implements CacheStorage {
57
+
58
+ #directory: string;
59
+ #hashes: Map<string, string> = new Map();
60
+
61
+ hash(key: string): string {
62
+ let hash = this.#hashes.get(key);
63
+
64
+ if (hash != null) return hash;
65
+
66
+ hash = createHash('md5').update(key).digest('hex');
67
+
68
+ this.#hashes.set(key, hash);
69
+
70
+ return hash;
71
+ }
72
+
73
+ async get(key: string): Promise<Blob> {
74
+ const buffer = await readFile(join(this.#directory, this.hash(key)));
75
+
76
+ return new Blob([buffer]);
77
+ }
78
+
79
+ async set(key: string, value: Blob): Promise<void> {
80
+ await writeFile(join(this.#directory, this.hash(key)), value.stream());
81
+ }
82
+
83
+ async invalidate(key: string): Promise<void> {
84
+ await rm(join(this.#directory, this.hash(key)));
85
+ }
86
+ }
@@ -7,7 +7,7 @@ import { isNil } from "./utils/isNil.js";
7
7
  import { isObject } from "./utils/isObject.js";
8
8
  import { isPopulatedObject } from "./utils/isPopulatedObject.js";
9
9
  import { type ProblemDetailsParamsRefs, makeAppendProblemDetails } from "./utils/makeAppendProblemDetails.js";
10
- import { failsRequiredRequirement, failsTypeRequirement, failsContentTypeRequirement, failsMaxValue, failsMinValue, failValueMinLength, failValueMaxLength, failsStepValue, failsPatternValue, failsValidator, isObjectArraySpec, isObjectSpec, isArraySpec } from "./validators.js";
10
+ import { failsRequiredRequirement, failsTypeRequirement, failsContentTypeRequirement, failsMaxValue, failsMinValue, failsValueMinLength, failsValueMaxLength, failsStepValue, failsPatternValue, failsValidator, isObjectArraySpec, isObjectSpec, isArraySpec } from "./validators.js";
11
11
  import { InvalidActionParamsError, ProblemDetailsError } from "./errors.js";
12
12
  import { alwaysArray } from "./utils/alwaysArray.js";
13
13
  import type { ImplementedAction } from "./actions/types.js";
@@ -46,13 +46,11 @@ export async function processAction<
46
46
  action,
47
47
  }: ProcessActionArgs<State, Spec>): Promise<ProcessActionResult<Spec>> {
48
48
  let httpStatus: number | null = null;
49
- const payload: Partial<ActionPayload<Spec>> = {};
50
- const transformers: Record<string, Promise<unknown>> = {};
51
- const refs: ProblemDetailsParamsRefs = {};
49
+ const payload: Partial<ActionPayload<Spec>> = Object.create(null);
50
+ const transformers: Record<string, Promise<unknown>> = Object.create(null);
51
+ const refs: ProblemDetailsParamsRefs = Object.create(null);
52
52
  const appendProblemDetailsParam = makeAppendProblemDetails(refs);
53
53
 
54
- console.log('SPEC', spec);
55
-
56
54
  let params: ParsedIRIValues;
57
55
  let query: ParsedIRIValues;
58
56
  let iriValues: IRIValue;
@@ -181,7 +179,7 @@ export async function processAction<
181
179
  });
182
180
 
183
181
  return null;
184
- } else if (failValueMinLength(value, specValue)) {
182
+ } else if (failsValueMinLength(value, specValue)) {
185
183
  appendProblemDetailsParam({
186
184
  status: 400,
187
185
  param: {
@@ -192,7 +190,7 @@ export async function processAction<
192
190
  });
193
191
 
194
192
  return null;
195
- } else if (failValueMaxLength(value, specValue)) {
193
+ } else if (failsValueMaxLength(value, specValue)) {
196
194
  appendProblemDetailsParam({
197
195
  status: 400,
198
196
  param: {
@@ -303,7 +301,6 @@ export async function processAction<
303
301
  }
304
302
 
305
303
  if (failsTypeRequirement(parentValue, specValue)) {
306
- throw new Error('Nope');
307
304
  appendProblemDetailsParam({
308
305
  param: {
309
306
  name: paramName,
@@ -318,7 +315,7 @@ export async function processAction<
318
315
 
319
316
  const arrayValue = alwaysArray(parentValue);
320
317
 
321
- if (failValueMinLength(arrayValue, specValue)) {
318
+ if (failsValueMinLength(arrayValue, specValue)) {
322
319
  appendProblemDetailsParam({
323
320
  param: {
324
321
  name: paramName,
@@ -329,7 +326,7 @@ export async function processAction<
329
326
  });
330
327
 
331
328
  return null;
332
- } else if (failValueMaxLength(arrayValue, specValue)) {
329
+ } else if (failsValueMaxLength(arrayValue, specValue)) {
333
330
  appendProblemDetailsParam({
334
331
  param: {
335
332
  name: paramName,
@@ -464,7 +461,7 @@ export async function processAction<
464
461
 
465
462
  const arrayValue = alwaysArray(parentValue);
466
463
 
467
- if (failValueMinLength(arrayValue, specValue)) {
464
+ if (failsValueMinLength(arrayValue, specValue)) {
468
465
  appendProblemDetailsParam({
469
466
  param: {
470
467
  name: paramName,
@@ -475,7 +472,7 @@ export async function processAction<
475
472
  });
476
473
 
477
474
  return null;
478
- } else if (failValueMaxLength(arrayValue, specValue)) {
475
+ } else if (failsValueMaxLength(arrayValue, specValue)) {
479
476
  appendProblemDetailsParam({
480
477
  param: {
481
478
  name: paramName,
@@ -23,7 +23,7 @@ export async function getRequestBodyValues<
23
23
  req: Request,
24
24
  action: ImplementedAction<State, Spec>,
25
25
  }): Promise<RequestBodyResult> {
26
- let bodyValues: BodyValue = {};
26
+ let bodyValues: BodyValue = Object.create(null);
27
27
  const contentType = req.headers.get('content-type');
28
28
  const mappedTypes: Record<string, {
29
29
  term: string;
@@ -151,5 +151,7 @@ export async function getRequestBodyValues<
151
151
  bodyValues = compacted as JSONObject;
152
152
  }
153
153
 
154
+ Object.freeze(bodyValues);
155
+
154
156
  return { bodyValues };
155
157
  }
@@ -40,12 +40,12 @@ export function getRequestIRIValues<
40
40
  iri: string;
41
41
  action: ImplementedAction<State, Spec>;
42
42
  }): RequestIRIResult<Spec> {
43
- const pathValues: ParsedIRIValues = {};
44
- const queryValues: ParsedIRIValues = {};
43
+ const pathValues: ParsedIRIValues = Object.create(null);
44
+ const queryValues: ParsedIRIValues = Object.create(null);
45
45
  // deno-lint-ignore no-explicit-any
46
- const iriValues = {} as IRIValue<any>;
46
+ const iriValues = Object.create(null) as IRIValue<any>;
47
47
  const urlPatternResult = action.pattern.exec(iri);
48
- const pathParams = urlPatternResult?.pathname.groups || {};
48
+ const pathParams = urlPatternResult?.pathname.groups || Object.create(null);
49
49
  const searchParams = new URL(iri).searchParams;
50
50
 
51
51
  const valueNames = Object.values<PropertySpec>(action.spec)
package/lib/validators.ts CHANGED
@@ -36,7 +36,7 @@ export function failsRequiredRequirement(
36
36
  value: JSONValue,
37
37
  specValue: PropertySpec,
38
38
  ) {
39
- return specValue.valueRequired && (typeof value === 'undefined' || value === null);
39
+ return specValue.valueRequired && value == null;
40
40
  }
41
41
 
42
42
  export function failsTypeRequirement(
@@ -146,7 +146,7 @@ export function failsPatternValue(value: JSONValue, specValue: PropertySpec) {
146
146
  return !regexp.test(value);
147
147
  }
148
148
 
149
- export function failValueMinLength(value: JSONValue, specValue: PropertySpec) {
149
+ export function failsValueMinLength(value: JSONValue, specValue: PropertySpec) {
150
150
  if (typeof specValue.valueMinLength !== 'number') {
151
151
  return false;
152
152
  }
@@ -158,7 +158,7 @@ export function failValueMinLength(value: JSONValue, specValue: PropertySpec) {
158
158
  return true;
159
159
  }
160
160
 
161
- export function failValueMaxLength(value: JSONValue, specValue: PropertySpec) {
161
+ export function failsValueMaxLength(value: JSONValue, specValue: PropertySpec) {
162
162
  if (typeof specValue.valueMaxLength !== 'number') {
163
163
  return false;
164
164
  }
@@ -184,3 +184,4 @@ export function failsValidator(
184
184
 
185
185
  return !validator(value);
186
186
  }
187
+
package/package.json CHANGED
@@ -5,8 +5,8 @@
5
5
  "homepage": "https://github.com/occultist-dev/occultist",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
- "main": "dist/occultist.ts",
9
- "types": "dist/occultist.d.ts",
8
+ "main": "dist/mod.js",
9
+ "types": "dist/mod.d.ts",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "git+https://github.com/occultist-dev/occultist.git"
@@ -34,7 +34,7 @@
34
34
  "jsonld": "^9.0.0",
35
35
  "typescript": "^5.9.3"
36
36
  },
37
- "version": "0.0.1",
37
+ "version": "0.0.3",
38
38
  "scripts": {
39
39
  "build": "tsc"
40
40
  }