@tymber/common 0.0.1-alpha.0 → 0.1.0

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.
Files changed (129) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +46 -0
  3. package/dist/App.d.ts +17 -0
  4. package/dist/App.js +236 -0
  5. package/dist/Component.d.ts +16 -0
  6. package/dist/Component.js +116 -0
  7. package/dist/ConfigService.d.ts +31 -0
  8. package/dist/ConfigService.js +75 -0
  9. package/dist/Context.d.ts +41 -0
  10. package/dist/Context.js +10 -0
  11. package/dist/DB.d.ts +15 -0
  12. package/dist/DB.js +7 -0
  13. package/dist/Endpoint.d.ts +21 -0
  14. package/dist/Endpoint.js +87 -0
  15. package/dist/EventEmitter.d.ts +9 -0
  16. package/dist/EventEmitter.js +21 -0
  17. package/dist/Handler.d.ts +8 -0
  18. package/dist/Handler.js +8 -0
  19. package/dist/HttpContext.d.ts +26 -0
  20. package/dist/HttpContext.js +11 -0
  21. package/dist/I18nService.d.ts +18 -0
  22. package/dist/I18nService.js +72 -0
  23. package/dist/Middleware.d.ts +6 -0
  24. package/dist/Middleware.js +4 -0
  25. package/dist/Module.d.ts +47 -0
  26. package/dist/Module.js +12 -0
  27. package/dist/PubSubService.d.ts +20 -0
  28. package/dist/PubSubService.js +60 -0
  29. package/dist/Repository.d.ts +29 -0
  30. package/dist/Repository.js +110 -0
  31. package/dist/Router.d.ts +10 -0
  32. package/dist/Router.js +53 -0
  33. package/dist/TemplateService.d.ts +22 -0
  34. package/dist/TemplateService.js +66 -0
  35. package/dist/View.d.ts +17 -0
  36. package/dist/View.js +48 -0
  37. package/dist/ViewRenderer.d.ts +16 -0
  38. package/dist/ViewRenderer.js +59 -0
  39. package/dist/contrib/accept-language-parser.d.ts +9 -0
  40. package/dist/contrib/accept-language-parser.js +73 -0
  41. package/dist/contrib/cookie.d.ts +33 -0
  42. package/dist/contrib/cookie.js +207 -0
  43. package/dist/contrib/template.d.ts +1 -0
  44. package/dist/contrib/template.js +107 -0
  45. package/dist/index.d.ts +32 -0
  46. package/dist/index.js +32 -0
  47. package/dist/utils/ajv.d.ts +2 -0
  48. package/dist/utils/ajv.js +10 -0
  49. package/dist/utils/camelToSnakeCase.d.ts +1 -0
  50. package/dist/utils/camelToSnakeCase.js +3 -0
  51. package/dist/utils/computeBaseUrl.d.ts +1 -0
  52. package/dist/utils/computeBaseUrl.js +37 -0
  53. package/dist/utils/computeContentType.d.ts +1 -0
  54. package/dist/utils/computeContentType.js +17 -0
  55. package/dist/utils/createDebug.d.ts +1 -0
  56. package/dist/utils/createDebug.js +4 -0
  57. package/dist/utils/createTestApp.d.ts +8 -0
  58. package/dist/utils/createTestApp.js +57 -0
  59. package/dist/utils/escapeValue.d.ts +1 -0
  60. package/dist/utils/escapeValue.js +3 -0
  61. package/dist/utils/fs.d.ts +6 -0
  62. package/dist/utils/fs.js +13 -0
  63. package/dist/utils/isAdmin.d.ts +2 -0
  64. package/dist/utils/isAdmin.js +4 -0
  65. package/dist/utils/isProduction.d.ts +1 -0
  66. package/dist/utils/isProduction.js +1 -0
  67. package/dist/utils/loadModules.d.ts +3 -0
  68. package/dist/utils/loadModules.js +83 -0
  69. package/dist/utils/randomId.d.ts +1 -0
  70. package/dist/utils/randomId.js +4 -0
  71. package/dist/utils/randomUUID.d.ts +1 -0
  72. package/dist/utils/randomUUID.js +4 -0
  73. package/dist/utils/runMigrations.d.ts +3 -0
  74. package/dist/utils/runMigrations.js +85 -0
  75. package/dist/utils/snakeToCamelCase.d.ts +1 -0
  76. package/dist/utils/snakeToCamelCase.js +3 -0
  77. package/dist/utils/sortBy.d.ts +1 -0
  78. package/dist/utils/sortBy.js +8 -0
  79. package/dist/utils/sql.d.ts +120 -0
  80. package/dist/utils/sql.js +433 -0
  81. package/dist/utils/toNodeHandler.d.ts +2 -0
  82. package/dist/utils/toNodeHandler.js +91 -0
  83. package/dist/utils/types.d.ts +3 -0
  84. package/dist/utils/types.js +1 -0
  85. package/dist/utils/waitFor.d.ts +1 -0
  86. package/dist/utils/waitFor.js +5 -0
  87. package/package.json +33 -2
  88. package/src/App.ts +319 -0
  89. package/src/Component.ts +166 -0
  90. package/src/ConfigService.ts +121 -0
  91. package/src/Context.ts +60 -0
  92. package/src/DB.ts +28 -0
  93. package/src/Endpoint.ts +118 -0
  94. package/src/EventEmitter.ts +32 -0
  95. package/src/Handler.ts +14 -0
  96. package/src/HttpContext.ts +35 -0
  97. package/src/I18nService.ts +96 -0
  98. package/src/Middleware.ts +10 -0
  99. package/src/Module.ts +60 -0
  100. package/src/PubSubService.ts +77 -0
  101. package/src/Repository.ts +158 -0
  102. package/src/Router.ts +77 -0
  103. package/src/TemplateService.ts +97 -0
  104. package/src/View.ts +60 -0
  105. package/src/ViewRenderer.ts +71 -0
  106. package/src/contrib/accept-language-parser.ts +94 -0
  107. package/src/contrib/cookie.ts +256 -0
  108. package/src/contrib/template.ts +134 -0
  109. package/src/index.ts +54 -0
  110. package/src/utils/ajv.ts +13 -0
  111. package/src/utils/camelToSnakeCase.ts +3 -0
  112. package/src/utils/computeBaseUrl.ts +46 -0
  113. package/src/utils/computeContentType.ts +17 -0
  114. package/src/utils/createDebug.ts +5 -0
  115. package/src/utils/createTestApp.ts +84 -0
  116. package/src/utils/escapeValue.ts +3 -0
  117. package/src/utils/fs.ts +15 -0
  118. package/src/utils/isAdmin.ts +5 -0
  119. package/src/utils/isProduction.ts +2 -0
  120. package/src/utils/loadModules.ts +105 -0
  121. package/src/utils/randomId.ts +5 -0
  122. package/src/utils/randomUUID.ts +5 -0
  123. package/src/utils/runMigrations.ts +122 -0
  124. package/src/utils/snakeToCamelCase.ts +3 -0
  125. package/src/utils/sortBy.ts +8 -0
  126. package/src/utils/sql.ts +553 -0
  127. package/src/utils/toNodeHandler.ts +121 -0
  128. package/src/utils/types.ts +1 -0
  129. package/src/utils/waitFor.ts +5 -0
