@tymber/common 0.0.1-alpha.0 → 0.0.1

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 (128) hide show
  1. package/LICENSE +22 -0
  2. package/dist/App.d.ts +14 -0
  3. package/dist/App.js +227 -0
  4. package/dist/Component.d.ts +16 -0
  5. package/dist/Component.js +116 -0
  6. package/dist/ConfigService.d.ts +31 -0
  7. package/dist/ConfigService.js +75 -0
  8. package/dist/Context.d.ts +32 -0
  9. package/dist/Context.js +10 -0
  10. package/dist/DB.d.ts +15 -0
  11. package/dist/DB.js +7 -0
  12. package/dist/Endpoint.d.ts +21 -0
  13. package/dist/Endpoint.js +87 -0
  14. package/dist/EventEmitter.d.ts +9 -0
  15. package/dist/EventEmitter.js +21 -0
  16. package/dist/Handler.d.ts +8 -0
  17. package/dist/Handler.js +8 -0
  18. package/dist/HttpContext.d.ts +24 -0
  19. package/dist/HttpContext.js +10 -0
  20. package/dist/I18nService.d.ts +18 -0
  21. package/dist/I18nService.js +72 -0
  22. package/dist/Middleware.d.ts +6 -0
  23. package/dist/Middleware.js +4 -0
  24. package/dist/Module.d.ts +47 -0
  25. package/dist/Module.js +12 -0
  26. package/dist/PubSubService.d.ts +20 -0
  27. package/dist/PubSubService.js +60 -0
  28. package/dist/Repository.d.ts +48 -0
  29. package/dist/Repository.js +133 -0
  30. package/dist/Router.d.ts +10 -0
  31. package/dist/Router.js +53 -0
  32. package/dist/TemplateService.d.ts +22 -0
  33. package/dist/TemplateService.js +66 -0
  34. package/dist/View.d.ts +17 -0
  35. package/dist/View.js +48 -0
  36. package/dist/ViewRenderer.d.ts +15 -0
  37. package/dist/ViewRenderer.js +58 -0
  38. package/dist/contrib/accept-language-parser.d.ts +9 -0
  39. package/dist/contrib/accept-language-parser.js +73 -0
  40. package/dist/contrib/cookie.d.ts +33 -0
  41. package/dist/contrib/cookie.js +207 -0
  42. package/dist/contrib/template.d.ts +1 -0
  43. package/dist/contrib/template.js +107 -0
  44. package/dist/index.d.ts +31 -0
  45. package/dist/index.js +31 -0
  46. package/dist/utils/ajv.d.ts +2 -0
  47. package/dist/utils/ajv.js +10 -0
  48. package/dist/utils/camelToSnakeCase.d.ts +1 -0
  49. package/dist/utils/camelToSnakeCase.js +3 -0
  50. package/dist/utils/computeBaseUrl.d.ts +1 -0
  51. package/dist/utils/computeBaseUrl.js +37 -0
  52. package/dist/utils/computeContentType.d.ts +1 -0
  53. package/dist/utils/computeContentType.js +17 -0
  54. package/dist/utils/createDebug.d.ts +1 -0
  55. package/dist/utils/createDebug.js +4 -0
  56. package/dist/utils/createTestApp.d.ts +8 -0
  57. package/dist/utils/createTestApp.js +54 -0
  58. package/dist/utils/escapeValue.d.ts +1 -0
  59. package/dist/utils/escapeValue.js +3 -0
  60. package/dist/utils/fs.d.ts +6 -0
  61. package/dist/utils/fs.js +13 -0
  62. package/dist/utils/isAdmin.d.ts +2 -0
  63. package/dist/utils/isAdmin.js +4 -0
  64. package/dist/utils/isProduction.d.ts +1 -0
  65. package/dist/utils/isProduction.js +1 -0
  66. package/dist/utils/loadModules.d.ts +3 -0
  67. package/dist/utils/loadModules.js +83 -0
  68. package/dist/utils/randomId.d.ts +1 -0
  69. package/dist/utils/randomId.js +4 -0
  70. package/dist/utils/randomUUID.d.ts +1 -0
  71. package/dist/utils/randomUUID.js +4 -0
  72. package/dist/utils/runMigrations.d.ts +3 -0
  73. package/dist/utils/runMigrations.js +85 -0
  74. package/dist/utils/snakeToCamelCase.d.ts +1 -0
  75. package/dist/utils/snakeToCamelCase.js +3 -0
  76. package/dist/utils/sortBy.d.ts +1 -0
  77. package/dist/utils/sortBy.js +8 -0
  78. package/dist/utils/sql.d.ts +120 -0
  79. package/dist/utils/sql.js +433 -0
  80. package/dist/utils/toNodeHandler.d.ts +2 -0
  81. package/dist/utils/toNodeHandler.js +91 -0
  82. package/dist/utils/types.d.ts +3 -0
  83. package/dist/utils/types.js +1 -0
  84. package/dist/utils/waitFor.d.ts +1 -0
  85. package/dist/utils/waitFor.js +5 -0
  86. package/package.json +28 -2
  87. package/src/App.ts +302 -0
  88. package/src/Component.ts +166 -0
  89. package/src/ConfigService.ts +121 -0
  90. package/src/Context.ts +49 -0
  91. package/src/DB.ts +28 -0
  92. package/src/Endpoint.ts +118 -0
  93. package/src/EventEmitter.ts +32 -0
  94. package/src/Handler.ts +14 -0
  95. package/src/HttpContext.ts +33 -0
  96. package/src/I18nService.ts +96 -0
  97. package/src/Middleware.ts +10 -0
  98. package/src/Module.ts +60 -0
  99. package/src/PubSubService.ts +77 -0
  100. package/src/Repository.ts +204 -0
  101. package/src/Router.ts +77 -0
  102. package/src/TemplateService.ts +97 -0
  103. package/src/View.ts +60 -0
  104. package/src/ViewRenderer.ts +71 -0
  105. package/src/contrib/accept-language-parser.ts +94 -0
  106. package/src/contrib/cookie.ts +256 -0
  107. package/src/contrib/template.ts +134 -0
  108. package/src/index.ts +57 -0
  109. package/src/utils/ajv.ts +13 -0
  110. package/src/utils/camelToSnakeCase.ts +3 -0
  111. package/src/utils/computeBaseUrl.ts +46 -0
  112. package/src/utils/computeContentType.ts +17 -0
  113. package/src/utils/createDebug.ts +5 -0
  114. package/src/utils/createTestApp.ts +81 -0
  115. package/src/utils/escapeValue.ts +3 -0
  116. package/src/utils/fs.ts +15 -0
  117. package/src/utils/isAdmin.ts +5 -0
  118. package/src/utils/isProduction.ts +2 -0
  119. package/src/utils/loadModules.ts +105 -0
  120. package/src/utils/randomId.ts +5 -0
  121. package/src/utils/randomUUID.ts +5 -0
  122. package/src/utils/runMigrations.ts +122 -0
  123. package/src/utils/snakeToCamelCase.ts +3 -0
  124. package/src/utils/sortBy.ts +8 -0
  125. package/src/utils/sql.ts +553 -0
  126. package/src/utils/toNodeHandler.ts +121 -0
  127. package/src/utils/types.ts +1 -0
  128. package/src/utils/waitFor.ts +5 -0
