@toa.io/extensions.chronicles 0.0.0-stage → 1.0.0-alpha.332

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 (67) hide show
  1. package/components/chronicles.facts/manifest.toa.yaml +32 -0
  2. package/components/chronicles.facts/operations/record.js +4 -0
  3. package/components/chronicles.facts/types/index.d.ts +3 -0
  4. package/components/chronicles.facts/types/toa.d.ts +19 -0
  5. package/components/chronicles.ingestion/manifest.toa.yaml +60 -0
  6. package/components/chronicles.ingestion/operations/anonymous.js +4 -0
  7. package/components/chronicles.ingestion/operations/identified.js +4 -0
  8. package/components/chronicles.ingestion/types/index.d.ts +3 -0
  9. package/components/chronicles.ingestion/types/toa.d.ts +23 -0
  10. package/components/chronicles.queries/manifest.toa.yaml +115 -0
  11. package/components/chronicles.queries/operations/define.js +3 -0
  12. package/components/chronicles.queries/operations/describe.js +3 -0
  13. package/components/chronicles.queries/operations/drop.js +3 -0
  14. package/components/chronicles.queries/operations/query.js +3 -0
  15. package/components/chronicles.queries/types/index.d.ts +3 -0
  16. package/components/chronicles.queries/types/toa.d.ts +44 -0
  17. package/package.json +35 -4
  18. package/readme.md +369 -0
  19. package/transpiled/Client.d.ts +19 -0
  20. package/transpiled/Client.js +121 -0
  21. package/transpiled/Client.js.map +1 -0
  22. package/transpiled/Factory.d.ts +16 -0
  23. package/transpiled/Factory.js +53 -0
  24. package/transpiled/Factory.js.map +1 -0
  25. package/transpiled/Facts.d.ts +9 -0
  26. package/transpiled/Facts.js +16 -0
  27. package/transpiled/Facts.js.map +1 -0
  28. package/transpiled/Provider.d.ts +91 -0
  29. package/transpiled/Provider.js +4 -0
  30. package/transpiled/Provider.js.map +1 -0
  31. package/transpiled/Reader.d.ts +16 -0
  32. package/transpiled/Reader.js +82 -0
  33. package/transpiled/Reader.js.map +1 -0
  34. package/transpiled/Recorder.d.ts +28 -0
  35. package/transpiled/Recorder.js +82 -0
  36. package/transpiled/Recorder.js.map +1 -0
  37. package/transpiled/Scribe.d.ts +25 -0
  38. package/transpiled/Scribe.js +61 -0
  39. package/transpiled/Scribe.js.map +1 -0
  40. package/transpiled/Sender.d.ts +21 -0
  41. package/transpiled/Sender.js +69 -0
  42. package/transpiled/Sender.js.map +1 -0
  43. package/transpiled/Writer.d.ts +14 -0
  44. package/transpiled/Writer.js +50 -0
  45. package/transpiled/Writer.js.map +1 -0
  46. package/transpiled/address.d.ts +7 -0
  47. package/transpiled/address.js +27 -0
  48. package/transpiled/address.js.map +1 -0
  49. package/transpiled/clickhouse/Client.d.ts +38 -0
  50. package/transpiled/clickhouse/Client.js +73 -0
  51. package/transpiled/clickhouse/Client.js.map +1 -0
  52. package/transpiled/clickhouse/Provider.d.ts +33 -0
  53. package/transpiled/clickhouse/Provider.js +144 -0
  54. package/transpiled/clickhouse/Provider.js.map +1 -0
  55. package/transpiled/clickhouse/ddl.d.ts +26 -0
  56. package/transpiled/clickhouse/ddl.js +88 -0
  57. package/transpiled/clickhouse/ddl.js.map +1 -0
  58. package/transpiled/index.d.ts +9 -0
  59. package/transpiled/index.js +2 -0
  60. package/transpiled/index.js.map +1 -0
  61. package/transpiled/settings.d.ts +11 -0
  62. package/transpiled/settings.js +35 -0
  63. package/transpiled/settings.js.map +1 -0
  64. package/transpiled/store.d.ts +5 -0
  65. package/transpiled/store.js +11 -0
  66. package/transpiled/store.js.map +1 -0
  67. package/README.md +0 -3
