iopa
Version:
API-first, Internet of Things (IoT) stack for Typescript, official implementation of the Internet Open Protocols Alliance (IOPA) reference pattern
1,571 lines (1,551 loc) • 42.4 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// src/util/shallow.ts
var shallow_exports = {};
__export(shallow_exports, {
assign: () => assign,
clone: () => clone,
cloneDoubleLayer: () => cloneDoubleLayer,
cloneFilter: () => cloneFilter,
cloneTripleLayer: () => cloneTripleLayer,
copy: () => copy,
merge: () => merge,
mergeContext: () => mergeContext
});
function merge(target, defaults, replace) {
if (!target) {
throw new Error("target must not be empty");
}
if (!defaults) {
defaults = {};
}
if (replace) {
for (var key in defaults) {
if (defaults.hasOwnProperty(key)) {
target[key] = defaults[key];
}
}
} else {
for (var key in defaults) {
if (defaults.hasOwnProperty(key) && !target.hasOwnProperty(key)) {
target[key] = defaults[key];
}
}
}
}
function assign(target) {
if (!target) {
throw new Error("target must not be empty");
}
target = Object(target);
for (let index = 1; index < arguments.length; index++) {
const source = arguments[index];
if (source != null) {
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
}
return target;
}
function copy(source, target) {
if (!source) {
source = {};
}
if (!target) {
target = Object.create(Object.getPrototypeOf(source));
}
for (const key in source) {
if (source.hasOwnProperty(key)) {
target[key] = source[key];
}
}
return target;
}
function clone(source) {
const clone2 = Object.create(Object.getPrototypeOf(source));
for (const key in source) {
if (source.hasOwnProperty(key)) {
clone2[key] = source[key];
}
}
return clone2;
}
function cloneDoubleLayer(source) {
const clone2 = Object.create(Object.getPrototypeOf(source));
for (const key1 in source) {
if (source.hasOwnProperty(key1)) {
const item = source[key1];
if (typeof item === "object") {
const targetItem = Object.create(Object.getPrototypeOf(item));
for (const key2 in item) {
if (item.hasOwnProperty(key2)) {
targetItem[key2] = item[key2];
}
}
clone2[key1] = targetItem;
} else {
clone2[key1] = item;
}
}
}
return clone2;
}
function cloneTripleLayer(source) {
const clone2 = Object.create(Object.getPrototypeOf(source));
for (const key1 in source) {
if (source.hasOwnProperty(key1)) {
const item = source[key1];
if (typeof item === "object") {
const targetItem = Object.create(Object.getPrototypeOf(item));
for (const key2 in item) {
if (item.hasOwnProperty(key2)) {
const item2 = item[key2];
if (typeof item2 === "object") {
const targetItem2 = Object.create(Object.getPrototypeOf(item2));
for (const key3 in item2) {
if (item2.hasOwnProperty(key3)) {
targetItem2[key3] = item[key3];
}
}
targetItem[key2] = targetItem2;
} else {
targetItem[key2] = item2;
}
}
}
clone2[key1] = targetItem;
} else {
clone2[key1] = item;
}
}
}
return clone2;
}
function cloneFilter(source, blacklist) {
const clone2 = Object.create(Object.getPrototypeOf(source));
for (const key in source) {
if (source.hasOwnProperty(key) && blacklist.indexOf(key) == -1) {
clone2[key] = source[key];
}
}
return clone2;
}
function mergeContext(target, defaults) {
if (!target) {
throw new Error("target must not be empty");
}
if (!defaults) {
return;
}
Object.keys(defaults).forEach((key) => {
if (key !== "iopa.Headers") {
target[key] = defaults[key];
} else {
const targetHeaders = target[key];
defaults[key].forEach((value, key2) => {
targetHeaders.set(key2, value);
});
}
});
}
// src/util/url.ts
var url_exports = {};
__export(url_exports, {
getPathFromURL: () => getPathFromURL,
getPattern: () => getPattern,
isAbsoluteURL: () => isAbsoluteURL,
mergePath: () => mergePath,
splitPath: () => splitPath
});
var URL_REGEXP = /^https?:\/\/[a-zA-Z0-9\-\.:]+(\/?[^?#]*)/;
var splitPath = (path) => {
const paths = path.split(/\//);
if (paths[0] === "") {
paths.shift();
}
return paths;
};
var patternCache = {};
var getPattern = (label) => {
if (label === "*") {
return "*";
}
const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
if (match) {
if (!patternCache[label]) {
if (match[2]) {
patternCache[label] = [
label,
match[1],
new RegExp("^" + match[2] + "$")
];
} else {
patternCache[label] = [label, match[1], true];
}
}
return patternCache[label];
}
return null;
};
var getPathFromURL = (url, params = { strict: true }) => {
if (params.strict === false && url.endsWith("/")) {
url = url.slice(0, -1);
}
const match = url.match(URL_REGEXP);
if (match) {
return match[1];
}
return "";
};
var isAbsoluteURL = (url) => {
const match = url.match(URL_REGEXP);
if (match) {
return true;
}
return false;
};
var mergePath = (...paths) => {
let p = "";
let endsWithSlash = false;
for (let path of paths) {
if (p.endsWith("/")) {
p = p.slice(0, -1);
endsWithSlash = true;
}
if (!path.startsWith("/")) {
path = `/${path}`;
}
if (path === "/" && endsWithSlash) {
p = `${p}/`;
} else if (path !== "/") {
p = `${p}${path}`;
}
if (path === "/" && p === "") {
p = "/";
}
}
return p;
};
// src/util/status.ts
var status_exports = {};
__export(status_exports, {
getStatusText: () => getStatusText
});
var statuses = {
100: "Continue",
101: "Switching Protocols",
102: "Processing",
103: "Early Hints",
200: "OK",
201: "Created",
202: "Accepted",
204: "No Content",
206: "Partial Content",
301: "Moved Permanently",
302: "Moved Temporarily",
303: "See Other",
304: "Not Modified",
307: "Temporary Redirect",
308: "Permanent Redirect",
400: "Bad Request",
401: "Unauthorized",
402: "Payment Required",
403: "Forbidden",
404: "Not Found",
405: "Not Allowed",
406: "Not Acceptable",
408: "Request Time-out",
409: "Conflict",
410: "Gone",
411: "Length Required",
412: "Precondition Failed",
413: "Request Entity Too Large",
414: "Request-URI Too Large",
415: "Unsupported Media Type",
416: "Requested Range Not Satisfiable",
421: "Misdirected Request",
429: "Too Many Requests",
500: "Internal Server Error",
501: "Not Implemented",
502: "Bad Gateway",
503: "Service Temporarily Unavailable",
504: "Gateway Time-out",
505: "HTTP Version Not Supported",
507: "Insufficient Storage"
};
var getStatusText = (statusCode) => {
const text = statuses[statusCode];
return text;
};
// src/util/prototype.ts
function cloneKeyBehaviors(targetObjectPrototype, sourceObjectprototype, iopaContextKey, response) {
Object.getOwnPropertyNames(sourceObjectprototype).forEach((srcProp) => {
if (typeof sourceObjectprototype[srcProp] === "function") {
targetObjectPrototype[srcProp] = (...rest) => {
let item;
if (response) {
item = targetObjectPrototype[iopaContextKey];
} else {
item = targetObjectPrototype.response[iopaContextKey];
}
return item[srcProp](...rest);
};
} else {
Object.defineProperty(targetObjectPrototype, srcProp, {
get() {
let item;
if (response) {
item = this[iopaContextKey];
} else {
item = this.response[iopaContextKey];
}
return item[srcProp];
},
set(val) {
let item;
if (response) {
item = this[iopaContextKey];
} else {
item = this.response[iopaContextKey];
}
item[srcProp] = val;
}
});
}
});
}
// src/util/disposable.ts
var Disposable = class {
_disposer;
constructor(disposer) {
this._disposer = disposer;
}
dispose() {
this._disposer.apply(this._disposer);
}
};
// src/iopa/constants.ts
var VERSION = "4.0";
var URN_APP = "urn:io.iopa:app";
var AppRef = {
id: URN_APP,
description: "Iopa App Capability common to every Iopa App, includes host name and version"
};
// src/util/guid.ts
function guid() {
return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;
}
function s4() {
return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1);
}
// src/util/freelist.ts
var FreeList = class {
name;
max;
_constructor;
list;
constructor(name, max, factory) {
this.name = name;
this._constructor = factory;
this.max = max;
this.list = [];
}
alloc(...args) {
return this.list.length ? this.list.shift() : this._constructor(...args);
}
free(obj) {
if (this.list.length < this.max) {
this.list.push(obj);
return true;
}
return false;
}
};
// src/util/events.ts
var ExtendableEventTarget = class extends EventTarget {
constructor() {
super();
}
dispatchEvent(event) {
if (!(event instanceof Event)) {
const { type, ...rest } = event;
const eventInstance = new Event(type);
Object.keys(rest).forEach((key) => {
eventInstance[key] = rest[key];
});
event = eventInstance;
}
return super.dispatchEvent(event);
}
async dispatchEventExtendable(event) {
const promises = [];
const extendableEvent = {
...event,
waitUntil: (p) => {
promises.push(p);
}
};
const result = this.dispatchEvent(extendableEvent);
await Promise.all(promises);
return result;
}
};
var TraceEvent = class extends Event {
label;
get type() {
return super.type;
}
constructor(type, eventInitDict) {
const { label, ...options } = eventInitDict || {};
super(type, options);
this.label = label;
}
};
// src/iopa/logging.ts
function noop() {
}
var logger = {
flush: noop,
fatal: noop,
error: noop,
warn: noop,
info: noop,
debug: noop,
trace: noop,
child: () => logger,
level: "info",
silent: noop,
isLevelEnabled: function(level) {
throw new Error("Function not implemented.");
},
bindings: function() {
throw new Error("Function not implemented.");
},
setBindings: function(bindings) {
throw new Error("Function not implemented.");
}
};
var consoleLogger = {
flush: noop,
fatal: console.error,
error: console.error,
warn: console.warn,
info: console.info,
debug: console.debug,
trace: console.trace,
child: () => consoleLogger,
level: "info",
silent: noop,
isLevelEnabled: function(level) {
throw new Error("Function not implemented.");
},
bindings: function() {
throw new Error("Function not implemented.");
},
setBindings: function(bindings) {
throw new Error("Function not implemented.");
}
};
var logging_default = logger;
// src/iopa/map.ts
var _IopaMap = class {
constructor(data, prevData) {
if (prevData) {
this._loadEntries(prevData.entries());
}
if (data) {
if (Array.isArray(data)) {
this._loadEntries(data);
} else if ("entries" in data) {
this._loadEntries(data.entries());
} else {
this._loadEntries(Object.entries(data));
}
}
}
get(key) {
return this[key];
}
set(data, value) {
if (value || typeof data !== "object") {
this[data] = value;
return;
}
if (Array.isArray(data)) {
this._loadEntries(data);
} else if ("entries" in data) {
this._loadEntries(data.entries());
} else {
this._loadEntries(Object.entries(data));
}
}
_loadEntries(entries) {
for (const entry of entries) {
this.set(entry[0], entry[1]);
}
}
getRef(iRef) {
return this[iRef.id];
}
has(key) {
return key in this;
}
addRef(iRef, value) {
this[iRef.id] = value;
return value;
}
delete(key) {
if (key in this) {
delete this[key];
return true;
}
return false;
}
default(key, valueFn) {
if (key in this) {
} else if (typeof valueFn === "function") {
this.set(key, valueFn());
} else {
this.set(key, valueFn);
}
return this.get(key);
}
entries() {
return Object.entries(this);
}
toString() {
return jsonSerialize(this.toJSON());
}
toJSON() {
const jsonObj = {};
for (const key of Object.getOwnPropertyNames(this).filter((key2) => !key2.startsWith("_") && !_IopaMap._BLACK_LIST_STRINGIFY.includes(key2) && this[key2] != null)) {
if (typeof this[key] === "object" && this[key].constructor.name.toString() === "URL") {
jsonObj[key] = this[key].href;
break;
}
jsonObj[key] = this[key];
}
const proto1 = Object.getPrototypeOf(this);
const proto2 = Object.getPrototypeOf(proto1);
[proto1, proto2].forEach((proto) => {
for (const key of Object.getOwnPropertyNames(proto).filter((key2) => !(key2 in jsonObj) && !key2.startsWith("_") && !_IopaMap._BLACK_LIST_STRINGIFY.includes(key2) && this[key2] != null)) {
const desc = Object.getOwnPropertyDescriptor(proto, key);
const hasGetter = desc && typeof desc.get === "function";
if (hasGetter) {
const value = desc.get.call(this);
if (typeof value === "object" && value.constructor.name.toString() === "Headers") {
jsonObj[key] = Object.fromEntries(value.entries());
break;
}
jsonObj[key] = value;
}
}
});
if (this["iopa.Headers"]) {
jsonObj["iopa.Headers"] = Object.fromEntries(this["iopa.Headers"].entries());
}
return jsonObj;
}
};
var IopaMap = _IopaMap;
__publicField(IopaMap, "_BLACK_LIST_STRINGIFY", [
"app",
"body",
"bodyUsed",
"capability",
"create",
"createChild",
"delete",
"dispose",
"get",
"headers",
"iopa.Body",
"iopa.Events",
"iopa.Headers",
"iopa.IsFinalized",
"iopa.LogStream",
"iopa.RawRequest",
"iopa.RawRequestClone",
"iopa.RawResponse",
"iopa.RawResponseClone",
"iopa.Url",
"log",
"method",
"ok",
"redirected",
"response",
"server.AbortController",
"server.AbortSignal",
"server.Capabilities",
"server.CurrentMiddleware",
"server.Environment",
"server.Events",
"server.PassThroughOnException",
"server.Trace",
"server.WaitUntil",
"set",
"setCapability",
"signal",
"toJSON",
"url"
]);
function getCircularReplacer() {
const seen = /* @__PURE__ */ new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return void 0;
}
seen.add(value);
if ("toJSON" in value) {
return value.toJSON();
}
}
return value;
};
}
function jsonSerialize(data) {
return JSON.stringify(data, getCircularReplacer(), 2);
}
// src/iopa/context-core.ts
var ContextCore = class extends IopaMap {
"iopa.Version";
dispose;
createChild;
log;
app;
init() {
const abortController = new AbortController();
this.set("server.Timestamp", Date.now());
this.set("iopa.Events", new ExtendableEventTarget());
this.set("iopa.Version", VERSION);
this.set("server.AbortController", abortController);
this.set("server.AbortSignal", abortController.signal);
this.set("server.CurrentMiddleware", "");
this.set("log", logging_default);
return this;
}
dispatchEventExtendable(event) {
return this.get("iopa.Events").dispatchEventExtendable(event);
}
addEventListener(type, callback, options) {
return this.get("iopa.Events").addEventListener(type, callback, options);
}
dispatchEvent(event) {
return this.get("iopa.Events").dispatchEvent(event);
}
removeEventListener(type, callback, options) {
return this.get("iopa.Events").removeEventListener(type, callback, options);
}
using(appFuncPromiseOrValue) {
if (typeof appFuncPromiseOrValue === "function") {
return _using({
context: this,
p: appFuncPromiseOrValue(this)
});
}
return _using({
context: this,
p: appFuncPromiseOrValue
});
}
capability(keyOrRef) {
if (typeof keyOrRef === "string") {
return this._capability(keyOrRef);
} else {
return this._capability(keyOrRef.id);
}
}
_capability(keyOrRef) {
return this.get("server.Capabilities")[keyOrRef];
}
setCapability(keyOrRef, value) {
if (typeof keyOrRef === "string") {
return this._setCapability(keyOrRef, value);
} else {
return this._setCapability(keyOrRef.id, value);
}
}
_setCapability(keyOrRef, value) {
this.get("server.Capabilities")[keyOrRef] = value;
}
respondWith(res, status) {
if (res || status) {
throw new Error("responses Not Implemented in Core");
}
return this;
}
};
function _using({
context,
p
}) {
return new Promise((resolve, reject) => {
if (typeof p === "undefined") {
p = null;
}
resolve(p);
}).then((value) => {
return Promise.resolve((() => {
setTimeout(() => {
if (context.dispose) {
context.dispose();
}
}, 0);
return value;
})());
}, (err) => {
console.error(err);
setTimeout(() => {
if (context.dispose) {
context.dispose();
}
}, 0);
throw err;
});
}
// src/iopa/factory-core.ts
var Factory = class {
_factory;
constructor(name = "IopaContext", size = 100, factory = () => new ContextCore()) {
this._factory = new FreeList(name, size, factory);
}
createContext(urlOrRequest, options) {
const optionsValid = _validOptions(options);
const context = this._factory.alloc().init();
context.dispose = this._dispose.bind(this, context);
context.set("iopa.Id", `#${_nextSequence()}`);
context.set("server.Timestamp", Date.now());
if (urlOrRequest) {
if (typeof urlOrRequest === "string") {
const url = urlOrRequest;
context.set("iopa.OriginalUrl", url);
context.set("iopa.Url", new URL(url));
} else {
const url = urlOrRequest.url;
context.set("iopa.OriginalUrl", url);
context.set("iopa.Url", new URL(url));
context.set("iopa.RawRequest", urlOrRequest);
context.set("iopa.RawRequestClone", urlOrRequest.clone());
}
}
context.createChild = this.createChildContext.bind(this, context);
mergeContext(context, optionsValid);
return context;
}
createChildContext(parentContext, urlPath, defaults) {
const defaultsValid = _validOptions(defaults);
const context = this.createContext();
context.set("server.Events", parentContext.get("server.Events"));
context.set("server.Capabilities", parentContext.get("server.Capabilities"));
context.app = parentContext.app;
const parentUrl = parentContext.get("iopa.Url") || new URL("https://schema.iopa.io");
const childUrl = `${parentUrl.protocol}//${parentUrl.host}/${urlPath ? urlPath.replace(/^\//, "") : parentUrl.pathname.replace(/^\//, "")}`;
context.set("iopa.OriginalUrl", childUrl);
context.set("iopa.Url", new URL(childUrl));
if (parentContext.get("iopa.RawRequest")) {
context.set("iopa.RawRequest", new Request(childUrl, {
headers: defaultsValid["iopa.Headers"] || parentContext.get("iopa.Headers"),
method: defaultsValid["iopa.Method"] || parentContext.get("iopa.Method"),
body: null
}));
context.set("iopa.RawRequestClone", new Request(childUrl, {
headers: defaultsValid["iopa.Headers"] || parentContext.get("iopa.Headers"),
method: defaultsValid["iopa.Method"] || parentContext.get("iopa.Method"),
body: null
}));
}
mergeContext(context, defaultsValid);
return context;
}
_dispose(context) {
if (context === null || context.get("server.AbortController") === null) {
return;
}
Object.keys(context).forEach((prop) => {
context[prop] = null;
});
this._factory.free(context);
}
};
function _validOptions(options) {
if (typeof options === "string" || options instanceof String) {
const result = {};
result["iopa.Method"] = options;
return result;
}
return options || {};
}
var maxSequence = 2 ** 16;
var _lastSequence = Math.floor(Math.random() * (maxSequence - 1));
function _nextSequence() {
_lastSequence += 1;
if (_lastSequence === maxSequence) {
_lastSequence = 1;
}
return _lastSequence.toString();
}
// src/iopa/context-edge-cookies.ts
var mins = ["m", "min", "mins", "minute", "minutes"];
var hrs = ["h", "hr", "hrs", "hour", "hours"];
var days = ["d", "day", "days"];
var weeks = ["w", "wk", "wks", "week", "weeks"];
var timeUnits = [mins, hrs, days, weeks];
function getSeconds(timeString) {
const [val, unit] = timeString.split(" ");
const time = Number.parseInt(val, 10);
if (Number.isNaN(time)) {
return 0;
}
const multipliers = [60, 3600, 86400, 604800];
for (let i = 0; i < timeUnits.length; i++) {
if (timeUnits[i].includes(unit)) {
return time * multipliers[i];
}
}
return 0;
}
function getMaxAge(age) {
return `Max-Age=${getSeconds(age)}`;
}
function getExpires(date) {
if (typeof date === "number") {
return `Expires=${new Date(date).toUTCString()}`;
}
return `Expires=${new Date(Date.now() + getSeconds(date) * 1e3).toUTCString()}`;
}
function mapOptionsToString({
options
}) {
const { expires, maxAge, domain, path, secure, httpOnly, sameSite } = options;
let opt = "";
if (expires) {
opt += ` ${getExpires(expires)};`;
}
if (maxAge) {
opt += ` ${getMaxAge(maxAge)};`;
}
if (domain) {
opt += ` Domain=${domain};`;
}
if (path) {
opt += ` Path=${path};`;
}
if (secure) {
opt += " Secure;";
}
if (httpOnly) {
opt += " HttpOnly;";
}
if (sameSite) {
opt += ` SameSite=${sameSite};`;
}
return opt;
}
var context_edge_cookies_default = {
set: (headers, name, value, options) => {
let cookie = `${name}=${value};`;
if (options) {
cookie += mapOptionsToString({ options });
}
headers.append("set-cookie", cookie);
},
clear: (headers, name, options) => {
let cookie = `${name}=; ${getExpires(0)};`;
if (options) {
cookie += mapOptionsToString({ options });
}
headers.append("set-cookie", cookie);
}
};
// src/iopa/context-edge.ts
var kRequest = Symbol("request");
var kRequestClone = Symbol("requestClone");
var kHeaders = Symbol("headers");
var kIsFinalized = Symbol("is_finalized");
var kResponse = Symbol("response");
var kStatusCode = Symbol("statusCode");
var ContextEdge = class extends ContextCore {
[kRequest];
[kHeaders];
notFound;
response;
cookies;
signedCookies;
secret;
init() {
super.init();
this.set("iopa.Headers", new Headers());
return this;
}
get body() {
return this[kRequest].body;
}
get headers() {
return this[kRequest] ? this[kRequest].headers : this[kHeaders];
}
get url() {
return this["iopa.OriginalUrl"];
}
get signal() {
return this[kRequest] ? this[kRequest].signal : this.get("server.AbortSignal");
}
get bodyUsed() {
return this[kRequest].bodyUsed;
}
get method() {
return this[kRequest].method;
}
get "iopa.Method"() {
return this[kRequest].method;
}
set "iopa.Method"(value) {
}
get "iopa.Headers"() {
return this[kRequest] ? this[kRequest].headers : this[kHeaders];
}
set "iopa.Headers"(headers) {
this[kHeaders] = headers;
}
get "iopa.RawRequest"() {
return this[kRequest];
}
set "iopa.RawRequest"(request) {
this[kRequest] = request;
}
get "iopa.RawRequestClone"() {
return this[kRequestClone];
}
set "iopa.RawRequestClone"(request) {
this[kRequestClone] = request;
}
param(key) {
const params = this.get("iopa.Params") || {};
if (params) {
if (key) {
return params[key];
} else {
return params;
}
}
return void 0;
}
query(key) {
const params = Object.fromEntries(this.get("iopa.Url").searchParams.entries());
if (params) {
if (key) {
return params[key];
} else {
return params;
}
}
return void 0;
}
async blob() {
return this[kRequest].blob();
}
async arrayBuffer() {
return this[kRequest].arrayBuffer();
}
async text() {
return this[kRequest].text();
}
async json() {
return this[kRequest].json();
}
async formData() {
return this[kRequest].formData();
}
redirect(location, code) {
if (typeof location !== "string") {
throw new TypeError("location must be a string!");
}
if (!isAbsoluteURL(location)) {
const url = this.get("iopa.Url");
url.pathname = location;
location = url.toString();
}
this.response.status(code || 302).headers.set("location", location);
return this;
}
respondWith(res, options) {
if (res instanceof Error || !this.response[kIsFinalized]) {
this.response.respondWith(res, options);
}
return this;
}
};
var ContextReply = class extends IopaMap {
[kHeaders];
[kStatusCode];
"iopa.Version";
[kResponse];
[kIsFinalized] = false;
get "iopa.StatusCode"() {
return this[kStatusCode] || 200;
}
set "iopa.StatusCode"(value) {
this[kStatusCode] = value;
}
get headers() {
return this[kHeaders];
}
get redirected() {
const status = this.get("iopa.StatusCode");
return status === 302 || status === 301;
}
get ok() {
const status = this.get("iopa.StatusCode");
return status < 300;
}
get statusText() {
return this.get("iopa.StatusText");
}
get "iopa.Headers"() {
return this[kHeaders];
}
set "iopa.Headers"(headers) {
this[kHeaders] = headers;
}
get "iopa.IsFinalized"() {
return this[kIsFinalized];
}
get "iopa.RawResponse"() {
if (this[kIsFinalized]) {
return this[kResponse];
} else {
return new Response(this.get("iopa.Body"), {
headers: this.get("iopa.Headers"),
status: this.get("iopa.StatusCode"),
statusText: this.get("iopa.StatusText") || getStatusText(this.get("iopa.StatusCode")) || void 0
});
}
}
get "iopa.RawResponseClone"() {
if (this[kIsFinalized]) {
return Promise.resolve(this[kResponse]).then((x) => x.clone());
} else {
return new Response(this.get("iopa.Body"), {
headers: this.get("iopa.Headers"),
status: this.get("iopa.StatusCode"),
statusText: this.get("iopa.StatusText") || void 0
});
}
}
init() {
this.set("iopa.Version", VERSION);
this[kHeaders] = new Headers();
this[kIsFinalized] = false;
return this;
}
status(code) {
this.set("iopa.StatusCode", code);
return this;
}
header(field, value) {
this.get("iopa.Headers").set(field, value);
return this;
}
cookie(name, value, options) {
context_edge_cookies_default.set(this.get("iopa.Headers"), name, value, options);
return this;
}
clearCookie(name, options) {
context_edge_cookies_default.clear(this.get("iopa.Headers"), name, options);
return this;
}
arrayBuffer(data) {
this.set("iopa.Body", data);
return this;
}
formData(data) {
this.set("iopa.Body", data);
return this;
}
blob(data) {
this.set("iopa.Body", data);
return this;
}
json(data) {
this.header("Content-Type", "application/json; charset=UTF-8");
this.set("iopa.Body", JSON.stringify(data));
return this;
}
text(data) {
this.header("Content-Type", "text/html; charset=UTF-8");
this.set("iopa.Body", data);
return this;
}
html(data) {
this.header("Content-Type", "text/plain; charset=UTF-8");
this.set("iopa.Body", data);
return this;
}
respondWith(res, options) {
if (this[kIsFinalized]) {
return this;
}
let status;
if (options || options === 0) {
if (typeof options === "number") {
status = options;
} else {
status = options.status;
}
}
if (options && options.headers) {
Object.entries(options.headers).forEach(([key, value]) => this[kHeaders].set(key, value));
}
if (status) {
this.status(status);
}
if (res === void 0 || res === null) {
this[kResponse] = this.get("iopa.RawResponse");
this[kIsFinalized] = true;
} else if (res instanceof Response) {
this[kResponse] = res;
this[kIsFinalized] = true;
} else if (res instanceof Error) {
this.status(res.statusCode || status || 500).text(`${res.statusCode || status || 500} ERROR ${res.name} ${res.message}`);
} else {
if (typeof res === "number" && !status) {
this.status(res);
} else if (typeof res === "string" || res instanceof String) {
this.text(res).status(status || 200);
} else if (typeof res === "boolean") {
if (res) {
this.text(`true`).status(status || 200);
} else {
this.text(`false`).status(status || 200);
}
} else if ("iopa.Version" in res) {
} else {
this.json(res).status(status || 200);
}
this[kResponse] = this.get("iopa.RawResponse");
this[kIsFinalized] = true;
}
return this;
}
};
// src/iopa/factory-edge.ts
var FactoryEdge = class extends Factory {
_factoryResponse;
constructor(name = "IopaContext", size = 100, factory = () => new ContextEdge()) {
super(name, size, factory);
this._factoryResponse = new FreeList("IopaReply", size, () => new ContextReply());
}
createContext(urlOrRequest, options) {
const context = super.createContext(urlOrRequest, options);
const response = this._factoryResponse.alloc().init();
context.response = response;
return context;
}
_dispose(context) {
if (context === null || context.get("server.AbortController") === null) {
return;
}
if (context.response) {
const { response } = context;
Object.keys(response).forEach((prop) => {
response[prop] = null;
});
this._factoryResponse.free(response);
}
Object.keys(context).forEach((prop) => {
context[prop] = null;
});
this._factory.free(context);
}
};
// src/appBuilder/middleware.ts
function Middleware(app, middleware, action = "invoke") {
let args;
if (typeof middleware === "function") {
switch (middleware.length) {
case 0:
middleware.call(app);
return (context, next) => {
return middleware.invoke.call(context, next);
};
break;
case 1:
args = _getParamNames(middleware);
if (arrayEqual(args, ["next"])) {
return (context, next) => {
return middleware.call(context, next);
};
}
const mw = new middleware(app);
return mw.invoke.bind(mw);
case 2:
args = _getParamNames(middleware);
if (arrayEqual(args, ["req", "res"])) {
throw new Error("must require 'iopa-connect' to use Connect/Express style middleware");
} else {
return middleware;
}
case 3:
throw new Error("must require 'iopa-connect' to use Connect/Express style middleware");
case 4:
throw new Error("must require 'iopa-connect' to use Connect/Express style middleware");
default:
throw new Error("unknown middleware");
}
} else {
console.error("middleware must be a function");
throw new Error("middleware must be called on a function");
}
}
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
function _getParamNames(func) {
const fnStr = func.toString().replace(STRIP_COMMENTS, "");
let result = fnStr.slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")")).match(/([^\s,]+)/g);
if (result === null) {
result = [];
}
return result;
}
function arrayEqual(array1, array2) {
if (!array2) {
return false;
}
if (array1.length !== array2.length) {
return false;
}
for (let i = 0, l = array1.length; i < l; i++) {
if (array1[i] instanceof Array && array2[i] instanceof Array) {
if (!array1[i].compare(array2[i])) {
return false;
}
} else if (array1[i] !== array2[i]) {
return false;
}
}
return true;
}
// src/appBuilder/appBuilder.ts
var AppBuilder = class {
properties;
_middleware;
middlewareProxy = Middleware;
_factory;
_abortController;
constructor(appProperties, appOptions = {
"server.Version": VERSION,
"server.Base": "core"
}) {
this._abortController = new AbortController();
process.on("exit", this._abort);
process.on("SIGINT", this._abort);
process.on("uncaughtException", this._exception);
this._abortController.signal.addEventListener("abort", this._dispose);
const defaults = {
"iopa.Id": guid(),
"server.Capabilities": {
[URN_APP]: appOptions
},
"server.Events": new ExtendableEventTarget(),
"server.Logger": logging_default,
"server.NotFound": DefaultApp,
"server.ErrorHandler": ErrorHandler,
"server.IsBuilt": false,
"server.Pipeline": void 0,
"server.AbortController": this._abortController,
"server.AbortSignal": this._abortController.signal
};
if (typeof appProperties === "string") {
appProperties = { "iopa.Id": appProperties };
}
if (appProperties) {
Object.entries(appProperties).forEach(([key, value]) => {
if (key === "server.Capabilities") {
const capabilities = defaults["server.Capabilities"];
Object.entries(value).forEach(([key2, value2]) => {
capabilities[key2] = value2;
});
} else {
defaults[key] = value;
}
});
}
this._factory = defaults["server.Factory"] ?? appOptions["server.Base"] === "request" ? new FactoryEdge() : new Factory();
this.properties = new IopaMap(defaults);
this._middleware = { invoke: [], dispatch: [] };
}
_dispose = () => {
this._abortController.signal.removeEventListener("abort", this._dispose);
process.off("exit", this._abort);
process.off("SIGINT", this._abort);
process.off("uncaughtException", this._exception);
};
_abort = () => {
this._abortController.abort();
};
_exception = (e) => {
console.log("Uncaught Exception...");
console.log(e.stack);
this._abortController.abort();
process.exit(99);
};
capability(keyOrRef) {
if (typeof keyOrRef === "string") {
return this._capability(keyOrRef);
} else {
return this._capability(keyOrRef.id);
}
}
_capability(keyOrRef) {
return this.properties.get("server.Capabilities")[keyOrRef];
}
setCapability(keyOrRef, value) {
if (typeof keyOrRef === "string") {
return this._setCapability(keyOrRef, value);
} else {
return this._setCapability(keyOrRef.id, value);
}
}
_setCapability(keyOrRef, value) {
this.properties.get("server.Capabilities")[keyOrRef] = value;
}
createContext(urlOrRequest, options) {
return this._factory.createContext(urlOrRequest, options);
}
fork(when) {
const subApp = new AppBuilder(this.properties.toJSON());
this.use(async function forkFunction(context, next) {
if (!subApp.properties.get("server.IsBuilt")) {
subApp.build();
}
if (when(context)) {
await subApp.invoke(context);
return Promise.resolve(null);
}
return next();
}, "forkFuncton");
return subApp;
}
use(arg0, arg1, options) {
let id, mw, method;
if (typeof arg0 === "object" && "default" in arg0) {
arg0 = arg0["default"];
} else if (typeof arg1 === "object" && "default" in arg1) {
arg1 = arg1["default"];
}
if (typeof arg0 === "function" && typeof arg1 === "string") {
id = arg1;
mw = arg0;
method = "invoke";
} else if (typeof arg0 === "function" && !arg1) {
id = arg0.name || arg0.toString().split(/\r?\n/)[0];
mw = arg0;
method = "invoke";
} else if (arg0 === void 0) {
throw new Error(`app.use called with undefined / empty middleware for ${mw}`);
} else {
id = arg1.name || arg1.toString().split(/\r?\n/)[0];
method = arg0;
mw = arg1;
}
if (!this._middleware[method]) {
throw new Error(`Unknown AppBuilder Category ${JSON.stringify(method, null, 2)} for ${id}`);
}
const params = _getParams(mw);
if (params === "app" || mw.length === 1) {
const Mw = mw;
let mwInstance;
try {
mwInstance = new Mw(this, options);
} catch (ex) {
mwInstance = Mw(this, options) || {};
}
if (typeof mwInstance.invoke === "function") {
const fn = mwInstance.invoke.bind(mwInstance);
fn.id = id;
this._middleware.invoke.push(fn);
}
if (typeof mwInstance.dispatch === "function") {
const fn = mwInstance.dispatch.bind(mwInstance);
fn.id = id;
this._middleware.dispatch.push(fn);
}
} else {
if (options) {
throw new Error(`Cannot instantiate AppFunc ${id} with options, use a class constructor instead`);
}
const fn = this.middlewareProxy(this, mw);
fn.id = id;
this._middleware[method].push(fn);
}
return this;
}
dispose() {
}
build() {
const middleware = this._middleware.invoke.concat(this.properties.get("server.NotFound"));
const pipeline = this._compose(middleware);
if (this._middleware.dispatch.length > 0) {
pipeline.dispatch = this._compose(this._middleware.dispatch.reverse());
} else {
pipeline.dispatch = (context) => {
return Promise.resolve();
};
}
pipeline.properties = this.properties;
this.properties.set("server.IsBuilt", true);
this.properties.set("server.Pipeline", pipeline);
return pipeline;
}
_buildDynamic(handler) {
const middleware = this._middleware.invoke.concat(handler);
return this._compose(middleware);
}
dispatch(context) {
return this.properties.get("server.Pipeline").dispatch.call(this, context);
}
invoke(context) {
context.log = this.properties.get("server.Logger").child({ tid: context.get("iopa.Id") });
if (!this.properties.get("server.IsBuilt")) {
this.build();
}
return this.properties.get("server.Pipeline").call(this, context);
}
childInvoke(context, handler, id) {
handler.id = id || "childInvoke";
const pipeline = this._buildDynamic(handler);
context.log = this.properties.get("server.Logger").child({ tid: context.get("iopa.Id") });
return pipeline.call(this, context);
}
_compose(middleware) {
let i;
let next;
let curr;
i = middleware.length;
next = () => {
return Promise.resolve();
};
while (i--) {
curr = middleware[i];
if (!curr) {
console.error(middleware, i);
throw new Error("Missing middleware");
}
next = ((fn, prev, context) => {
context.set("server.CurrentMiddleware", fn.id);
const _next = () => {
context.dispatchEvent(new TraceEvent("trace-next", {
label: fn.id
}));
return prev.call(this, context).then(() => {
context.dispatchEvent(new TraceEvent("trace-next-resume", {
label: fn.id
}));
});
};
_next.invoke = prev;
context.dispatchEvent(new TraceEvent("trace-start", {
label: fn.id
}));
const _oldLogger = context.log;
context.log = context.log.child({
middleware: fn.id
});
return Promise.resolve(fn.call(this, context, _next)).then((res) => {
context.log = _oldLogger;
if (res || res === false || res === 0 || res === "") {
;
context.respondWith(res);
}
context.dispatchEvent(new TraceEvent("trace-end", {
label: fn.id
}));
});
}).bind(this, curr, next);
}
const rootPipeline = next;
return (context) => {
const capabilities = this.properties.get("server.Capabilities");
context.set("server.Capabilities", capabilities);
context.set("server.Events", this.properties.get("server.Events"));
context.app = this;
return rootPipeline.call(this, context);
};
}
usePlugin(plugin) {
throw new Error("Not Implemented");
}
};
var RouterApp = class extends AppBuilder {
head;
post;
get;
options;
put;
delete;
patch;
all;
config;
constructor(appProperties = void 0, appOptions = {}) {
super(appProperties, {
"server.Base": "request",
...appOptions
});
}
registerFeatureFlag(flagOptions) {
throw new Error("Method not implemented.");
}
};
function DefaultApp(context) {
return Promise.resolve();
}
DefaultApp.id = "DefaultApp";
function ErrorHandler(ex, context) {
throw ex;
}
ErrorHandler.id = "ErrorHandler";
var STRIP_COMMENTS2 = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
function _getParams(func) {
const fnStr = func.toString().replace(STRIP_COMMENTS2, "");
let result = fnStr.slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")")).match(/([^\s,]+)/g);
if (result === null) {
result = [];
}
return result.join();
}
// src/index.ts
var iopaPrototype = {
cloneKeyBehaviors
};
var util = {
shallow: shallow_exports,
url: url_exports,
status: status_exports,
prototype: iopaPrototype,
Disposable
};
export {
AppBuilder as App,
AppRef,
ContextCore,
ContextEdge,
ContextReply,
IopaMap,
RouterApp,
TraceEvent,
URN_APP,
VERSION,
consoleLogger,
iopaPrototype,
util
};