@@ -0,0 +1,433 @@
1
+ export function sql() { }
2
+ const options = {
3
+ placeholder: "$%d",
4
+ quoteChar: '"',
5
+ };
6
+ sql.setOption = function (o, value) {
7
+ options[o] = value;
8
+ };
9
+ function joinParts(parts) {
10
+ return parts.filter((s) => !!s).join(" ");
11
+ }
12
+ export class Statement {
13
+ build() {
14
+ const values = [];
15
+ return {
16
+ text: joinParts(this.computeParts({
17
+ values,
18
+ })),
19
+ values,
20
+ };
21
+ }
22
+ }
23
+ function joinExpression(type, table, on) {
24
+ return () => {
25
+ // we cannot use sql.and() since the right part of the expression must be escaped with handleColumn() instead of handleValue()
26
+ const condition = Object.entries(on)
27
+ .map(([column, value]) => {
28
+ return handleColumn(column) + " = " + handleColumn(value);
29
+ })
30
+ .join(" AND ");
31
+ return `${type} JOIN ${handleTable(table)} ON ${condition}`;
32
+ };
33
+ }
34
+ class SelectStatement extends Statement {
35
+ _table;
36
+ _distinct = false;
37
+ _columns = [];
38
+ _joins = [];
39
+ _where = [];
40
+ _orderBy = [];
41
+ _groupBy = [];
42
+ _having;
43
+ _limit;
44
+ _offset;
45
+ _forUpdate = false;
46
+ constructor(columns) {
47
+ super();
48
+ if (columns) {
49
+ this._columns.push(...columns);
50
+ }
51
+ }
52
+ distinct() {
53
+ this._distinct = true;
54
+ return this;
55
+ }
56
+ from(table) {
57
+ this._table = table;
58
+ return this;
59
+ }
60
+ innerJoin(table, on) {
61
+ this._joins.push(joinExpression("INNER", table, on));
62
+ return this;
63
+ }
64
+ leftJoin(table, on) {
65
+ this._joins.push(joinExpression("LEFT", table, on));
66
+ return this;
67
+ }
68
+ rightJoin(table, on) {
69
+ this._joins.push(joinExpression("RIGHT", table, on));
70
+ return this;
71
+ }
72
+ fullOuterJoin(table, on) {
73
+ this._joins.push(joinExpression("FULL OUTER", table, on));
74
+ return this;
75
+ }
76
+ where(arg) {
77
+ if (typeof arg === "function") {
78
+ this._where.push(arg);
79
+ }
80
+ else {
81
+ for (const [column, value] of Object.entries(arg)) {
82
+ this._where.push(sql.eq(column, value));
83
+ }
84
+ }
85
+ return this;
86
+ }
87
+ groupBy(columns) {
88
+ this._groupBy.push(...columns);
89
+ return this;
90
+ }
91
+ having(expr) {
92
+ this._having = expr;
93
+ return this;
94
+ }
95
+ orderBy(columns) {
96
+ this._orderBy.push(...columns);
97
+ return this;
98
+ }
99
+ limit(limit) {
100
+ this._limit = limit;
101
+ return this;
102
+ }
103
+ offset(offset) {
104
+ this._offset = offset;
105
+ return this;
106
+ }
107
+ forUpdate() {
108
+ this._forUpdate = true;
109
+ return this;
110
+ }
111
+ computeParts(ctx) {
112
+ return [
113
+ "SELECT",
114
+ this.distinctPart(),
115
+ this.columnsPart(ctx),
116
+ this.fromPart(),
117
+ this.joinsPart(ctx),
118
+ this.wherePart(ctx),
119
+ this.groupByPart(),
120
+ this.havingPart(ctx),
121
+ this.orderByPart(),
122
+ this.limitPart(ctx),
123
+ this.offsetPart(ctx),
124
+ this.forUpdatePart(),
125
+ ];
126
+ }
127
+ distinctPart() {
128
+ if (this._distinct) {
129
+ return "DISTINCT";
130
+ }
131
+ }
132
+ columnsPart(ctx) {
133
+ if (this._columns.length) {
134
+ return this._columns
135
+ .map((column) => {
136
+ return typeof column === "function"
137
+ ? column(ctx)
138
+ : handleColumn(column);
139
+ })
140
+ .join(", ");
141
+ }
142
+ else {
143
+ return "*";
144
+ }
145
+ }
146
+ fromPart() {
147
+ if (this._table) {
148
+ return `FROM ${handleTable(this._table)}`;
149
+ }
150
+ }
151
+ joinsPart(ctx) {
152
+ if (this._joins.length) {
153
+ return this._joins.map((join) => join(ctx)).join(" ");
154
+ }
155
+ }
156
+ wherePart(ctx) {
157
+ if (this._where.length) {
158
+ return "WHERE " + groupExpression(this._where, " AND ", false)(ctx);
159
+ }
160
+ }
161
+ groupByPart() {
162
+ if (this._groupBy.length) {
163
+ return "GROUP BY " + handleColumns(this._groupBy);
164
+ }
165
+ }
166
+ havingPart(ctx) {
167
+ if (this._having) {
168
+ return "HAVING " + this._having(ctx);
169
+ }
170
+ }
171
+ orderByPart() {
172
+ if (this._orderBy.length) {
173
+ return "ORDER BY " + handleColumns(this._orderBy);
174
+ }
175
+ }
176
+ limitPart(ctx) {
177
+ if (this._limit) {
178
+ // PostgreSQL/SQLite syntax
179
+ return "LIMIT " + handleValue(this._limit, ctx);
180
+ }
181
+ }
182
+ offsetPart(ctx) {
183
+ if (this._offset) {
184
+ // PostgreSQL/SQLite syntax
185
+ return "OFFSET " + handleValue(this._offset, ctx);
186
+ }
187
+ }
188
+ forUpdatePart() {
189
+ if (this._forUpdate) {
190
+ return "FOR UPDATE";
191
+ }
192
+ }
193
+ }
194
+ sql.select = (columns) => new SelectStatement(columns);
195
+ class InsertStatement extends Statement {
196
+ _table;
197
+ _values = [];
198
+ _select;
199
+ _returning = [];
200
+ into(table) {
201
+ this._table = table;
202
+ return this;
203
+ }
204
+ values(values) {
205
+ this._values.push(...values);
206
+ return this;
207
+ }
208
+ select(statement) {
209
+ this._select = statement;
210
+ return this;
211
+ }
212
+ returning(columns = ["*"]) {
213
+ this._returning.push(...columns);
214
+ return this;
215
+ }
216
+ computeParts(ctx) {
217
+ return [
218
+ "INSERT",
219
+ this.intoPart(),
220
+ this.columnsPart(),
221
+ this.valuesPart(ctx),
222
+ this.returningPart(),
223
+ ];
224
+ }
225
+ intoPart() {
226
+ if (this._table) {
227
+ return "INTO " + handleTable(this._table);
228
+ }
229
+ }
230
+ columnsPart() {
231
+ if (this._values.length) {
232
+ const columns = Object.keys(this._values[0]);
233
+ return "(" + columns.map(handleColumn).join(", ") + ")";
234
+ }
235
+ if (this._select) {
236
+ // @ts-expect-error protected method
237
+ return "(" + this._select.columnsPart() + ")";
238
+ }
239
+ }
240
+ valuesPart(ctx) {
241
+ if (this._values.length) {
242
+ const columns = Object.keys(this._values[0]);
243
+ const values = this._values.map((values) => `(${columns.map((column) => handleValue(values[column], ctx)).join(", ")})`);
244
+ return "VALUES " + values.join(", ");
245
+ }
246
+ if (this._select) {
247
+ // @ts-expect-error protected method
248
+ return joinParts(this._select.computeParts(ctx));
249
+ }
250
+ }
251
+ returningPart() {
252
+ if (this._returning.length) {
253
+ return "RETURNING " + handleColumns(this._returning);
254
+ }
255
+ }
256
+ }
257
+ sql.insert = () => new InsertStatement();
258
+ class UpdateStatement extends Statement {
259
+ table;
260
+ _values = {};
261
+ _where = [];
262
+ constructor(table) {
263
+ super();
264
+ this.table = table;
265
+ }
266
+ set(values) {
267
+ Object.assign(this._values, values);
268
+ return this;
269
+ }
270
+ where(arg) {
271
+ if (typeof arg === "function") {
272
+ this._where.push(arg);
273
+ }
274
+ else {
275
+ for (const [column, value] of Object.entries(arg)) {
276
+ this._where.push(sql.eq(column, value));
277
+ }
278
+ }
279
+ return this;
280
+ }
281
+ computeParts(ctx) {
282
+ return [
283
+ `UPDATE ${handleTable(this.table)}`,
284
+ this.setPart(ctx),
285
+ this.wherePart(ctx),
286
+ ];
287
+ }
288
+ setPart(ctx) {
289
+ const values = [];
290
+ for (const [column, value] of Object.entries(this._values)) {
291
+ values.push(`${handleColumn(column)} = ${handleValue(value, ctx)}`);
292
+ }
293
+ return "SET " + values.join(", ");
294
+ }
295
+ wherePart(ctx) {
296
+ if (this._where.length) {
297
+ return "WHERE " + groupExpression(this._where, " AND ", false)(ctx);
298
+ }
299
+ }
300
+ }
301
+ sql.update = (table) => new UpdateStatement(table);
302
+ class DeleteStatement extends Statement {
303
+ _table;
304
+ _where = [];
305
+ constructor(table) {
306
+ super();
307
+ this._table = table;
308
+ }
309
+ where(arg) {
310
+ if (typeof arg === "function") {
311
+ this._where.push(arg);
312
+ }
313
+ else {
314
+ for (const [column, value] of Object.entries(arg)) {
315
+ this._where.push(sql.eq(column, value));
316
+ }
317
+ }
318
+ return this;
319
+ }
320
+ computeParts(ctx) {
321
+ return [`DELETE FROM ${handleTable(this._table)}`, this.wherePart(ctx)];
322
+ }
323
+ wherePart(ctx) {
324
+ if (this._where.length) {
325
+ return "WHERE " + groupExpression(this._where, " AND ", false)(ctx);
326
+ }
327
+ }
328
+ }
329
+ sql.deleteFrom = (table) => new DeleteStatement(table);
330
+ function groupExpression(clauses, op, includeParens = true) {
331
+ return (ctx) => {
332
+ const output = clauses.map((expr) => expr(ctx)).join(op);
333
+ return includeParens ? `(${output})` : output;
334
+ };
335
+ }
336
+ sql.and = (clauses) => groupExpression(clauses, " AND ");
337
+ sql.or = (clauses) => groupExpression(clauses, " OR ");
338
+ sql.not = (expr) => (ctx) => "NOT " + expr(ctx);
339
+ function unaryExpression(column, op) {
340
+ return () => `${handleColumn(column)} ${op}`;
341
+ }
342
+ sql.isNull = (column) => unaryExpression(column, "IS NULL");
343
+ sql.isNotNull = (column) => unaryExpression(column, "IS NOT NULL");
344
+ function binaryExpression(column, op, value) {
345
+ return (ctx) => `${handleColumn(column)} ${op} ${handleValue(value, ctx)}`;
346
+ }
347
+ sql.eq = (column, value) => {
348
+ return value === null
349
+ ? sql.isNull(column)
350
+ : binaryExpression(column, "=", value);
351
+ };
352
+ sql.notEq = (column, value) => {
353
+ return value === null
354
+ ? sql.isNotNull(column)
355
+ : binaryExpression(column, "<>", value);
356
+ };
357
+ sql.lt = (column, value) => binaryExpression(column, "<", value);
358
+ sql.lte = (column, value) => binaryExpression(column, "<=", value);
359
+ sql.gt = (column, value) => binaryExpression(column, ">", value);
360
+ sql.gte = (column, value) => binaryExpression(column, ">=", value);
361
+ sql.between = (column, low, high) => {
362
+ return (ctx) => `${handleColumn(column)} BETWEEN ${handleValue(low, ctx)} AND ${handleValue(high, ctx)}`;
363
+ };
364
+ function likeExpression(column, op, value, escapeChar) {
365
+ return (ctx) => {
366
+ const output = `${handleColumn(column)} ${op} ${handleValue(value, ctx)}`;
367
+ return escapeChar ? `${output} ESCAPE '${escapeChar}'` : output;
368
+ };
369
+ }
370
+ sql.like = (column, value, escapeChar) => likeExpression(column, "LIKE", value, escapeChar);
371
+ sql.ilike = (column, value, escapeChar) => likeExpression(column, "ILIKE", value, escapeChar);
372
+ sql.in = (column, values) => {
373
+ return (ctx) => `${handleColumn(column)} IN (${values.map((value) => handleValue(value, ctx)).join(", ")})`;
374
+ };
375
+ sql.raw = (text, values = []) => {
376
+ return (ctx) => {
377
+ let i = 0;
378
+ return text.replace(/\?/g, () => {
379
+ if (i >= values.length) {
380
+ throw new Error("not enough values");
381
+ }
382
+ return handleValue(values[i++], ctx);
383
+ });
384
+ };
385
+ };
386
+ function handleColumns(columns) {
387
+ return columns.map(handleColumn).join(", ");
388
+ }
389
+ const WITH_SCHEMA_OR_ALIAS_REGEX = /^((\w+)\.)?(\w+)(( AS)? \w+)?$/i;
390
+ function handleTable(table) {
391
+ return handleColumn(table);
392
+ }
393
+ function handleColumn(name) {
394
+ const match = WITH_SCHEMA_OR_ALIAS_REGEX.exec(name);
395
+ if (match) {
396
+ const schema = match[2];
397
+ const table = match[3];
398
+ const alias = match[4];
399
+ let output = schema
400
+ ? `${quoteKey(schema)}.${quoteKey(table)}`
401
+ : quoteKey(table);
402
+ if (alias) {
403
+ output += alias;
404
+ }
405
+ return output;
406
+ }
407
+ return quoteKey(name);
408
+ }
409
+ const UPPERCASE_REGEX = /[A-Z]/;
410
+ // SQL:2023 specification: https://en.wikipedia.org/wiki/List_of_SQL_reserved_words
411
+ // prettier-ignore
412
+ const RESERVED_KEYWORDS = new Set(["abs", "absent", "acos", "all", "allocate", "alter", "and", "any", "any_value", "are", "array", "array_agg", "array_max_cardinality", "as", "asensitive", "asin", "asymmetric", "at", "atan", "atomic", "authorization", "avg", "begin", "begin_frame", "begin_partition", "between", "bigint", "binary", "blob", "boolean", "both", "btrim", "by", "call", "called", "cardinality", "cascaded", "case", "cast", "ceil", "ceiling", "char", "char_length", "character", "character_length", "check", "classifier", "clob", "close", "coalesce", "collate", "collect", "column", "commit", "condition", "connect", "constraint", "contains", "convert", "copy", "corr", "corresponding", "cos", "cosh", "count", "covar_pop", "covar_samp", "create", "cross", "cube", "cume_dist", "current", "current_catalog", "current_date", "current_default_transform_group", "current_path", "current_role", "current_row", "current_schema", "current_time", "current_timestamp", "current_transform_group_for_type", "current_user", "cursor", "cycle", "date", "day", "deallocate", "dec", "decfloat", "decimal", "declare", "default", "define", "delete", "dense_rank", "deref", "describe", "deterministic", "disconnect", "distinct", "double", "drop", "dynamic", "each", "element", "else", "empty", "end", "end_frame", "end_partition", "end-exec", "equals", "escape", "every", "except", "exec", "execute", "exists", "exp", "external", "extract", "false", "fetch", "filter", "first_value", "float", "floor", "for", "foreign", "frame_row", "free", "from", "full", "function", "fusion", "get", "global", "grant", "greatest", "group", "grouping", "groups", "having", "hold", "hour", "identity", "in", "indicator", "initial", "inner", "inout", "insensitive", "insert", "int", "integer", "intersect", "intersection", "interval", "into", "is", "join", "json", "json_array", "json_arrayagg", "json_exists", "json_object", "json_objectagg", "json_query", "json_scalar", "json_serialize", "json_table", "json_table_primitive", "json_value", "lag", "language", "large", "last_value", "lateral", "lead", "leading", "least", "left", "like", "like_regex", "listagg", "ln", "local", "localtime", "localtimestamp", "log", "log10", "lower", "lpad", "ltrim", "match", "match_number", "match_recognize", "matches", "max", "member", "merge", "method", "min", "minute", "mod", "modifies", "module", "month", "multiset", "national", "natural", "nchar", "nclob", "new", "no", "none", "normalize", "not", "nth_value", "ntile", "null", "nullif", "numeric", "occurrences_regex", "octet_length", "of", "offset", "old", "omit", "on", "one", "only", "open", "or", "order", "out", "outer", "over", "overlaps", "overlay", "parameter", "partition", "pattern", "per", "percent", "percent_rank", "percentile_cont", "percentile_disc", "period", "portion", "position", "position_regex", "power", "precedes", "precision", "prepare", "primary", "procedure", "ptf", "range", "rank", "reads", "real", "recursive", "ref", "references", "referencing", "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", "regr_r2", "regr_slope", "regr_sxx", "regr_sxy", "regr_syy", "release", "result", "return", "returns", "revoke", "right", "rollback", "rollup", "row", "row_number", "rows", "rpad", "running", "savepoint", "scope", "scroll", "search", "second", "seek", "select", "sensitive", "session_user", "set", "show", "similar", "sin", "sinh", "skip", "smallint", "some", "specific", "specifictype", "sql", "sqlexception", "sqlstate", "sqlwarning", "sqrt", "start", "static", "stddev_pop", "stddev_samp", "submultiset", "subset", "substring", "substring_regex", "succeeds", "sum", "symmetric", "system", "system_time", "system_user", "table", "tablesample", "tan", "tanh", "then", "time", "timestamp", "timezone_hour", "timezone_minute", "to", "trailing", "translate", "translate_regex", "translation", "treat", "trigger", "trim", "trim_array", "true", "truncate", "uescape", "union", "unique", "unknown", "unnest", "update", "upper", "user", "using", "value", "value_of", "values", "var_pop", "var_samp", "varbinary", "varchar", "varying", "versioning", "when", "whenever", "where", "width_bucket", "window", "with", "within", "without", "year"]);
413
+ function quoteKey(name) {
414
+ if (UPPERCASE_REGEX.test(name) || RESERVED_KEYWORDS.has(name)) {
415
+ return options.quoteChar + name + options.quoteChar;
416
+ }
417
+ return name;
418
+ }
419
+ function handleValue(value, ctx) {
420
+ ctx.values.push(value);
421
+ return options.placeholder.replace("%d", String(ctx.values.length));
422
+ }
423
+ class RawStatement extends Statement {
424
+ text;
425
+ constructor(text) {
426
+ super();
427
+ this.text = text;
428
+ }
429
+ computeParts() {
430
+ return [this.text];
431
+ }
432
+ }
433
+ sql.rawStatement = (text) => new RawStatement(text);
@@ -0,0 +1,2 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ export declare function toNodeHandler(nativeHandler: (req: Request) => Promise<Response>): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
@@ -0,0 +1,91 @@
1
+ import { Readable } from "node:stream";
2
+ import { createBrotliCompress, createDeflate, createGzip, createZstdCompress, } from "node:zlib";
3
+ function toHeaders(nodeHeaders) {
4
+ const headers = new Headers();
5
+ for (const [key, value] of Object.entries(nodeHeaders)) {
6
+ if (Array.isArray(value)) {
7
+ for (const val of value) {
8
+ headers.append(key, val);
9
+ }
10
+ }
11
+ else if (value !== undefined) {
12
+ headers.set(key, value);
13
+ }
14
+ }
15
+ return headers;
16
+ }
17
+ function readBody(req) {
18
+ return new Promise((resolve, reject) => {
19
+ const chunks = [];
20
+ req.setEncoding("utf8");
21
+ req.on("data", (chunk) => chunks.push(chunk));
22
+ req.on("end", () => resolve(chunks.join()));
23
+ req.on("error", (err) => reject(err));
24
+ });
25
+ }
26
+ function createNativeRequest(nodeReq) {
27
+ const req = Object.create(null);
28
+ req.url = nodeReq.url;
29
+ req.method = nodeReq.method;
30
+ req.headers = toHeaders(nodeReq.headers);
31
+ req.json = () => readBody(nodeReq).then(JSON.parse);
32
+ const controller = new AbortController();
33
+ req.signal = controller.signal;
34
+ nodeReq.on("close", () => controller.abort());
35
+ return req;
36
+ }
37
+ const AVAILABLE_COMPRESSION_ALGORITHMS = [
38
+ {
39
+ name: "zstd", // added in v22.15.0
40
+ createCompressor: createZstdCompress,
41
+ },
42
+ {
43
+ name: "brotli", // added in v10.16.0
44
+ createCompressor: createBrotliCompress,
45
+ },
46
+ {
47
+ name: "gzip",
48
+ createCompressor: createGzip,
49
+ },
50
+ {
51
+ name: "deflate",
52
+ createCompressor: createDeflate,
53
+ },
54
+ ];
55
+ function writeResponse(nodeReq, nodeRes, res) {
56
+ const isSSE = res.headers.get("content-type") === "text/event-stream";
57
+ const acceptEncoding = nodeReq.headers["accept-encoding"];
58
+ let compressor;
59
+ if (res.body && acceptEncoding && !isSSE) {
60
+ // TODO handle quality
61
+ // ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Encoding
62
+ for (const { name, createCompressor } of AVAILABLE_COMPRESSION_ALGORITHMS) {
63
+ if (acceptEncoding.includes(name)) {
64
+ res.headers.set("content-encoding", name);
65
+ compressor = createCompressor();
66
+ break;
67
+ }
68
+ }
69
+ }
70
+ nodeRes.setHeaders(res.headers);
71
+ nodeRes.writeHead(res.status);
72
+ if (!res.body) {
73
+ return nodeRes.end();
74
+ }
75
+ if (isSSE) {
76
+ nodeRes.flushHeaders();
77
+ }
78
+ if (compressor) {
79
+ Readable.fromWeb(res.body).pipe(compressor).pipe(nodeRes);
80
+ }
81
+ else {
82
+ Readable.fromWeb(res.body).pipe(nodeRes);
83
+ }
84
+ }
85
+ export function toNodeHandler(nativeHandler) {
86
+ return async function (nodeReq, nodeRes) {
87
+ const req = createNativeRequest(nodeReq);
88
+ const httpResponse = await nativeHandler(req);
89
+ writeResponse(nodeReq, nodeRes, httpResponse);
90
+ };
91
+ }
@@ -0,0 +1,3 @@
1
+ export type Brand<K, T> = K & {
2
+ __brand: T;
3
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare function waitFor(target: EventTarget, type: string): Promise<unknown>;
@@ -0,0 +1,5 @@
1
+ export function waitFor(target, type) {
2
+ return new Promise((resolve) => {
3
+ target.addEventListener(type, resolve, { once: true });
4
+ });
5
+ }
package/package.json CHANGED
@@ -1,7 +1,33 @@
1
1
  {
2
2
  "name": "@tymber/common",
3
- "version": "0.0.1-alpha.0",
3
+ "version": "0.0.1",
4
4
  "description": "The base of the Tymber framework",
5
5
  "license": "MIT",
6
- "author": "Damien ARRACHEQUESNE"
6
+ "author": "Damien ARRACHEQUESNE",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/tymber-framework/tymber.git"
10
+ },
11
+ "type": "module",
12
+ "main": "dist/index.js",
13
+ "types": "dist/index.d.ts",
14
+ "scripts": {
15
+ "compile": "rm -rf dist/ && tsc",
16
+ "format:check": "prettier -c src/ test/ bun-tests/",
17
+ "format:fix": "prettier -w src/ test/ bun-tests/",
18
+ "test": "tsx --test 'test/**/*.test.ts'"
19
+ },
20
+ "files": [
21
+ "src/",
22
+ "dist/"
23
+ ],
24
+ "exports": {
25
+ "node": "./dist/index.js",
26
+ "bun": "./src/index.ts",
27
+ "deno": "./src/index.ts"
28
+ },
29
+ "dependencies": {
30
+ "ajv": "~8.17.1",
31
+ "ajv-formats": "~3.0.1"
32
+ }
7
33
  }