@@ -0,0 +1,38 @@
1
+ /**
2
+ * ClickHouse over its HTTP interface, as one user: `fetch` and nothing else, because what the log
3
+ * needs of it is a statement and its answer.
4
+ */
5
+ export declare class ClickHouse {
6
+ readonly database: string;
7
+ private readonly endpoint;
8
+ private readonly headers;
9
+ constructor(address: string, user: string, key: string);
10
+ /**
11
+ * A statement that answers nothing worth reading. `database` is the one it runs in, where that
12
+ * is not this client's: `''` for a statement that must run before the database exists.
13
+ */
14
+ run(sql: string, settings?: Record<string, string>, database?: string): Promise<void>;
15
+ /**
16
+ * A query, answered as `JSONCompact`: the columns, and the rows as arrays. The format is the
17
+ * default rather than a clause, which a statement like `EXPLAIN` would take as its own.
18
+ */
19
+ select(sql: string, settings?: Record<string, string>): Promise<Answer>;
20
+ /** Each row as an object, for what this extension reads of the database itself. */
21
+ rows<T = Record<string, unknown>>(sql: string): Promise<T[]>;
22
+ private request;
23
+ }
24
+ export interface Answer {
25
+ meta: Array<{
26
+ name: string;
27
+ type: string;
28
+ }>;
29
+ data: unknown[][];
30
+ rows: number;
31
+ }
32
+ /** What ClickHouse refused a statement with, as it said it. */
33
+ export declare class ClickHouseError extends Error {
34
+ readonly status: number;
35
+ /** ClickHouse's own code, where its message carries one */
36
+ readonly code: number | undefined;
37
+ constructor(status: number, message: string);
38
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * ClickHouse over its HTTP interface, as one user: `fetch` and nothing else, because what the log
3
+ * needs of it is a statement and its answer.
4
+ */
5
+ export class ClickHouse {
6
+ database;
7
+ endpoint;
8
+ headers;
9
+ constructor(address, user, key) {
10
+ const url = new URL(address);
11
+ this.database = decodeURIComponent(url.pathname.replace(/^\/+|\/+$/g, ''));
12
+ this.endpoint = `${url.protocol}//${url.host}/`;
13
+ this.headers = { 'x-clickhouse-user': user, 'x-clickhouse-key': key };
14
+ }
15
+ /**
16
+ * A statement that answers nothing worth reading. `database` is the one it runs in, where that
17
+ * is not this client's: `''` for a statement that must run before the database exists.
18
+ */
19
+ async run(sql, settings = {}, database = this.database) {
20
+ await this.request(sql, settings, database);
21
+ }
22
+ /**
23
+ * A query, answered as `JSONCompact`: the columns, and the rows as arrays. The format is the
24
+ * default rather than a clause, which a statement like `EXPLAIN` would take as its own.
25
+ */
26
+ async select(sql, settings = {}) {
27
+ const text = await this.request(sql, { ...settings, default_format: 'JSONCompact' });
28
+ return parse(text);
29
+ }
30
+ /** Each row as an object, for what this extension reads of the database itself. */
31
+ async rows(sql) {
32
+ const text = await this.request(sql, { ...NUMBERS, default_format: 'JSON' });
33
+ return parse(text).data;
34
+ }
35
+ async request(sql, settings, database = this.database) {
36
+ const search = new URLSearchParams(settings);
37
+ if (database !== '')
38
+ search.set('database', database);
39
+ const response = await fetch(`${this.endpoint}?${search.toString()}`, {
40
+ method: 'POST',
41
+ headers: this.headers,
42
+ body: sql
43
+ });
44
+ const text = await response.text();
45
+ if (!response.ok)
46
+ throw new ClickHouseError(response.status, text.trim());
47
+ return text;
48
+ }
49
+ }
50
+ /** What ClickHouse refused a statement with, as it said it. */
51
+ export class ClickHouseError extends Error {
52
+ status;
53
+ /** ClickHouse's own code, where its message carries one */
54
+ code;
55
+ constructor(status, message) {
56
+ super(message);
57
+ this.status = status;
58
+ const code = /^Code: (\d+)\./.exec(message)?.[1];
59
+ this.code = code === undefined ? undefined : Number(code);
60
+ }
61
+ }
62
+ /** An answer in another format is one the statement asked for itself, with a `FORMAT`. */
63
+ function parse(text) {
64
+ try {
65
+ return JSON.parse(text);
66
+ }
67
+ catch {
68
+ throw new ClickHouseError(200, 'The answer is not JSON: a statement leaves `FORMAT` out');
69
+ }
70
+ }
71
+ /** UInt64 as numbers rather than strings: what this extension reads of them is counts. */
72
+ const NUMBERS = { output_format_json_quote_64bit_integers: '0' };
73
+ //# sourceMappingURL=Client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Client.js","sourceRoot":"","sources":["../../source/clickhouse/Client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,UAAU;IACL,QAAQ,CAAQ;IAEf,QAAQ,CAAQ;IAChB,OAAO,CAAwB;IAEhD,YAAmB,OAAe,EAAE,IAAY,EAAE,GAAW;QAC3D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;QAE5B,IAAI,CAAC,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAA;QAC1E,IAAI,CAAC,QAAQ,GAAG,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,IAAI,GAAG,CAAA;QAC/C,IAAI,CAAC,OAAO,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,CAAA;IACvE,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,GAAG,CACd,GAAW,EACX,QAAQ,GAA2B,EAAE,EACrC,QAAQ,GAAG,IAAI,CAAC,QAAQ;QAExB,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAC7C,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAM,CACjB,GAAW,EACX,QAAQ,GAA2B,EAAE;QAErC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,CAAA;QAEpF,OAAO,KAAK,CAAC,IAAI,CAAW,CAAA;IAC9B,CAAC;IAED,mFAAmF;IAC5E,KAAK,CAAC,IAAI,CAA8B,GAAW;QACxD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAA;QAE5E,OAAQ,KAAK,CAAC,IAAI,CAAmB,CAAC,IAAI,CAAA;IAC5C,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,GAAW,EACX,QAAgC,EAChC,QAAQ,GAAG,IAAI,CAAC,QAAQ;QAExB,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAA;QAE5C,IAAI,QAAQ,KAAK,EAAE;YAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QAErD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,EAAE;YACpE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,GAAG;SACV,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAElC,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QAEzE,OAAO,IAAI,CAAA;IACb,CAAC;CACF;AAQD,+DAA+D;AAC/D,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxB,MAAM,CAAQ;IAE9B,2DAA2D;IAC3C,IAAI,CAAoB;IAExC,YAAmB,MAAc,EAAE,OAAe;QAChD,KAAK,CAAC,OAAO,CAAC,CAAA;QAEd,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QAEpB,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAEhD,IAAI,CAAC,IAAI,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC3D,CAAC;CACF;AAED,0FAA0F;AAC1F,SAAS,KAAK,CAAC,IAAY;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,eAAe,CACvB,GAAG,EACH,yDAAyD,CAC1D,CAAA;IACH,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,MAAM,OAAO,GAAG,EAAE,uCAAuC,EAAE,GAAG,EAAE,CAAA"}
@@ -0,0 +1,33 @@
1
+ import type { Label, Provider, Result, Row, State, Summary, View } from '../Provider.ts';
2
+ import type { Credentials } from '../settings.ts';
3
+ /**
4
+ * The log in ClickHouse: `events`, replaced by `id`, and `states`, by the `version` of an entity, both
5
+ * read with `FINAL`. Queries run as `<database>_reader`, which provisioning creates with limits it
6
+ * cannot lift; views are made by the writer from what the reader was let plan.
7
+ */
8
+ export declare class ClickHouseProvider implements Provider {
9
+ readonly dialect = "ClickHouse SQL; read `events` and `states` with FINAL";
10
+ readonly tables: string[];
11
+ private readonly writer;
12
+ private readonly reader;
13
+ private readonly password;
14
+ private readonly retention;
15
+ constructor(url: string, credentials: Credentials, retention?: number);
16
+ provision(): Promise<void>;
17
+ write(rows: Row[], states: State[]): Promise<void>;
18
+ states(): Promise<Summary[]>;
19
+ labels(): Promise<Label[]>;
20
+ /**
21
+ * One row more than is answered, cut by the `limit` setting — the result's own, outside whatever
22
+ * the statement says — so a result of the limit exactly reads as whole, and one past it as cut.
23
+ */
24
+ query(sql: string): Promise<Result>;
25
+ validate(sql: string): Promise<void>;
26
+ views(): Promise<View[]>;
27
+ define(name: string, sql: string, refresh?: number): Promise<void>;
28
+ drop(name: string): Promise<void>;
29
+ private insert;
30
+ /** In order, each awaited: a view is made after the table it reads. */
31
+ private run;
32
+ private engine;
33
+ }
@@ -0,0 +1,144 @@
1
+ import { console } from 'openspan';
2
+ import { ClickHouse, ClickHouseError } from './Client.js';
3
+ import * as ddl from './ddl.js';
4
+ import { Refusal } from '../Provider.js';
5
+ /**
6
+ * The log in ClickHouse: `events`, replaced by `id`, and `states`, by the `version` of an entity, both
7
+ * read with `FINAL`. Queries run as `<database>_reader`, which provisioning creates with limits it
8
+ * cannot lift; views are made by the writer from what the reader was let plan.
9
+ */
10
+ export class ClickHouseProvider {
11
+ dialect = 'ClickHouse SQL; read `events` and `states` with FINAL';
12
+ tables = ddl.TABLES;
13
+ writer;
14
+ reader;
15
+ password;
16
+ retention;
17
+ constructor(url, credentials, retention) {
18
+ this.writer = new ClickHouse(url, credentials.username, credentials.password);
19
+ this.reader = new ClickHouse(url, `${this.writer.database}_reader`, credentials.reader);
20
+ this.password = credentials.reader;
21
+ this.retention = retention;
22
+ }
23
+ async provision() {
24
+ const { database } = this.writer;
25
+ for (const statement of ddl.database(database))
26
+ await this.writer.run(statement, {}, '');
27
+ await this.run(ddl.tables(this.retention));
28
+ await this.run(ddl.retention(this.retention, await this.engine()));
29
+ await this.run(ddl.reader(database, this.password));
30
+ console.info('Chronicles provisioned', { database });
31
+ }
32
+ async write(rows, states) {
33
+ if (rows.length > 0)
34
+ await this.insert('events', EVENTS, rows);
35
+ if (states.length > 0)
36
+ await this.insert('states', STATES, states);
37
+ }
38
+ async states() {
39
+ return await this.writer.rows(`SELECT component, uniqExact(entity) AS entities,
40
+ arraySort(groupUniqArrayArray(JSONAllPaths(payload))) AS paths
41
+ FROM states GROUP BY component ORDER BY component`);
42
+ }
43
+ async labels() {
44
+ const labels = await this.writer.rows(`SELECT label, count() AS rows, toString(min(time)) AS first, toString(max(time)) AS last
45
+ FROM events GROUP BY label ORDER BY label`);
46
+ // the fields of the latest payloads of each label, which is what a query is written against
47
+ const paths = await this.writer.rows(`SELECT label, arraySort(groupUniqArrayArray(JSONAllPaths(payload))) AS paths
48
+ FROM (SELECT label, payload FROM events ORDER BY time DESC LIMIT ${SAMPLE} BY label)
49
+ GROUP BY label`);
50
+ const byLabel = new Map(paths.map(({ label, paths }) => [label, paths]));
51
+ return labels.map((label) => ({ ...label, paths: byLabel.get(label.label) ?? [] }));
52
+ }
53
+ /**
54
+ * One row more than is answered, cut by the `limit` setting — the result's own, outside whatever
55
+ * the statement says — so a result of the limit exactly reads as whole, and one past it as cut.
56
+ */
57
+ async query(sql) {
58
+ const settings = { ...NUMBERS, limit: String(ddl.LIMITS.rows + 1) };
59
+ const answer = await refusing(async () => await this.reader.select(sql, settings));
60
+ return {
61
+ columns: answer.meta,
62
+ rows: answer.data.slice(0, ddl.LIMITS.rows),
63
+ truncated: answer.data.length > ddl.LIMITS.rows
64
+ };
65
+ }
66
+ // parsed and planned as the reader, which is what refuses a view that reads what a query
67
+ // could not
68
+ async validate(sql) {
69
+ await refusing(async () => {
70
+ const [ast] = await this.reader.rows(`EXPLAIN AST ${sql}`);
71
+ if (!ast.explain.startsWith('SelectWithUnionQuery'))
72
+ throw new Refusal('A view is one SELECT');
73
+ await this.reader.run(`EXPLAIN PLAN ${sql}`);
74
+ });
75
+ }
76
+ async views() {
77
+ const tables = await this.writer.rows(`SELECT name, as_select, create_table_query FROM system.tables
78
+ WHERE database = currentDatabase()
79
+ AND name NOT IN (${this.tables.map(ddl.literal).join(', ')})
80
+ AND NOT startsWith(name, '.inner')
81
+ ORDER BY name`);
82
+ return tables.map((table) => {
83
+ const view = { name: table.name, sql: table.as_select };
84
+ // stated in seconds, and kept in the largest unit that divides them
85
+ const every = /REFRESH EVERY (\d+) (SECOND|MINUTE|HOUR|DAY|WEEK)/.exec(table.create_table_query);
86
+ if (every !== null)
87
+ view.refresh = Number(every[1]) * UNITS[every[2]];
88
+ return view;
89
+ });
90
+ }
91
+ async define(name, sql, refresh) {
92
+ await this.writer.run(`DROP TABLE IF EXISTS ${ddl.id(name)} SYNC`);
93
+ await refusing(async () => {
94
+ if (refresh === undefined)
95
+ await this.writer.run(`CREATE VIEW ${ddl.id(name)} SQL SECURITY INVOKER AS ${sql}`);
96
+ else
97
+ await this.writer.run(`CREATE MATERIALIZED VIEW ${ddl.id(name)} REFRESH EVERY ${refresh} SECOND
98
+ ENGINE = MergeTree ORDER BY tuple() AS ${sql}`);
99
+ });
100
+ }
101
+ async drop(name) {
102
+ await this.writer.run(`DROP TABLE IF EXISTS ${ddl.id(name)} SYNC`);
103
+ }
104
+ async insert(table, columns, rows) {
105
+ const lines = rows.map((row) => JSON.stringify({ ...row, time: timestamp(row.time) }));
106
+ await this.writer.run(`INSERT INTO ${table} (${columns}) FORMAT JSONEachRow\n${lines.join('\n')}`);
107
+ }
108
+ /** In order, each awaited: a view is made after the table it reads. */
109
+ async run(statements) {
110
+ for (const statement of statements)
111
+ await this.writer.run(statement);
112
+ }
113
+ async engine() {
114
+ const [table] = await this.writer.rows("SELECT engine_full FROM system.tables WHERE database = currentDatabase() AND name = 'events'");
115
+ return table?.engine_full ?? '';
116
+ }
117
+ }
118
+ /** What ClickHouse refused is the provider's refusal, in ClickHouse's words. */
119
+ async function refusing(fn) {
120
+ try {
121
+ return await fn();
122
+ }
123
+ catch (exception) {
124
+ if (exception instanceof ClickHouseError)
125
+ throw new Refusal(exception.message);
126
+ throw exception;
127
+ }
128
+ }
129
+ /** A `DateTime64(3)` as ClickHouse reads one without guessing: UTC, to the millisecond. */
130
+ function timestamp(ms) {
131
+ return new Date(ms).toISOString().replace('T', ' ').replace('Z', '');
132
+ }
133
+ const EVENTS = 'id, label, component, time, entity, version, identity, ip, country, trace, payload';
134
+ const STATES = 'component, entity, version, identity, time, payload';
135
+ const UNITS = {
136
+ SECOND: 1,
137
+ MINUTE: 60,
138
+ HOUR: 3600,
139
+ DAY: 86400,
140
+ WEEK: 604800
141
+ };
142
+ const SAMPLE = 1000;
143
+ const NUMBERS = { output_format_json_quote_64bit_integers: '0' };
144
+ //# sourceMappingURL=Provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Provider.js","sourceRoot":"","sources":["../../source/clickhouse/Provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The log in ClickHouse. Every statement is one a second start changes nothing with, so two
3
+ * replicas starting together collide on nothing; the retention, which would change, is compared
4
+ * with what is there and changed only where it differs.
5
+ */
6
+ export declare const TABLES: string[];
7
+ export declare function database(name: string): string[];
8
+ /** What is kept: a row for everything that happened, and each entity as it stands. */
9
+ export declare function tables(retention: number | undefined): string[];
10
+ /** `ALTER TABLE` for the retention declared, given what the table states now; none if it agrees. */
11
+ export declare function retention(declared: number | undefined, engine: string): string[];
12
+ /**
13
+ * The user queries run as: it reads the database and nothing else, under limits a query cannot
14
+ * lift, because they are constraints of its profile rather than settings a request passes. Past
15
+ * the rows a query is refused, which is the overflow a client's query cache allows; a query of
16
+ * the provider's own asks for one row more than it answers, to tell a full answer from a cut one.
17
+ */
18
+ export declare function reader(database: string, password: string): string[];
19
+ export declare const LIMITS: {
20
+ seconds: number;
21
+ rows: number;
22
+ memory: number;
23
+ };
24
+ /** An identifier, which the annotation and the schema have already held to this. */
25
+ export declare function id(name: string): string;
26
+ export declare function literal(value: string): string;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The log in ClickHouse. Every statement is one a second start changes nothing with, so two
3
+ * replicas starting together collide on nothing; the retention, which would change, is compared
4
+ * with what is there and changed only where it differs.
5
+ */
6
+ export const TABLES = ['events', 'states'];
7
+ export function database(name) {
8
+ return [`CREATE DATABASE IF NOT EXISTS ${id(name)}`];
9
+ }
10
+ /** What is kept: a row for everything that happened, and each entity as it stands. */
11
+ export function tables(retention) {
12
+ return [
13
+ `CREATE TABLE IF NOT EXISTS events (
14
+ id String,
15
+ label LowCardinality(String),
16
+ component LowCardinality(String),
17
+ time DateTime64(3, 'UTC'),
18
+ received DateTime64(3, 'UTC') DEFAULT now64(3),
19
+ entity Nullable(String),
20
+ version Nullable(UInt64),
21
+ identity Nullable(String),
22
+ ip Nullable(String),
23
+ country LowCardinality(Nullable(String)),
24
+ trace Nullable(String),
25
+ payload JSON
26
+ ) ENGINE = ReplacingMergeTree
27
+ PARTITION BY toYYYYMM(time)
28
+ ORDER BY (label, toDate(time), id)
29
+ ${retention === undefined ? '' : ttl(retention)}`,
30
+ `CREATE TABLE IF NOT EXISTS states (
31
+ component LowCardinality(String),
32
+ entity String,
33
+ version UInt64,
34
+ identity Nullable(String),
35
+ time DateTime64(3, 'UTC'),
36
+ received DateTime64(3, 'UTC') DEFAULT now64(3),
37
+ payload JSON
38
+ ) ENGINE = ReplacingMergeTree(version)
39
+ ORDER BY (component, entity)`
40
+ ];
41
+ }
42
+ /** `ALTER TABLE` for the retention declared, given what the table states now; none if it agrees. */
43
+ export function retention(declared, engine) {
44
+ const stated = /TTL toDateTime\(time\) \+ toIntervalDay\((\d+)\)/.exec(engine)?.[1];
45
+ if (declared === undefined)
46
+ return stated === undefined && !engine.includes(' TTL ')
47
+ ? []
48
+ : ['ALTER TABLE events REMOVE TTL'];
49
+ if (stated === String(declared))
50
+ return [];
51
+ return [`ALTER TABLE events MODIFY ${ttl(declared)}`];
52
+ }
53
+ /**
54
+ * The user queries run as: it reads the database and nothing else, under limits a query cannot
55
+ * lift, because they are constraints of its profile rather than settings a request passes. Past
56
+ * the rows a query is refused, which is the overflow a client's query cache allows; a query of
57
+ * the provider's own asks for one row more than it answers, to tell a full answer from a cut one.
58
+ */
59
+ export function reader(database, password) {
60
+ const name = id(`${database}_reader`);
61
+ return [
62
+ `CREATE SETTINGS PROFILE IF NOT EXISTS ${name}`,
63
+ `ALTER SETTINGS PROFILE ${name} SETTINGS
64
+ readonly = 2 CONST,
65
+ max_execution_time = ${LIMITS.seconds} CONST,
66
+ max_result_rows = ${LIMITS.rows + 1} CONST,
67
+ max_memory_usage = ${LIMITS.memory} CONST`,
68
+ `CREATE USER IF NOT EXISTS ${name} IDENTIFIED WITH sha256_password BY ${literal(password)}`,
69
+ `ALTER USER ${name} IDENTIFIED WITH sha256_password BY ${literal(password)}
70
+ SETTINGS PROFILE ${literal(`${database}_reader`)}`,
71
+ `GRANT SELECT ON ${id(database)}.* TO ${name}`
72
+ ];
73
+ }
74
+ export const LIMITS = { seconds: 30, rows: 10_000, memory: 4_000_000_000 };
75
+ /** An identifier, which the annotation and the schema have already held to this. */
76
+ export function id(name) {
77
+ if (!IDENTIFIER.test(name))
78
+ throw new Error(`'${name}' is not a ClickHouse identifier chronicles accept`);
79
+ return '`' + name + '`';
80
+ }
81
+ export function literal(value) {
82
+ return "'" + value.replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'";
83
+ }
84
+ function ttl(days) {
85
+ return `TTL toDateTime(time) + INTERVAL ${days} DAY`;
86
+ }
87
+ const IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
88
+ //# sourceMappingURL=ddl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ddl.js","sourceRoot":"","sources":["../../source/clickhouse/ddl.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;AAE1C,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,CAAC,iCAAiC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACtD,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,MAAM,CAAC,SAA6B;IAClD,OAAO;QACL;;;;;;;;;;;;;;;;MAgBE,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;QAEjD;;;;;;;;;iCAS6B;KAC9B,CAAA;AACH,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,SAAS,CAAC,QAA4B,EAAE,MAAc;IACpE,MAAM,MAAM,GAAG,kDAAkD,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAEnF,IAAI,QAAQ,KAAK,SAAS;QACxB,OAAO,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;YACtD,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAA;IAEvC,IAAI,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAA;IAE1C,OAAO,CAAC,6BAA6B,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,QAAgB,EAAE,QAAgB;IACvD,MAAM,IAAI,GAAG,EAAE,CAAC,GAAG,QAAQ,SAAS,CAAC,CAAA;IAErC,OAAO;QACL,yCAAyC,IAAI,EAAE;QAC/C,0BAA0B,IAAI;;6BAEL,MAAM,CAAC,OAAO;0BACjB,MAAM,CAAC,IAAI,GAAG,CAAC;2BACd,MAAM,CAAC,MAAM,QAAQ;QAC5C,6BAA6B,IAAI,uCAAuC,OAAO,CAAC,QAAQ,CAAC,EAAE;QAC3F,cAAc,IAAI,uCAAuC,OAAO,CAAC,QAAQ,CAAC;yBACrD,OAAO,CAAC,GAAG,QAAQ,SAAS,CAAC,EAAE;QACpD,mBAAmB,EAAE,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE;KAC/C,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,CAAA;AAE1E,oFAAoF;AACpF,MAAM,UAAU,EAAE,CAAC,IAAY;IAC7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,oDAAoD,CAAC,CAAA;IAE/E,OAAO,GAAG,GAAG,IAAI,GAAG,GAAG,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,GAAG,CAAA;AACtE,CAAC;AAED,SAAS,GAAG,CAAC,IAAY;IACvB,OAAO,mCAAmC,IAAI,MAAM,CAAA;AACtD,CAAC;AAED,MAAM,UAAU,GAAG,0BAA0B,CAAA"}
@@ -0,0 +1,9 @@
1
+ export { Factory } from './Factory.ts';
2
+ /** `context.chronicles` of a component that declares `chronicles`. */
3
+ export interface Chronicles {
4
+ /**
5
+ * Writes a fact that changes no state to the log, under `<component>.<name>`. Resolves once the
6
+ * broker has it; nothing retries it.
7
+ */
8
+ send(name: string, payload?: object): Promise<void>;
9
+ }
@@ -0,0 +1,2 @@
1
+ export { Factory } from './Factory.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,11 @@
1
+ import type { Settings } from '@toa.io/definitions/extensions.chronicles';
2
+ /** Where the log is kept and what it is kept of, as the service is deployed with them. */
3
+ export declare function settings(): Settings;
4
+ /** The user the store is provisioned as, and the password of the reader it creates. */
5
+ export declare function credentials(): Credentials;
6
+ export interface Credentials {
7
+ username: string;
8
+ password: string;
9
+ /** the password of the reader */
10
+ reader: string;
11
+ }
@@ -0,0 +1,35 @@
1
+ import { environment } from '@toa.io/generic';
2
+ import { SETTINGS } from '@toa.io/definitions/extensions.chronicles';
3
+ /** Where the log is kept and what it is kept of, as the service is deployed with them. */
4
+ export function settings() {
5
+ const value = environment.get(SETTINGS);
6
+ if (value !== undefined)
7
+ return JSON.parse(value);
8
+ if (dev())
9
+ return DEV;
10
+ throw new Error(`${SETTINGS} is not set, so nothing says where the log is kept.`);
11
+ }
12
+ /** The user the store is provisioned as, and the password of the reader it creates. */
13
+ export function credentials() {
14
+ const [username, password, reader] = KEYS.map((key) => environment.get(`${SETTINGS}_STORE_${key}`));
15
+ if (username !== undefined && password !== undefined && reader !== undefined)
16
+ return { username, password, reader };
17
+ if (dev())
18
+ return { username: 'developer', password: 'secret', reader: 'secret' };
19
+ throw new Error(`${SETTINGS}_STORE_{USERNAME,PASSWORD,READER} are not all set.`);
20
+ }
21
+ function dev() {
22
+ return environment.get('TOA_DEV') === '1';
23
+ }
24
+ const KEYS = ['USERNAME', 'PASSWORD', 'READER'];
25
+ // Toa's own development stack is not on the conventional ports, which the applications built on
26
+ // Toa are on. See CONTRIBUTING.md.
27
+ const DEV = {
28
+ store: { provider: 'clickhouse', url: 'http://localhost:31030/chronicles' },
29
+ ingest: true,
30
+ ip: 'truncated',
31
+ events: [],
32
+ states: [],
33
+ identities: {}
34
+ };
35
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../source/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,2CAA2C,CAAA;AAGpE,0FAA0F;AAC1F,MAAM,UAAU,QAAQ;IACtB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAEvC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAa,CAAA;IAE7D,IAAI,GAAG,EAAE;QAAE,OAAO,GAAG,CAAA;IAErB,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,qDAAqD,CAAC,CAAA;AACnF,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,WAAW;IACzB,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACpD,WAAW,CAAC,GAAG,CAAC,GAAG,QAAQ,UAAU,GAAG,EAAE,CAAC,CAC5C,CAAA;IAED,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QAC1E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;IAEvC,IAAI,GAAG,EAAE;QAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;IAEjF,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,oDAAoD,CAAC,CAAA;AAClF,CAAC;AAUD,SAAS,GAAG;IACV,OAAO,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,GAAG,CAAA;AAC3C,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;AAE/C,gGAAgG;AAChG,mCAAmC;AACnC,MAAM,GAAG,GAAa;IACpB,KAAK,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,mCAAmC,EAAE;IAC3E,MAAM,EAAE,IAAI;IACZ,EAAE,EAAE,WAAW;IACf,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,EAAE;IACV,UAAU,EAAE,EAAE;CACf,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { Provider } from './Provider.ts';
2
+ import type { Credentials } from './settings.ts';
3
+ import type { Settings } from '@toa.io/definitions/extensions.chronicles';
4
+ /** The provider the annotation names. */
5
+ export declare function provider(settings: Settings, credentials: Credentials): Provider;
@@ -0,0 +1,11 @@
1
+ import { ClickHouseProvider } from './clickhouse/Provider.js';
2
+ /** The provider the annotation names. */
3
+ export function provider(settings, credentials) {
4
+ switch (settings.store.provider) {
5
+ case 'clickhouse':
6
+ return new ClickHouseProvider(settings.store.url, credentials, settings.retention);
7
+ default:
8
+ throw new Error(`Chronicles have no store '${String(settings.store.provider)}'`);
9
+ }
10
+ }
11
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../source/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAK7D,yCAAyC;AACzC,MAAM,UAAU,QAAQ,CAAC,QAAkB,EAAE,WAAwB;IACnE,QAAQ,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAChC,KAAK,YAAY;YACf,OAAO,IAAI,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAA;QACpF;YACE,MAAM,IAAI,KAAK,CAAC,6BAA6B,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;IACpF,CAAC;AACH,CAAC"}
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.