@sphereon/ssi-sdk.resource-resolver
Version:
318 lines (313 loc) • 10.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
// plugin.schema.json
var require_plugin_schema = __commonJS({
"plugin.schema.json"(exports, module) {
module.exports = {
IResourceResolver: {
components: {
schemas: {
ResourceResolverOptions: {
type: "object",
properties: {}
},
ResolveArgs: {
type: "object",
properties: {}
},
ResolveOptions: {
type: "object",
properties: {}
},
ResourceType: {
type: "object",
properties: {}
},
ClearAllResourcesArgs: {
type: "object",
properties: {}
},
PersistResourceArgs: {
type: "object",
properties: {}
},
GetResourceArgs: {
type: "object",
properties: {}
},
StoreIdStrArgs: {
type: "object",
properties: {}
},
NamespaceStrArgs: {
type: "object",
properties: {}
},
PrefixArgs: {
type: "object",
properties: {}
},
StoreArgs: {
type: "object",
properties: {}
},
Resource: {
type: "object",
properties: {}
},
SerializedResponse: {
type: "object",
properties: {}
}
},
methods: {
resourceResolve: {
description: "",
arguments: {
$ref: "#/components/schemas/ResolveArgs"
},
returnType: {}
},
resourceClearAllResources: {
description: "",
arguments: {
$ref: "#/components/schemas/ClearAllResourcesArgs"
},
returnType: {}
},
resourceDefaultStoreId: {
description: "",
returnType: {}
},
resourceDefaultNamespace: {
description: "",
returnType: {}
},
resourceDefaultTtl: {
description: "",
returnType: {}
}
}
}
}
};
}
});
// src/agent/ResourceResolver.ts
import { KeyValueStore } from "@sphereon/ssi-sdk.kv-store-temp";
import fetch, { Response as Response2, Headers as Headers2 } from "cross-fetch";
// src/utils/ResourceResolverUtils.ts
import { Headers, Response, Request as Request2 } from "cross-fetch";
import { fromString } from "uint8arrays/from-string";
import { toString } from "uint8arrays/to-string";
var getResourceIdentifier = /* @__PURE__ */ __name((input) => {
if (typeof input === "string") {
return input;
} else if (input instanceof Request2) {
return input.url;
} else if (input instanceof URL) {
return input.toString();
}
throw new Error("Invalid input type. Expected Request, string, or URL.");
}, "getResourceIdentifier");
var serializeResponse = /* @__PURE__ */ __name(async (response) => {
const arrayBuffer = await response.arrayBuffer();
const base64Url = toString(new Uint8Array(arrayBuffer), "base64url");
return {
status: response.status,
statusText: response.statusText,
// @ts-ignore
headers: Object.fromEntries(response.headers.entries()),
body: base64Url
};
}, "serializeResponse");
var deserializeResponse = /* @__PURE__ */ __name(async (data) => {
const { status, statusText, headers, body } = data;
const uint8Array = fromString(body, "base64url");
const arrayBuffer = uint8Array.buffer.slice(uint8Array.byteOffset, uint8Array.byteOffset + uint8Array.byteLength);
return new Response(arrayBuffer, {
status,
statusText,
headers: new Headers(headers)
});
}, "deserializeResponse");
var isCacheWithinMaxAge = /* @__PURE__ */ __name((cachedResource, resolveOpts) => {
return cachedResource && (resolveOpts?.maxAgeMs === void 0 || Date.now() - cachedResource.insertedAt < resolveOpts.maxAgeMs);
}, "isCacheWithinMaxAge");
// src/agent/ResourceResolver.ts
var ResourceResolver = class {
static {
__name(this, "ResourceResolver");
}
schema = schema.IResourceResolver;
methods = {
resourceResolve: this.resourceResolve.bind(this),
resourceClearAllResources: this.resourceClearAllResources.bind(this),
resourceDefaultStoreId: this.resourceDefaultStoreId.bind(this),
resourceDefaultNamespace: this.resourceDefaultNamespace.bind(this),
resourceDefaultTtl: this.resourceDefaultTtl.bind(this)
};
defaultStoreId;
defaultNamespace;
defaultTtl;
detectLocation;
_resourceStores;
constructor(options) {
const { defaultStore, defaultNamespace, resourceStores, ttl, detectLocation } = options ?? {};
this.defaultStoreId = defaultStore ?? "_default";
this.defaultNamespace = defaultNamespace ?? "resources";
this.defaultTtl = ttl ?? 3600;
this.detectLocation = detectLocation ?? false;
if (resourceStores && resourceStores instanceof Map) {
this._resourceStores = resourceStores;
} else if (resourceStores) {
this._resourceStores = (/* @__PURE__ */ new Map()).set(this.defaultStoreId, resourceStores);
} else {
this._resourceStores = (/* @__PURE__ */ new Map()).set(this.defaultStoreId, new KeyValueStore({
namespace: this.defaultNamespace,
store: /* @__PURE__ */ new Map(),
ttl: this.defaultTtl
}));
}
}
/** {@inheritDoc IResourceResolver.resourceResolve} */
async resourceResolve(args, context) {
const { input, init, resourceType, resolveOpts, partyCorrelationId, storeId, namespace } = args;
const resourceIdentifier = getResourceIdentifier(input);
const cachedResource = await this.getResource({
resourceIdentifier,
storeId,
namespace
});
if (cachedResource.value && isCacheWithinMaxAge(cachedResource.value, resolveOpts)) {
return deserializeResponse(cachedResource.value.response);
}
if (resolveOpts?.onlyCache) {
return new Response2(JSON.stringify({
error: "Resource not found"
}), {
status: 404,
statusText: "Not Found",
headers: new Headers2({
"Content-Type": "application/json"
})
});
}
let location;
if (this.detectLocation) {
location = await this.retrieveLocation(input, context);
}
const response = await fetch(input, init);
if (!resolveOpts?.skipPersistence && response.status >= 200 && response.status < 300) {
const serializedResponse = await serializeResponse(response);
const resource = {
location,
response: serializedResponse,
resourceType,
insertedAt: Date.now(),
partyCorrelationId
};
const cachedResource2 = await this.persistResource({
resource,
resourceIdentifier,
namespace,
storeId
});
if (!cachedResource2.value) {
return Promise.reject(Error("Resource not present in persistence result"));
}
return deserializeResponse(cachedResource2.value.response);
}
return response;
}
async retrieveLocation(input, context) {
let url;
if (input instanceof Request && input.url !== void 0 && input.url !== null) {
url = new URL(input.url);
} else if (input instanceof URL) {
url = input;
} else {
throw Error(`input type is required to be RequestInfo | URL`);
}
return await context.agent.anomalyDetectionLookupLocation({
ipOrHostname: url.hostname
});
}
/** {@inheritDoc IResourceResolver.resourceClearAllResources} */
async resourceClearAllResources(args, context) {
const { storeId } = args;
return await this.store({
stores: this._resourceStores,
storeId
}).clear().then(() => true);
}
/** {@inheritDoc IResourceResolver.resourceDefaultStoreId} */
async resourceDefaultStoreId(context) {
return this.defaultStoreId;
}
/** {@inheritDoc IResourceResolver.resourceDefaultNamespace} */
async resourceDefaultNamespace(context) {
return this.defaultNamespace;
}
/** {@inheritDoc IResourceResolver.resourceDefaultTtl} */
async resourceDefaultTtl(context) {
return this.defaultTtl;
}
async getResource(args) {
const { resourceIdentifier, storeId, namespace } = args;
return this.store({
stores: this._resourceStores,
storeId
}).getAsValueData(this.prefix({
namespace,
resourceIdentifier
}));
}
async persistResource(args) {
const { resource, resourceIdentifier, ttl } = args;
const namespace = this.namespaceStr(args);
const storeId = this.storeIdStr(args);
return await this.store({
stores: this._resourceStores,
storeId
}).set(this.prefix({
namespace,
resourceIdentifier
}), resource, ttl ?? this.defaultTtl);
}
store(args) {
const storeId = this.storeIdStr({
storeId: args.storeId
});
const store = args.stores.get(storeId);
if (!store) {
throw Error(`Could not get resource store: ${storeId}`);
}
return store;
}
storeIdStr(args) {
const { storeId } = args;
return storeId ?? this.defaultStoreId;
}
namespaceStr(args) {
const { namespace } = args;
return namespace ?? this.defaultNamespace;
}
prefix(args) {
const { namespace, resourceIdentifier } = args;
return `${this.namespaceStr({
namespace
})}:${resourceIdentifier}`;
}
};
// src/index.ts
var schema = require_plugin_schema();
export {
ResourceResolver,
schema
};
//# sourceMappingURL=index.js.map