@@ -0,0 +1,66 @@
1
+ import { compileTemplate } from "./contrib/template.js";
2
+ import { ModuleDefinitions } from "./Module.js";
3
+ import { createDebug } from "./utils/createDebug.js";
4
+ import { Component, INJECT } from "./Component.js";
5
+ import { FS } from "./utils/fs.js";
6
+ import { isProduction } from "./utils/isProduction.js";
7
+ const debug = createDebug("TemplateService");
8
+ export class TemplateService extends Component {
9
+ }
10
+ export class FileBasedTemplateService extends TemplateService {
11
+ modules;
12
+ static [INJECT] = [ModuleDefinitions];
13
+ templates = new Map();
14
+ constructor(modules) {
15
+ super();
16
+ this.modules = modules;
17
+ this.modules = modules;
18
+ }
19
+ init() {
20
+ return this.loadTemplates();
21
+ }
22
+ async loadTemplates() {
23
+ for (const module of this.modules.modules) {
24
+ if (!module.assetsDir) {
25
+ return;
26
+ }
27
+ try {
28
+ for (const filename of await FS.readDirRecursively(FS.join(module.assetsDir, "templates"))) {
29
+ const fileExtension = filename.slice(filename.lastIndexOf("."));
30
+ if (fileExtension === this.fileExtension) {
31
+ const viewName = filename.slice(0, filename.lastIndexOf("."));
32
+ debug("adding template %s", viewName);
33
+ if (this.templates.has(viewName)) {
34
+ debug("overriding existing template %s", viewName);
35
+ }
36
+ this.templates.set(viewName, FS.join(module.assetsDir, "templates", filename));
37
+ }
38
+ }
39
+ }
40
+ catch (e) { }
41
+ }
42
+ }
43
+ canRender(templateName) {
44
+ return this.templates.has(templateName);
45
+ }
46
+ }
47
+ export class BaseTemplateService extends FileBasedTemplateService {
48
+ fileExtension = ".html";
49
+ // TODO use a LRU cache
50
+ compiledTemplates = new Map();
51
+ render(templateName, data) {
52
+ return this.getTemplate(templateName).then((template) => template(data));
53
+ }
54
+ async getTemplate(templateName) {
55
+ if (isProduction && this.compiledTemplates.has(templateName)) {
56
+ return this.compiledTemplates.get(templateName);
57
+ }
58
+ const absolutePath = this.templates.get(templateName);
59
+ const content = await FS.readFile(absolutePath);
60
+ const compiledTemplate = compileTemplate(content);
61
+ if (isProduction) {
62
+ this.compiledTemplates.set(templateName, compiledTemplate);
63
+ }
64
+ return compiledTemplate;
65
+ }
66
+ }
package/dist/View.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { type HttpContext } from "./HttpContext.js";
2
+ import { Handler } from "./Handler.js";
3
+ export declare abstract class BaseView extends Handler {
4
+ protected pathParamsSchema: unknown;
5
+ protected querySchema: unknown;
6
+ private validatePathParams?;
7
+ private validateQuery?;
8
+ doHandle(ctx: HttpContext): Response | Promise<Response>;
9
+ }
10
+ export declare abstract class View extends BaseView {
11
+ private _viewBrand;
12
+ doHandle(ctx: HttpContext): Response | Promise<Response>;
13
+ }
14
+ export declare abstract class AdminView extends BaseView {
15
+ private _adminViewBrand;
16
+ doHandle(ctx: HttpContext): Response | Promise<Response>;
17
+ }
package/dist/View.js ADDED
@@ -0,0 +1,48 @@
1
+ import {} from "ajv";
2
+ import {} from "./HttpContext.js";
3
+ import { Handler } from "./Handler.js";
4
+ import { AJV_INSTANCE } from "./utils/ajv.js";
5
+ export class BaseView extends Handler {
6
+ pathParamsSchema; // JSONSchemaType<Params>;
7
+ querySchema; // JSONSchemaType<Query>;
8
+ validatePathParams;
9
+ validateQuery;
10
+ doHandle(ctx) {
11
+ const { pathParams, query } = ctx;
12
+ if (this.pathParamsSchema && !this.validatePathParams) {
13
+ this.validatePathParams = AJV_INSTANCE.compile(this.pathParamsSchema);
14
+ }
15
+ if (this.validatePathParams) {
16
+ this.validatePathParams(pathParams);
17
+ }
18
+ if (this.querySchema && !this.validateQuery) {
19
+ this.validateQuery = AJV_INSTANCE.compile(this.querySchema);
20
+ }
21
+ if (this.validateQuery) {
22
+ this.validateQuery(query);
23
+ }
24
+ return this.handle(ctx);
25
+ }
26
+ }
27
+ export class View extends BaseView {
28
+ _viewBrand; // nominal typing
29
+ doHandle(ctx) {
30
+ if (!this.allowAnonymous && !ctx.user) {
31
+ return ctx.redirect("/login");
32
+ }
33
+ if (!this.hasPermission(ctx)) {
34
+ return ctx.redirect("/forbidden");
35
+ }
36
+ return super.doHandle(ctx);
37
+ }
38
+ }
39
+ export class AdminView extends BaseView {
40
+ _adminViewBrand; // nominal typing
41
+ doHandle(ctx) {
42
+ if (!this.allowAnonymous && !ctx.admin) {
43
+ return ctx.redirect("/admin/login");
44
+ }
45
+ // note: no hasPermission() check for admins
46
+ return super.doHandle(ctx);
47
+ }
48
+ }
@@ -0,0 +1,16 @@
1
+ import { Component, INJECT } from "./Component.js";
2
+ import { BaseTemplateService, TemplateService } from "./TemplateService.js";
3
+ import { I18nService } from "./I18nService.js";
4
+ import { ModuleDefinitions } from "./Module.js";
5
+ import type { HttpContext } from "./HttpContext.js";
6
+ export declare class ViewRenderer extends Component {
7
+ private readonly i18nService;
8
+ private readonly templateService;
9
+ private readonly customTemplateService;
10
+ private readonly modules;
11
+ static [INJECT]: (typeof ModuleDefinitions | typeof TemplateService | typeof BaseTemplateService | typeof I18nService)[];
12
+ constructor(i18nService: I18nService, templateService: BaseTemplateService, customTemplateService: TemplateService, modules: ModuleDefinitions);
13
+ computeLocale(req: Request): import("./contrib/accept-language-parser.js").Locale;
14
+ render(ctx: HttpContext, view: string | string[], data?: Record<string, any>): Promise<import("undici-types").Response>;
15
+ private renderTemplate;
16
+ }
@@ -0,0 +1,59 @@
1
+ import { Component, INJECT } from "./Component.js";
2
+ import { BaseTemplateService, TemplateService } from "./TemplateService.js";
3
+ import { I18nService } from "./I18nService.js";
4
+ import { pick } from "./contrib/accept-language-parser.js";
5
+ import { ModuleDefinitions } from "./Module.js";
6
+ import { isProduction } from "./utils/isProduction.js";
7
+ export class ViewRenderer extends Component {
8
+ i18nService;
9
+ templateService;
10
+ customTemplateService;
11
+ modules;
12
+ static [INJECT] = [
13
+ I18nService,
14
+ BaseTemplateService,
15
+ TemplateService,
16
+ ModuleDefinitions,
17
+ ];
18
+ constructor(i18nService, templateService, customTemplateService, modules) {
19
+ super();
20
+ this.i18nService = i18nService;
21
+ this.templateService = templateService;
22
+ this.customTemplateService = customTemplateService;
23
+ this.modules = modules;
24
+ }
25
+ computeLocale(req) {
26
+ return pick(this.i18nService.availableLocales(), req.headers.get("accept-language") || "");
27
+ }
28
+ async render(ctx, view, data = {}) {
29
+ const templates = Array.isArray(view) ? view.reverse() : [view];
30
+ data.TITLE = "Tymber";
31
+ data.CTX = ctx;
32
+ data.CTX.app = data.CTX.app || {};
33
+ data.CTX.app.isProduction = isProduction;
34
+ data.CTX.app.modules = this.modules.modules;
35
+ data.$t = (key, ...args) => {
36
+ return this.i18nService.translate(ctx, ctx.locale, key, ...args);
37
+ };
38
+ for (const template of templates) {
39
+ data.VIEW = await this.renderTemplate(template, data);
40
+ }
41
+ return new Response(data.VIEW, {
42
+ headers: {
43
+ "content-type": "text/html",
44
+ "cache-control": "no-cache",
45
+ },
46
+ });
47
+ }
48
+ renderTemplate(templateName, data) {
49
+ if (this.customTemplateService.canRender(templateName)) {
50
+ return this.customTemplateService.render(templateName, data);
51
+ }
52
+ else if (this.templateService.canRender(templateName)) {
53
+ return this.templateService.render(templateName, data);
54
+ }
55
+ else {
56
+ throw new Error(`template ${templateName} not found`);
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,9 @@
1
+ import { type Brand } from "../utils/types.js";
2
+ export type Locale = Brand<string, "Locale">;
3
+ export declare function parse(al: string): ({
4
+ code: string;
5
+ script: string | null;
6
+ region: string;
7
+ quality: number;
8
+ } | undefined)[];
9
+ export declare function pick(supportedLanguages: string[], acceptLanguage: any, options?: any): Locale;
@@ -0,0 +1,73 @@
1
+ // from https://github.com/opentable/accept-language-parser
2
+ import {} from "../utils/types.js";
3
+ var regex = /((([a-zA-Z]+(-[a-zA-Z0-9]+){0,2})|\*)(;q=[0-1](\.[0-9]+)?)?)*/g;
4
+ var isString = function (s) {
5
+ return typeof s === "string";
6
+ };
7
+ export function parse(al) {
8
+ var strings = (al || "").match(regex);
9
+ return strings
10
+ .map(function (m) {
11
+ if (!m) {
12
+ return;
13
+ }
14
+ var bits = m.split(";");
15
+ var ietf = bits[0].split("-");
16
+ var hasScript = ietf.length === 3;
17
+ return {
18
+ code: ietf[0],
19
+ script: hasScript ? ietf[1] : null,
20
+ region: hasScript ? ietf[2] : ietf[1],
21
+ quality: bits[1] ? parseFloat(bits[1].split("=")[1]) : 1.0,
22
+ };
23
+ })
24
+ .filter(function (r) {
25
+ return r;
26
+ })
27
+ .sort(function (a, b) {
28
+ return b.quality - a.quality;
29
+ });
30
+ }
31
+ export function pick(supportedLanguages, acceptLanguage, options) {
32
+ options = options || {};
33
+ // if (!supportedLanguages || !supportedLanguages.length || !acceptLanguage) {
34
+ // return null;
35
+ // }
36
+ if (!acceptLanguage) {
37
+ return supportedLanguages[0]; // pick first as default
38
+ }
39
+ if (isString(acceptLanguage)) {
40
+ acceptLanguage = parse(acceptLanguage);
41
+ }
42
+ var supported = supportedLanguages.map(function (support) {
43
+ var bits = support.split("-");
44
+ var hasScript = bits.length === 3;
45
+ return {
46
+ code: bits[0],
47
+ script: hasScript ? bits[1] : null,
48
+ region: hasScript ? bits[2] : bits[1],
49
+ };
50
+ });
51
+ for (var i = 0; i < acceptLanguage.length; i++) {
52
+ var lang = acceptLanguage[i];
53
+ var langCode = lang.code.toLowerCase();
54
+ var langRegion = lang.region ? lang.region.toLowerCase() : lang.region;
55
+ var langScript = lang.script ? lang.script.toLowerCase() : lang.script;
56
+ for (var j = 0; j < supported.length; j++) {
57
+ var supportedCode = supported[j].code.toLowerCase();
58
+ var supportedScript = supported[j].script
59
+ ? supported[j].script.toLowerCase()
60
+ : supported[j].script;
61
+ var supportedRegion = supported[j].region
62
+ ? supported[j].region.toLowerCase()
63
+ : supported[j].region;
64
+ if (langCode === supportedCode &&
65
+ (options.loose || !langScript || langScript === supportedScript) &&
66
+ (options.loose || !langRegion || langRegion === supportedRegion)) {
67
+ return supportedLanguages[j];
68
+ }
69
+ }
70
+ }
71
+ // return null;
72
+ return supportedLanguages[0]; // pick first as default
73
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Module variables.
3
+ * @private
4
+ */
5
+ /**
6
+ * Parse a cookie header.
7
+ *
8
+ * Parse the given cookie header string into an object
9
+ * The object has the various cookies as keys(names) => values
10
+ *
11
+ * @param {string} str
12
+ * @param {object} [options]
13
+ * @return {object}
14
+ * @public
15
+ */
16
+ declare function parse(str: string, options?: any): Record<string, string>;
17
+ /**
18
+ * Serialize data into a cookie header.
19
+ *
20
+ * Serialize the a name value pair into a cookie string suitable for
21
+ * http headers. An optional options object specified cookie parameters.
22
+ *
23
+ * serialize('foo', 'bar', { httpOnly: true })
24
+ * => "foo=bar; httpOnly"
25
+ *
26
+ * @param {string} name
27
+ * @param {string} val
28
+ * @param {object} [options]
29
+ * @return {string}
30
+ * @public
31
+ */
32
+ declare function serialize(name: string, val: string, options: any): string;
33
+ export { parse as parseCookieHeader, serialize as createCookie };
@@ -0,0 +1,207 @@
1
+ // from https://www.npmjs.com/package/cookie
2
+ /**
3
+ * Module variables.
4
+ * @private
5
+ */
6
+ var __toString = Object.prototype.toString;
7
+ /**
8
+ * RegExp to match field-content in RFC 7230 sec 3.2
9
+ *
10
+ * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
11
+ * field-vchar = VCHAR / obs-text
12
+ * obs-text = %x80-FF
13
+ */
14
+ var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
15
+ /**
16
+ * Parse a cookie header.
17
+ *
18
+ * Parse the given cookie header string into an object
19
+ * The object has the various cookies as keys(names) => values
20
+ *
21
+ * @param {string} str
22
+ * @param {object} [options]
23
+ * @return {object}
24
+ * @public
25
+ */
26
+ function parse(str, options) {
27
+ if (typeof str !== "string") {
28
+ throw new TypeError("argument str must be a string");
29
+ }
30
+ var obj = {};
31
+ var opt = options || {};
32
+ var dec = opt.decode || decode;
33
+ var index = 0;
34
+ while (index < str.length) {
35
+ var eqIdx = str.indexOf("=", index);
36
+ // no more cookie pairs
37
+ if (eqIdx === -1) {
38
+ break;
39
+ }
40
+ var endIdx = str.indexOf(";", index);
41
+ if (endIdx === -1) {
42
+ endIdx = str.length;
43
+ }
44
+ else if (endIdx < eqIdx) {
45
+ // backtrack on prior semicolon
46
+ index = str.lastIndexOf(";", eqIdx - 1) + 1;
47
+ continue;
48
+ }
49
+ var key = str.slice(index, eqIdx).trim();
50
+ // only assign once
51
+ if (undefined === obj[key]) {
52
+ var val = str.slice(eqIdx + 1, endIdx).trim();
53
+ // quoted values
54
+ if (val.charCodeAt(0) === 0x22) {
55
+ val = val.slice(1, -1);
56
+ }
57
+ obj[key] = tryDecode(val, dec);
58
+ }
59
+ index = endIdx + 1;
60
+ }
61
+ return obj;
62
+ }
63
+ /**
64
+ * Serialize data into a cookie header.
65
+ *
66
+ * Serialize the a name value pair into a cookie string suitable for
67
+ * http headers. An optional options object specified cookie parameters.
68
+ *
69
+ * serialize('foo', 'bar', { httpOnly: true })
70
+ * => "foo=bar; httpOnly"
71
+ *
72
+ * @param {string} name
73
+ * @param {string} val
74
+ * @param {object} [options]
75
+ * @return {string}
76
+ * @public
77
+ */
78
+ function serialize(name, val, options) {
79
+ var opt = options || {};
80
+ var enc = opt.encode || encode;
81
+ if (typeof enc !== "function") {
82
+ throw new TypeError("option encode is invalid");
83
+ }
84
+ if (!fieldContentRegExp.test(name)) {
85
+ throw new TypeError("argument name is invalid");
86
+ }
87
+ var value = enc(val);
88
+ if (value && !fieldContentRegExp.test(value)) {
89
+ throw new TypeError("argument val is invalid");
90
+ }
91
+ var str = name + "=" + value;
92
+ if (null != opt.maxAge) {
93
+ var maxAge = opt.maxAge - 0;
94
+ if (isNaN(maxAge) || !isFinite(maxAge)) {
95
+ throw new TypeError("option maxAge is invalid");
96
+ }
97
+ str += "; Max-Age=" + Math.floor(maxAge);
98
+ }
99
+ if (opt.domain) {
100
+ if (!fieldContentRegExp.test(opt.domain)) {
101
+ throw new TypeError("option domain is invalid");
102
+ }
103
+ str += "; Domain=" + opt.domain;
104
+ }
105
+ if (opt.path) {
106
+ if (!fieldContentRegExp.test(opt.path)) {
107
+ throw new TypeError("option path is invalid");
108
+ }
109
+ str += "; Path=" + opt.path;
110
+ }
111
+ if (opt.expires) {
112
+ var expires = opt.expires;
113
+ if (!isDate(expires) || isNaN(expires.valueOf())) {
114
+ throw new TypeError("option expires is invalid");
115
+ }
116
+ str += "; Expires=" + expires.toUTCString();
117
+ }
118
+ if (opt.httpOnly) {
119
+ str += "; HttpOnly";
120
+ }
121
+ if (opt.secure) {
122
+ str += "; Secure";
123
+ }
124
+ if (opt.priority) {
125
+ var priority = typeof opt.priority === "string"
126
+ ? opt.priority.toLowerCase()
127
+ : opt.priority;
128
+ switch (priority) {
129
+ case "low":
130
+ str += "; Priority=Low";
131
+ break;
132
+ case "medium":
133
+ str += "; Priority=Medium";
134
+ break;
135
+ case "high":
136
+ str += "; Priority=High";
137
+ break;
138
+ default:
139
+ throw new TypeError("option priority is invalid");
140
+ }
141
+ }
142
+ if (opt.sameSite) {
143
+ var sameSite = typeof opt.sameSite === "string"
144
+ ? opt.sameSite.toLowerCase()
145
+ : opt.sameSite;
146
+ switch (sameSite) {
147
+ case true:
148
+ str += "; SameSite=Strict";
149
+ break;
150
+ case "lax":
151
+ str += "; SameSite=Lax";
152
+ break;
153
+ case "strict":
154
+ str += "; SameSite=Strict";
155
+ break;
156
+ case "none":
157
+ str += "; SameSite=None";
158
+ break;
159
+ default:
160
+ throw new TypeError("option sameSite is invalid");
161
+ }
162
+ }
163
+ return str;
164
+ }
165
+ /**
166
+ * URL-decode string value. Optimized to skip native call when no %.
167
+ *
168
+ * @param {string} str
169
+ * @returns {string}
170
+ */
171
+ function decode(str) {
172
+ return str.indexOf("%") !== -1 ? decodeURIComponent(str) : str;
173
+ }
174
+ /**
175
+ * URL-encode value.
176
+ *
177
+ * @param {string} str
178
+ * @returns {string}
179
+ */
180
+ function encode(val) {
181
+ return encodeURIComponent(val);
182
+ }
183
+ /**
184
+ * Determine if value is a Date.
185
+ *
186
+ * @param {*} val
187
+ * @private
188
+ */
189
+ function isDate(val) {
190
+ return __toString.call(val) === "[object Date]" || val instanceof Date;
191
+ }
192
+ /**
193
+ * Try decoding a string using a decoding function.
194
+ *
195
+ * @param {string} str
196
+ * @param {function} decode
197
+ * @private
198
+ */
199
+ function tryDecode(str, decode) {
200
+ try {
201
+ return decode(str);
202
+ }
203
+ catch (e) {
204
+ return str;
205
+ }
206
+ }
207
+ export { parse as parseCookieHeader, serialize as createCookie };
@@ -0,0 +1 @@
1
+ export declare function compileTemplate(text: string): (data: any) => string;
@@ -0,0 +1,107 @@
1
+ // from https://github.com/jashkenas/underscore/blob/master/modules/template.js
2
+ const escapeMap = {
3
+ "&": "&amp;",
4
+ "<": "&lt;",
5
+ ">": "&gt;",
6
+ '"': "&quot;",
7
+ };
8
+ const ESCAPE_REGEX = /[&<>"]/g;
9
+ const _ = {
10
+ escape(s) {
11
+ return s.replace(ESCAPE_REGEX, (match) => escapeMap[match]);
12
+ },
13
+ };
14
+ // When customizing `_.templateSettings`, if you don't want to define an
15
+ // interpolation, evaluation or escaping regex, we need one that is
16
+ // guaranteed not to match.
17
+ var noMatch = /(.)^/;
18
+ // Certain characters need to be escaped so that they can be put into a
19
+ // string literal.
20
+ var escapes = {
21
+ "'": "'",
22
+ "\\": "\\",
23
+ "\r": "r",
24
+ "\n": "n",
25
+ "\u2028": "u2028",
26
+ "\u2029": "u2029",
27
+ };
28
+ var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
29
+ function escapeChar(match) {
30
+ return "\\" + escapes[match];
31
+ }
32
+ // In order to prevent third-party code injection through
33
+ // `_.templateSettings.variable`, we test it against the following regular
34
+ // expression. It is intentionally a bit more liberal than just matching valid
35
+ // identifiers, but still prevents possible loopholes through defaults or
36
+ // destructuring assignment.
37
+ var bareIdentifier = /^\s*(\w|\$)+\s*$/;
38
+ // JavaScript micro-templating, similar to John Resig's implementation.
39
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
40
+ // and correctly escapes quotes within interpolated code.
41
+ // NB: `oldSettings` only exists for backwards compatibility.
42
+ export function compileTemplate(text) {
43
+ const settings = {
44
+ evaluate: /<%([\s\S]+?)%>/g,
45
+ interpolate: /<%=([\s\S]+?)%>/g,
46
+ escape: /<%-([\s\S]+?)%>/g,
47
+ };
48
+ // Combine delimiters into one regular expression via alternation.
49
+ var matcher = RegExp([
50
+ (settings.escape || noMatch).source,
51
+ (settings.interpolate || noMatch).source,
52
+ (settings.evaluate || noMatch).source,
53
+ ].join("|") + "|$", "g");
54
+ // Compile the template source, escaping string literals appropriately.
55
+ var index = 0;
56
+ var source = "__p+='";
57
+ text.replace(matcher, function (match, escape, interpolate, evaluate, offset) {
58
+ source += text.slice(index, offset).replace(escapeRegExp, escapeChar);
59
+ index = offset + match.length;
60
+ if (escape) {
61
+ source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
62
+ }
63
+ else if (interpolate) {
64
+ source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
65
+ }
66
+ else if (evaluate) {
67
+ source += "';\n" + evaluate + "\n__p+='";
68
+ }
69
+ // Adobe VMs need the match returned to produce the correct offset.
70
+ return match;
71
+ });
72
+ source += "';\n";
73
+ // @ts-expect-error unknown property
74
+ var argument = settings.variable;
75
+ if (argument) {
76
+ // Insure against third-party code injection. (CVE-2021-23358)
77
+ if (!bareIdentifier.test(argument))
78
+ throw new Error("variable is not a bare identifier: " + argument);
79
+ }
80
+ else {
81
+ // If a variable is not specified, place data values in local scope.
82
+ source = "with(obj||{}){\n" + source + "}\n";
83
+ argument = "obj";
84
+ }
85
+ source =
86
+ "var __t,__p='',__j=Array.prototype.join," +
87
+ "print=function(){__p+=__j.call(arguments,'');};\n" +
88
+ source +
89
+ "return __p;\n";
90
+ var render;
91
+ try {
92
+ render = new Function(argument, "_", source);
93
+ }
94
+ catch (e) {
95
+ // @ts-expect-error unknown property
96
+ e.source = source;
97
+ throw e;
98
+ }
99
+ var template = function (data) {
100
+ // @ts-expect-error unknown this
101
+ return render.call(this, data, _);
102
+ };
103
+ // Provide the compiled source as a convenience for precompilation.
104
+ // @ts-expect-error unknown property
105
+ template.source = "function(" + argument + "){\n" + source + "}";
106
+ return template;
107
+ }
@@ -0,0 +1,32 @@
1
+ export { Component, type Ctor, ComponentFactory, INJECT } from "./Component.js";
2
+ export { type InternalUserId, type UserId, type InternalGroupId, type GroupId, type Role, type ConnectedUser, type AdminUserId, type Admin, type Context, emptyContext, } from "./Context.js";
3
+ export { ConfigService } from "./ConfigService.js";
4
+ export { DB, DuplicateKeyError } from "./DB.js";
5
+ export { EventEmitter } from "./EventEmitter.js";
6
+ export { PubSubService, NodeClusterPubSubService, initPrimary, } from "./PubSubService.js";
7
+ export { I18nService } from "./I18nService.js";
8
+ export { Endpoint, AdminEndpoint } from "./Endpoint.js";
9
+ export { type HttpContext } from "./HttpContext.js";
10
+ export { App } from "./App.js";
11
+ export { type Module, type AppInit, ModuleDefinitions, type Route, } from "./Module.js";
12
+ export { View, AdminView } from "./View.js";
13
+ export { Middleware } from "./Middleware.js";
14
+ export { Repository, type Page, EntityNotFoundError } from "./Repository.js";
15
+ export { TemplateService } from "./TemplateService.js";
16
+ export { createCookie, parseCookieHeader } from "./contrib/cookie.js";
17
+ export { AJV_INSTANCE } from "./utils/ajv.js";
18
+ export { camelToSnakeCase } from "./utils/camelToSnakeCase.js";
19
+ export { createDebug } from "./utils/createDebug.js";
20
+ export { createTestApp, type BaseTestContext } from "./utils/createTestApp.js";
21
+ export { escapeValue } from "./utils/escapeValue.js";
22
+ export { FS } from "./utils/fs.js";
23
+ export { isAdmin } from "./utils/isAdmin.js";
24
+ export { isProduction } from "./utils/isProduction.js";
25
+ export { randomId } from "./utils/randomId.js";
26
+ export { randomUUID } from "./utils/randomUUID.js";
27
+ export { snakeToCamelCase } from "./utils/snakeToCamelCase.js";
28
+ export { sortBy } from "./utils/sortBy.js";
29
+ export { sql, Statement } from "./utils/sql.js";
30
+ export { toNodeHandler } from "./utils/toNodeHandler.js";
31
+ export { type Brand } from "./utils/types.js";
32
+ export { waitFor } from "./utils/waitFor.js";