@owlmeans/planning-postgres 0.1.18-rc.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.
- package/README.md +88 -0
- package/agent-meta/manifest.json +16 -0
- package/agent-meta/skills/planning-postgres/SKILL.md +292 -0
- package/build/consts.d.ts +45 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +45 -0
- package/build/consts.js.map +1 -0
- package/build/errors.d.ts +10 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +13 -0
- package/build/errors.js.map +1 -0
- package/build/index.d.ts +9 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +8 -0
- package/build/index.js.map +1 -0
- package/build/resource.d.ts +32 -0
- package/build/resource.d.ts.map +1 -0
- package/build/resource.js +94 -0
- package/build/resource.js.map +1 -0
- package/build/schemas.d.ts +20 -0
- package/build/schemas.d.ts.map +1 -0
- package/build/schemas.js +64 -0
- package/build/schemas.js.map +1 -0
- package/build/service.d.ts +16 -0
- package/build/service.d.ts.map +1 -0
- package/build/service.js +34 -0
- package/build/service.js.map +1 -0
- package/build/sql.d.ts +61 -0
- package/build/sql.d.ts.map +1 -0
- package/build/sql.js +90 -0
- package/build/sql.js.map +1 -0
- package/build/store/bus.d.ts +52 -0
- package/build/store/bus.d.ts.map +1 -0
- package/build/store/bus.js +167 -0
- package/build/store/bus.js.map +1 -0
- package/build/store/cards.d.ts +35 -0
- package/build/store/cards.d.ts.map +1 -0
- package/build/store/cards.js +112 -0
- package/build/store/cards.js.map +1 -0
- package/build/store/fold.d.ts +56 -0
- package/build/store/fold.d.ts.map +1 -0
- package/build/store/fold.js +453 -0
- package/build/store/fold.js.map +1 -0
- package/build/store/index.d.ts +22 -0
- package/build/store/index.d.ts.map +1 -0
- package/build/store/index.js +206 -0
- package/build/store/index.js.map +1 -0
- package/build/store/links.d.ts +18 -0
- package/build/store/links.d.ts.map +1 -0
- package/build/store/links.js +54 -0
- package/build/store/links.js.map +1 -0
- package/build/store/schemas.d.ts +32 -0
- package/build/store/schemas.d.ts.map +1 -0
- package/build/store/schemas.js +143 -0
- package/build/store/schemas.js.map +1 -0
- package/build/store/specs.d.ts +10 -0
- package/build/store/specs.d.ts.map +1 -0
- package/build/store/specs.js +47 -0
- package/build/store/specs.js.map +1 -0
- package/build/store/transitions.d.ts +44 -0
- package/build/store/transitions.d.ts.map +1 -0
- package/build/store/transitions.js +164 -0
- package/build/store/transitions.js.map +1 -0
- package/build/types.d.ts +72 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +56 -0
- package/src/consts.ts +54 -0
- package/src/errors.ts +15 -0
- package/src/index.ts +9 -0
- package/src/resource.ts +133 -0
- package/src/schemas.ts +84 -0
- package/src/service.ts +45 -0
- package/src/sql.ts +135 -0
- package/src/store/bus.ts +217 -0
- package/src/store/cards.ts +153 -0
- package/src/store/fold.ts +560 -0
- package/src/store/index.ts +237 -0
- package/src/store/links.ts +77 -0
- package/src/store/schemas.ts +174 -0
- package/src/store/specs.ts +72 -0
- package/src/store/transitions.ts +221 -0
- package/src/types.ts +73 -0
- package/tests/bus.spec.ts +142 -0
- package/tests/conformance.spec.ts +37 -0
- package/tests/context.ts +143 -0
- package/tests/fold.spec.ts +213 -0
- package/tests/schema.spec.ts +89 -0
- package/tests/sql.spec.ts +50 -0
- package/tests/sync.spec.ts +61 -0
- package/tests/tsconfig.json +17 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { uuid } from '@owlmeans/basic-ids';
|
|
2
|
+
import { CommitState, TransitionAction } from '@owlmeans/planning';
|
|
3
|
+
import { makeCommitHub } from '@owlmeans/server-planning/store';
|
|
4
|
+
import { DEFAULT_PLANNING_POSTGRES_LIMITS, PLANNING_POSTGRES_STORE, PLANNING_RESOURCE_FILES, RES_PLANNING_CARD, RES_PLANNING_LINK, RES_PLANNING_SCHEMA, RES_PLANNING_TRANSITION, } from '../consts.js';
|
|
5
|
+
import { PlanningPostgresError } from '../errors.js';
|
|
6
|
+
import { planningIndexName } from '../resource.js';
|
|
7
|
+
import { poolRunner } from '../sql.js';
|
|
8
|
+
import { makePlanningBus } from './bus.js';
|
|
9
|
+
import { makeCardPort, readCard } from './cards.js';
|
|
10
|
+
import { makeFoldEngine } from './fold.js';
|
|
11
|
+
import { makeLinkPort } from './links.js';
|
|
12
|
+
import { makeSchemaPort } from './schemas.js';
|
|
13
|
+
import { makeSpecPort } from './specs.js';
|
|
14
|
+
import { makeTransitionPort, readTransition } from './transitions.js';
|
|
15
|
+
export * from './bus.js';
|
|
16
|
+
export * from './cards.js';
|
|
17
|
+
export * from './fold.js';
|
|
18
|
+
export * from './links.js';
|
|
19
|
+
export * from './schemas.js';
|
|
20
|
+
export * from './specs.js';
|
|
21
|
+
export * from './transitions.js';
|
|
22
|
+
const isoNow = () => new Date().toISOString();
|
|
23
|
+
/** The aliases a store resolves, each defaulting to the package's own resource alias. */
|
|
24
|
+
export const planningPostgresAliases = (aliases) => ({
|
|
25
|
+
card: aliases?.card ?? RES_PLANNING_CARD,
|
|
26
|
+
transition: aliases?.transition ?? RES_PLANNING_TRANSITION,
|
|
27
|
+
link: aliases?.link ?? RES_PLANNING_LINK,
|
|
28
|
+
schema: aliases?.schema ?? RES_PLANNING_SCHEMA,
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* The Postgres `PlanningStore`: four tables, an inline fold (one transaction per card under its
|
|
32
|
+
* advisory lock), the commit hub fed by the fold and by a LISTEN/NOTIFY bus, and the data-defined
|
|
33
|
+
* schema port.
|
|
34
|
+
*
|
|
35
|
+
* Nothing is resolved at construction: the resources are looked up on the context at the first
|
|
36
|
+
* call — which also runs one `recover()` in the background — so the store can be handed to the
|
|
37
|
+
* planning service before the context initializes. A resource the context does not have is refused
|
|
38
|
+
* with the file a target adds for it.
|
|
39
|
+
*/
|
|
40
|
+
export const makePostgresPlanningStore = (opts) => {
|
|
41
|
+
const aliases = planningPostgresAliases(opts.aliases);
|
|
42
|
+
const limits = { ...DEFAULT_PLANNING_POSTGRES_LIMITS, ...(opts.limits ?? {}) };
|
|
43
|
+
const ids = opts.ids ?? uuid;
|
|
44
|
+
const now = opts.now ?? isoNow;
|
|
45
|
+
const processId = uuid();
|
|
46
|
+
let committed;
|
|
47
|
+
let closed = false;
|
|
48
|
+
const resourceOf = (kind) => () => {
|
|
49
|
+
const context = opts.context();
|
|
50
|
+
const alias = aliases[kind];
|
|
51
|
+
if (context == null) {
|
|
52
|
+
throw new PlanningPostgresError(`context-missing:${alias}`);
|
|
53
|
+
}
|
|
54
|
+
if (!context.hasResource(alias)) {
|
|
55
|
+
throw new PlanningPostgresError(`resource-missing:${alias}: add ${PLANNING_RESOURCE_FILES[kind]}`);
|
|
56
|
+
}
|
|
57
|
+
return context.resource(alias);
|
|
58
|
+
};
|
|
59
|
+
const resources = {
|
|
60
|
+
card: resourceOf('card'),
|
|
61
|
+
transition: resourceOf('transition'),
|
|
62
|
+
link: resourceOf('link'),
|
|
63
|
+
schema: resourceOf('schema'),
|
|
64
|
+
};
|
|
65
|
+
let ready;
|
|
66
|
+
let recovered = false;
|
|
67
|
+
const tables = () => {
|
|
68
|
+
ready ??= (async () => {
|
|
69
|
+
const resolved = [resources.card(), resources.transition(), resources.link(), resources.schema()];
|
|
70
|
+
// A resource registered after the context initialized is initialized here, once.
|
|
71
|
+
await Promise.all(resolved.map(async (resource) => { await resource.queryOne('SELECT 1'); }));
|
|
72
|
+
const [card, transition, link, schema] = resolved.map(resource => resource.table);
|
|
73
|
+
return { card, transition, link, schema };
|
|
74
|
+
})();
|
|
75
|
+
const pending = ready;
|
|
76
|
+
pending.then(() => {
|
|
77
|
+
if (!recovered && !closed) {
|
|
78
|
+
recovered = true;
|
|
79
|
+
void engine.recover().catch(error => {
|
|
80
|
+
if (!closed) {
|
|
81
|
+
console.error('planning-postgres: recovery on first use failed:', error);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}, () => {
|
|
86
|
+
// A failed resolution (a missing resource) is asked again by the next call.
|
|
87
|
+
if (ready === pending) {
|
|
88
|
+
ready = undefined;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return pending;
|
|
92
|
+
};
|
|
93
|
+
const pool = async () => (await resources.card().db()).pool;
|
|
94
|
+
const sql = async () => ({ runner: poolRunner(await pool()), tables: await tables() });
|
|
95
|
+
const schemaWatchers = new Set();
|
|
96
|
+
const touched = (entityId) => {
|
|
97
|
+
for (const watcher of [...schemaWatchers]) {
|
|
98
|
+
try {
|
|
99
|
+
watcher(entityId);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.error('planning-postgres: schema watcher failed:', error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const bus = makePlanningBus({
|
|
107
|
+
enabled: opts.bus !== false,
|
|
108
|
+
processId,
|
|
109
|
+
table: async () => (await tables()).transition.qualified,
|
|
110
|
+
pool,
|
|
111
|
+
});
|
|
112
|
+
const statusOf = async (transition) => {
|
|
113
|
+
const context = await sql();
|
|
114
|
+
const row = await readTransition(context, transition);
|
|
115
|
+
if (row == null) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const status = { transition, state: row.commit.state };
|
|
119
|
+
if (row.commit.at != null) {
|
|
120
|
+
status.at = row.commit.at;
|
|
121
|
+
}
|
|
122
|
+
if (row.commit.error != null) {
|
|
123
|
+
status.error = row.commit.error;
|
|
124
|
+
}
|
|
125
|
+
if (row.commit.state === CommitState.Pending && Date.now() - Date.parse(row.at) > limits.healAfterMs) {
|
|
126
|
+
// Every waiter is a healer: a commit left pending by a lost fold is folded again.
|
|
127
|
+
engine.heal(row.card);
|
|
128
|
+
}
|
|
129
|
+
if (row.commit.state === CommitState.Committed) {
|
|
130
|
+
status.card = row.action === TransitionAction.Delete ? null : await readCard(context, row.card, row.entityId);
|
|
131
|
+
}
|
|
132
|
+
return status;
|
|
133
|
+
};
|
|
134
|
+
const hub = makeCommitHub({ status: statusOf });
|
|
135
|
+
bus.onCommit(async (event) => { await hub.publish(event); });
|
|
136
|
+
bus.onSchema(touched);
|
|
137
|
+
const engine = makeFoldEngine({
|
|
138
|
+
pool,
|
|
139
|
+
tables,
|
|
140
|
+
limits,
|
|
141
|
+
ids,
|
|
142
|
+
now,
|
|
143
|
+
bus,
|
|
144
|
+
hub,
|
|
145
|
+
committed: () => committed,
|
|
146
|
+
schemasTouched: touched,
|
|
147
|
+
closed: () => closed,
|
|
148
|
+
});
|
|
149
|
+
const commits = {
|
|
150
|
+
...hub,
|
|
151
|
+
subscribe: (listener, filter) => {
|
|
152
|
+
bus.ensure();
|
|
153
|
+
return hub.subscribe(listener, filter);
|
|
154
|
+
},
|
|
155
|
+
wait: async (transition, waitOpts) => {
|
|
156
|
+
bus.ensure();
|
|
157
|
+
return await hub.wait(transition, waitOpts);
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
const indexes = async () => {
|
|
161
|
+
await tables();
|
|
162
|
+
return {
|
|
163
|
+
cardSeq: planningIndexName(aliases.transition, 'card_seq'),
|
|
164
|
+
entityKey: planningIndexName(aliases.transition, 'entity_key'),
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
const store = {
|
|
168
|
+
alias: PLANNING_POSTGRES_STORE,
|
|
169
|
+
capabilities: { transitions: true, sync: true, purge: true, revisions: true },
|
|
170
|
+
newId: ids,
|
|
171
|
+
transitions: makeTransitionPort({ sql, resource: resources.transition, ids, now, indexes }),
|
|
172
|
+
cards: makeCardPort({
|
|
173
|
+
sql,
|
|
174
|
+
resource: resources.card,
|
|
175
|
+
project: async (card) => { await engine.fold(card); },
|
|
176
|
+
purge: engine.purge,
|
|
177
|
+
}),
|
|
178
|
+
specs: makeSpecPort({ sql, resource: resources.card }),
|
|
179
|
+
links: makeLinkPort({ sql, resource: resources.link, ids }),
|
|
180
|
+
commits,
|
|
181
|
+
schemas: makeSchemaPort({
|
|
182
|
+
sql,
|
|
183
|
+
pool,
|
|
184
|
+
tables,
|
|
185
|
+
bus,
|
|
186
|
+
ids,
|
|
187
|
+
now,
|
|
188
|
+
touched,
|
|
189
|
+
watch: listener => {
|
|
190
|
+
bus.ensure();
|
|
191
|
+
schemaWatchers.add(listener);
|
|
192
|
+
const unsubscribe = () => { schemaWatchers.delete(listener); };
|
|
193
|
+
return unsubscribe;
|
|
194
|
+
},
|
|
195
|
+
}),
|
|
196
|
+
bind: listener => { committed = listener; },
|
|
197
|
+
fold: async (cardId) => await engine.fold(cardId),
|
|
198
|
+
recover: async (recoverOpts) => await engine.recover(recoverOpts),
|
|
199
|
+
close: async () => {
|
|
200
|
+
closed = true;
|
|
201
|
+
await bus.close();
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
return store;
|
|
205
|
+
};
|
|
206
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Relationship, RelationshipStore, RelationshipWhere } from '@owlmeans/planning';
|
|
2
|
+
import type { Criteria, ListResult } from '@owlmeans/resource';
|
|
3
|
+
import type { SqlContext } from '../sql.js';
|
|
4
|
+
import type { PlanningLinkResource } from '../types.js';
|
|
5
|
+
export declare const linkCriteria: (where: RelationshipWhere) => Criteria<Relationship>;
|
|
6
|
+
/** Edges by fixed fields — this package's own statement, so it runs inside a fold's transaction. */
|
|
7
|
+
export declare const listLinks: (sql: SqlContext, where: RelationshipWhere) => Promise<ListResult<Relationship>>;
|
|
8
|
+
/** One edge per `(from, to, type)`: an existing one is answered as it is. */
|
|
9
|
+
export declare const putLink: (sql: SqlContext, link: Relationship, id: () => string) => Promise<Relationship>;
|
|
10
|
+
/** @throws {PlanningError} `links:drop-empty` for a where naming nothing but the organization */
|
|
11
|
+
export declare const dropLinks: (sql: SqlContext, where: RelationshipWhere) => Promise<number>;
|
|
12
|
+
export interface LinkPortDeps {
|
|
13
|
+
sql: () => Promise<SqlContext>;
|
|
14
|
+
resource: () => PlanningLinkResource;
|
|
15
|
+
ids: () => string;
|
|
16
|
+
}
|
|
17
|
+
export declare const makeLinkPort: (deps: LinkPortDeps) => RelationshipStore;
|
|
18
|
+
//# sourceMappingURL=links.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/store/links.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC5F,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAKvD,eAAO,MAAM,YAAY,UAAW,iBAAiB,KAAG,QAAQ,CAAC,YAAY,CAOjD,CAAA;AAM5B,oGAAoG;AACpG,eAAO,MAAM,SAAS,QAAe,UAAU,SAAS,iBAAiB,KAAG,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAQ3G,CAAA;AAED,6EAA6E;AAC7E,eAAO,MAAM,OAAO,QAAe,UAAU,QAAQ,YAAY,MAAM,MAAM,MAAM,KAAG,OAAO,CAAC,YAAY,CAWzG,CAAA;AAED,iGAAiG;AACjG,eAAO,MAAM,SAAS,QAAe,UAAU,SAAS,iBAAiB,KAAG,OAAO,CAAC,MAAM,CASzF,CAAA;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAA;IAC9B,QAAQ,EAAE,MAAM,oBAAoB,CAAA;IACpC,GAAG,EAAE,MAAM,MAAM,CAAA;CAClB;AAED,eAAO,MAAM,YAAY,SAAU,YAAY,KAAG,iBAUhD,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { PlanningError } from '@owlmeans/planning';
|
|
2
|
+
import { cleanRecord, col, insertOf, recordOf, whereOf } from '../sql.js';
|
|
3
|
+
const clean = (record) => Object.fromEntries(Object.entries(record).filter(([, value]) => value !== undefined));
|
|
4
|
+
export const linkCriteria = (where) => clean({
|
|
5
|
+
entityId: where.entityId,
|
|
6
|
+
id: where.id,
|
|
7
|
+
from: where.from,
|
|
8
|
+
to: where.to,
|
|
9
|
+
type: where.type,
|
|
10
|
+
project: where.project,
|
|
11
|
+
});
|
|
12
|
+
const fixed = (where) => ({
|
|
13
|
+
entityId: where.entityId, id: where.id, from: where.from, to: where.to, type: where.type, project: where.project,
|
|
14
|
+
});
|
|
15
|
+
/** Edges by fixed fields — this package's own statement, so it runs inside a fold's transaction. */
|
|
16
|
+
export const listLinks = async (sql, where) => {
|
|
17
|
+
const spec = sql.tables.link;
|
|
18
|
+
const condition = whereOf(spec, fixed(where));
|
|
19
|
+
const rows = await sql.runner.query(`SELECT * FROM ${spec.qualified} WHERE ${condition.text} ORDER BY ${col(spec, 'createdAt')}, ${col(spec, 'id')}`, condition.params);
|
|
20
|
+
const items = rows.map(row => recordOf(row, spec));
|
|
21
|
+
return { items, total: items.length };
|
|
22
|
+
};
|
|
23
|
+
/** One edge per `(from, to, type)`: an existing one is answered as it is. */
|
|
24
|
+
export const putLink = async (sql, link, id) => {
|
|
25
|
+
const spec = sql.tables.link;
|
|
26
|
+
const statement = insertOf(spec, { ...link, id: link.id ?? id() }, {
|
|
27
|
+
tail: `ON CONFLICT (${col(spec, 'from')}, ${col(spec, 'to')}, ${col(spec, 'type')}) DO NOTHING RETURNING *`,
|
|
28
|
+
});
|
|
29
|
+
const inserted = await sql.runner.query(statement.text, statement.params);
|
|
30
|
+
if (inserted[0] != null) {
|
|
31
|
+
return recordOf(inserted[0], spec);
|
|
32
|
+
}
|
|
33
|
+
const existing = await listLinks(sql, { entityId: link.entityId, from: link.from, to: link.to, type: link.type });
|
|
34
|
+
return existing.items[0] ?? link;
|
|
35
|
+
};
|
|
36
|
+
/** @throws {PlanningError} `links:drop-empty` for a where naming nothing but the organization */
|
|
37
|
+
export const dropLinks = async (sql, where) => {
|
|
38
|
+
if (where.id == null && where.from == null && where.to == null && where.type == null && where.project == null) {
|
|
39
|
+
throw new PlanningError('links:drop-empty');
|
|
40
|
+
}
|
|
41
|
+
const spec = sql.tables.link;
|
|
42
|
+
const condition = whereOf(spec, fixed(where));
|
|
43
|
+
return (await sql.runner.query(`DELETE FROM ${spec.qualified} WHERE ${condition.text} RETURNING ${col(spec, 'id')}`, condition.params)).length;
|
|
44
|
+
};
|
|
45
|
+
export const makeLinkPort = (deps) => ({
|
|
46
|
+
list: async (where, opts) => {
|
|
47
|
+
await deps.sql();
|
|
48
|
+
const listed = await deps.resource().list(linkCriteria(where), opts);
|
|
49
|
+
return { ...listed, items: listed.items.map(item => cleanRecord(item)) };
|
|
50
|
+
},
|
|
51
|
+
put: async (link) => await putLink(await deps.sql(), link, deps.ids),
|
|
52
|
+
drop: async (where) => await dropLinks(await deps.sql(), where),
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/store/links.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SchemaStore, Unsubscribe } from '@owlmeans/planning';
|
|
2
|
+
import type { Pool } from 'pg';
|
|
3
|
+
import type { PlanningTables, SqlContext } from '../sql.js';
|
|
4
|
+
import type { PlanningBus } from './bus.js';
|
|
5
|
+
/**
|
|
6
|
+
* Bump an organization's schema revision — its private `head` row, created at 1 — and answer the
|
|
7
|
+
* new value. Runs inside the write's own transaction, so the revision moves exactly when it commits.
|
|
8
|
+
*/
|
|
9
|
+
export declare const bumpRevision: (sql: SqlContext, entityId: string, at: string, id: () => string) => Promise<number>;
|
|
10
|
+
/** Remove the layers of the given projects inside a transaction; answers how many records went. */
|
|
11
|
+
export declare const purgeSchemaLayers: (sql: SqlContext, entityId: string, projects: readonly string[]) => Promise<number>;
|
|
12
|
+
export interface SchemaPortDeps {
|
|
13
|
+
sql: () => Promise<SqlContext>;
|
|
14
|
+
pool: () => Promise<Pool>;
|
|
15
|
+
tables: () => Promise<PlanningTables>;
|
|
16
|
+
bus: PlanningBus;
|
|
17
|
+
ids: () => string;
|
|
18
|
+
now: () => string;
|
|
19
|
+
/** Every local watcher, told after a write of this process commits. */
|
|
20
|
+
touched: (entityId: string) => void;
|
|
21
|
+
watch: (listener: (entityId: string) => void) => Unsubscribe;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The data-defined schema port over `planning-schema`.
|
|
25
|
+
*
|
|
26
|
+
* `put` is one transaction: bump the organization's revision row, write the record under a
|
|
27
|
+
* compare-and-set on `version` (an INSERT that must not conflict for version 1, an UPDATE guarded
|
|
28
|
+
* on `version - 1` after), NOTIFY a schema frame. `revision` reads the head row — one primary read,
|
|
29
|
+
* so every lookup of a resolved layer sees a write committed anywhere.
|
|
30
|
+
*/
|
|
31
|
+
export declare const makeSchemaPort: (deps: SchemaPortDeps) => SchemaStore;
|
|
32
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/store/schemas.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAsB,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACtF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAG9B,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAa,MAAM,WAAW,CAAA;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAQ3C;;;GAGG;AACH,eAAO,MAAM,YAAY,QAAe,UAAU,YAAY,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,KAAG,OAAO,CAAC,MAAM,CAWlH,CAAA;AAED,mGAAmG;AACnG,eAAO,MAAM,iBAAiB,QAAe,UAAU,YAAY,MAAM,YAAY,SAAS,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAStH,CAAA;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAA;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;IACrC,GAAG,EAAE,WAAW,CAAA;IAChB,GAAG,EAAE,MAAM,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,MAAM,CAAA;IACjB,uEAAuE;IACvE,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,KAAK,WAAW,CAAA;CAC7D;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,SAAU,cAAc,KAAG,WA8GrD,CAAA"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { SchemaConflict } from '@owlmeans/planning';
|
|
2
|
+
import { SCHEMA_HEAD_KEY, SCHEMA_HEAD_KIND } from '../consts.js';
|
|
3
|
+
import { clientRunner, col, insertOf, recordOf } from '../sql.js';
|
|
4
|
+
/** The scope's uniqueness expression — the one the `…_scope` index is built on. */
|
|
5
|
+
const scopeTarget = (sql) => {
|
|
6
|
+
const spec = sql.tables.schema;
|
|
7
|
+
return `(${col(spec, 'entityId')}, COALESCE(${col(spec, 'project')}, ''), ${col(spec, 'kind')}, ${col(spec, 'key')})`;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Bump an organization's schema revision — its private `head` row, created at 1 — and answer the
|
|
11
|
+
* new value. Runs inside the write's own transaction, so the revision moves exactly when it commits.
|
|
12
|
+
*/
|
|
13
|
+
export const bumpRevision = async (sql, entityId, at, id) => {
|
|
14
|
+
const spec = sql.tables.schema;
|
|
15
|
+
const statement = insertOf(spec, {
|
|
16
|
+
id: id(), entityId, kind: SCHEMA_HEAD_KIND, key: SCHEMA_HEAD_KEY, version: 1, rev: 1, definition: {}, createdAt: at,
|
|
17
|
+
}, {
|
|
18
|
+
as: 'existing',
|
|
19
|
+
tail: `ON CONFLICT ${scopeTarget(sql)} DO UPDATE SET ${col(spec, 'rev')} = COALESCE(existing.${col(spec, 'rev')}, 0) + 1,`
|
|
20
|
+
+ ` ${col(spec, 'updatedAt')} = EXCLUDED.${col(spec, 'createdAt')} RETURNING ${col(spec, 'rev')} AS rev`,
|
|
21
|
+
});
|
|
22
|
+
const rows = await sql.runner.query(statement.text, statement.params);
|
|
23
|
+
return Number(rows[0]?.rev ?? 0);
|
|
24
|
+
};
|
|
25
|
+
/** Remove the layers of the given projects inside a transaction; answers how many records went. */
|
|
26
|
+
export const purgeSchemaLayers = async (sql, entityId, projects) => {
|
|
27
|
+
if (projects.length === 0) {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
const spec = sql.tables.schema;
|
|
31
|
+
return (await sql.runner.query(`DELETE FROM ${spec.qualified} WHERE ${col(spec, 'entityId')} = $1 AND ${col(spec, 'project')} = ANY($2) RETURNING ${col(spec, 'id')}`, [entityId, [...projects]])).length;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The data-defined schema port over `planning-schema`.
|
|
35
|
+
*
|
|
36
|
+
* `put` is one transaction: bump the organization's revision row, write the record under a
|
|
37
|
+
* compare-and-set on `version` (an INSERT that must not conflict for version 1, an UPDATE guarded
|
|
38
|
+
* on `version - 1` after), NOTIFY a schema frame. `revision` reads the head row — one primary read,
|
|
39
|
+
* so every lookup of a resolved layer sees a write committed anywhere.
|
|
40
|
+
*/
|
|
41
|
+
export const makeSchemaPort = (deps) => {
|
|
42
|
+
const transaction = async (run) => {
|
|
43
|
+
const client = await (await deps.pool()).connect();
|
|
44
|
+
const tables = await deps.tables();
|
|
45
|
+
const runner = clientRunner(client);
|
|
46
|
+
try {
|
|
47
|
+
await client.query('BEGIN');
|
|
48
|
+
const result = await run({ runner, tables });
|
|
49
|
+
await client.query('COMMIT');
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
await client.query('ROLLBACK').catch(() => undefined);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
client.release();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
list: async (where) => {
|
|
62
|
+
const sql = await deps.sql();
|
|
63
|
+
const spec = sql.tables.schema;
|
|
64
|
+
const clauses = [`${col(spec, 'entityId')} = $1`, `${col(spec, 'kind')} <> '${SCHEMA_HEAD_KIND}'`];
|
|
65
|
+
const params = [where.entityId];
|
|
66
|
+
if (where.project === null) {
|
|
67
|
+
clauses.push(`${col(spec, 'project')} IS NULL`);
|
|
68
|
+
}
|
|
69
|
+
else if (where.project !== undefined) {
|
|
70
|
+
params.push(where.project);
|
|
71
|
+
clauses.push(`${col(spec, 'project')} = $${params.length}`);
|
|
72
|
+
}
|
|
73
|
+
if (where.kind != null) {
|
|
74
|
+
params.push(where.kind);
|
|
75
|
+
clauses.push(`${col(spec, 'kind')} = $${params.length}`);
|
|
76
|
+
}
|
|
77
|
+
if (where.key != null) {
|
|
78
|
+
params.push(Array.isArray(where.key) ? where.key : [where.key]);
|
|
79
|
+
clauses.push(`${col(spec, 'key')} = ANY($${params.length})`);
|
|
80
|
+
}
|
|
81
|
+
if (where.retired != null) {
|
|
82
|
+
clauses.push(where.retired ? `${col(spec, 'retired')} IS TRUE` : `${col(spec, 'retired')} IS NOT TRUE`);
|
|
83
|
+
}
|
|
84
|
+
const rows = await sql.runner.query(`SELECT * FROM ${spec.qualified} WHERE ${clauses.join(' AND ')}`
|
|
85
|
+
+ ` ORDER BY ${col(spec, 'kind')}, ${col(spec, 'key')}, ${col(spec, 'project')} NULLS FIRST`, params);
|
|
86
|
+
return rows.map(row => recordOf(row, spec));
|
|
87
|
+
},
|
|
88
|
+
put: async (record) => {
|
|
89
|
+
const written = await transaction(async (sql) => {
|
|
90
|
+
const spec = sql.tables.schema;
|
|
91
|
+
const rev = await bumpRevision(sql, record.entityId, deps.now(), deps.ids);
|
|
92
|
+
const values = { ...record, id: record.id ?? deps.ids(), rev, retired: record.retired === true ? true : undefined };
|
|
93
|
+
let rows;
|
|
94
|
+
if (record.version === 1) {
|
|
95
|
+
const insert = insertOf(spec, values, {
|
|
96
|
+
tail: `ON CONFLICT ${scopeTarget(sql)} DO NOTHING RETURNING *`,
|
|
97
|
+
});
|
|
98
|
+
rows = await sql.runner.query(insert.text, insert.params);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
rows = await sql.runner.query(`UPDATE ${spec.qualified} SET ${col(spec, 'version')} = $5, ${col(spec, 'definition')} = $6::jsonb,`
|
|
102
|
+
+ ` ${col(spec, 'retired')} = $7, ${col(spec, 'rev')} = $8, ${col(spec, 'updatedAt')} = $9, ${col(spec, 'by')} = $10::jsonb`
|
|
103
|
+
+ ` WHERE ${col(spec, 'entityId')} = $1 AND COALESCE(${col(spec, 'project')}, '') = $2 AND ${col(spec, 'kind')} = $3`
|
|
104
|
+
+ ` AND ${col(spec, 'key')} = $4 AND ${col(spec, 'version')} = $5 - 1 RETURNING *`, [
|
|
105
|
+
record.entityId, record.project ?? '', record.kind, record.key, record.version,
|
|
106
|
+
JSON.stringify(record.definition), record.retired === true ? true : null, rev,
|
|
107
|
+
record.updatedAt ?? deps.now(), record.by != null ? JSON.stringify(record.by) : null,
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
if (rows[0] == null) {
|
|
111
|
+
throw new SchemaConflict(`${record.kind}:${record.key}:version:${record.version}`);
|
|
112
|
+
}
|
|
113
|
+
await deps.bus.notify(sql.runner, { t: 's', e: record.entityId });
|
|
114
|
+
return recordOf(rows[0], spec);
|
|
115
|
+
});
|
|
116
|
+
deps.touched(record.entityId);
|
|
117
|
+
return written;
|
|
118
|
+
},
|
|
119
|
+
purge: async (where) => {
|
|
120
|
+
const count = await transaction(async (sql) => {
|
|
121
|
+
const purged = await purgeSchemaLayers(sql, where.entityId, [where.project]);
|
|
122
|
+
if (purged > 0) {
|
|
123
|
+
await bumpRevision(sql, where.entityId, deps.now(), deps.ids);
|
|
124
|
+
await deps.bus.notify(sql.runner, { t: 's', e: where.entityId });
|
|
125
|
+
}
|
|
126
|
+
return purged;
|
|
127
|
+
});
|
|
128
|
+
if (count > 0) {
|
|
129
|
+
deps.touched(where.entityId);
|
|
130
|
+
}
|
|
131
|
+
return count;
|
|
132
|
+
},
|
|
133
|
+
revision: async (entityId) => {
|
|
134
|
+
const sql = await deps.sql();
|
|
135
|
+
const spec = sql.tables.schema;
|
|
136
|
+
const rows = await sql.runner.query(`SELECT ${col(spec, 'rev')} AS rev FROM ${spec.qualified} WHERE ${col(spec, 'entityId')} = $1`
|
|
137
|
+
+ ` AND ${col(spec, 'project')} IS NULL AND ${col(spec, 'kind')} = '${SCHEMA_HEAD_KIND}' AND ${col(spec, 'key')} = '${SCHEMA_HEAD_KEY}'`, [entityId]);
|
|
138
|
+
return Number(rows[0]?.rev ?? 0);
|
|
139
|
+
},
|
|
140
|
+
watch: listener => deps.watch(listener),
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/store/schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SpecificationStore } from '@owlmeans/planning';
|
|
2
|
+
import type { SqlContext } from '../sql.js';
|
|
3
|
+
import type { PlanningCardResource } from '../types.js';
|
|
4
|
+
export interface SpecPortDeps {
|
|
5
|
+
sql: () => Promise<SqlContext>;
|
|
6
|
+
resource: () => PlanningCardResource;
|
|
7
|
+
}
|
|
8
|
+
/** Specifications are rows of the card table (`kind: 'specification'`), read per parent and slot. */
|
|
9
|
+
export declare const makeSpecPort: (deps: SpecPortDeps) => SpecificationStore;
|
|
10
|
+
//# sourceMappingURL=specs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specs.d.ts","sourceRoot":"","sources":["../../src/store/specs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAK3E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAsB,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAa3E,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAA;IAC9B,QAAQ,EAAE,MAAM,oBAAoB,CAAA;CACrC;AAED,qGAAqG;AACrG,eAAO,MAAM,YAAY,SAAU,YAAY,KAAG,kBA6ChD,CAAA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { listOptionsOf, specCriteriaOf, WorkcardKind } from '@owlmeans/planning';
|
|
2
|
+
import { applyQuery } from '@owlmeans/resource';
|
|
3
|
+
import { revisionsFromLog } from '@owlmeans/server-planning/store';
|
|
4
|
+
import { cleanRecord, col, recordOf } from '../sql.js';
|
|
5
|
+
import { CARD_PRIVATE } from './cards.js';
|
|
6
|
+
import { listTransitions } from './transitions.js';
|
|
7
|
+
/** The current document of a slot is the highest revision, then the most recently updated. */
|
|
8
|
+
const currentOrder = (sql) => {
|
|
9
|
+
const spec = sql.tables.card;
|
|
10
|
+
return `COALESCE(${col(spec, 'revision')}, 0) DESC, COALESCE(${col(spec, 'updatedAt')}, ${col(spec, 'createdAt')}) DESC, ${col(spec, 'id')}`;
|
|
11
|
+
};
|
|
12
|
+
const specOf = (row, sql) => cleanRecord(recordOf(row, sql.tables.card), CARD_PRIVATE);
|
|
13
|
+
/** Specifications are rows of the card table (`kind: 'specification'`), read per parent and slot. */
|
|
14
|
+
export const makeSpecPort = (deps) => ({
|
|
15
|
+
current: async (parent, category, entityId) => {
|
|
16
|
+
const sql = await deps.sql();
|
|
17
|
+
const spec = sql.tables.card;
|
|
18
|
+
const rows = await sql.runner.query(`SELECT * FROM ${spec.qualified} WHERE ${col(spec, 'entityId')} = $1 AND ${col(spec, 'kind')} = $2`
|
|
19
|
+
+ ` AND ${col(spec, 'parent')} = $3 AND ${col(spec, 'category')} = $4 ORDER BY ${currentOrder(sql)} LIMIT 1`, [entityId, WorkcardKind.Specification, parent, category]);
|
|
20
|
+
return rows[0] == null ? null : specOf(rows[0], sql);
|
|
21
|
+
},
|
|
22
|
+
list: async (parent, entityId, query) => {
|
|
23
|
+
const sql = await deps.sql();
|
|
24
|
+
if (query?.all === true) {
|
|
25
|
+
const listed = await deps.resource().list(specCriteriaOf(parent, query, { entityId }), listOptionsOf(query));
|
|
26
|
+
return { ...listed, items: listed.items.map(item => cleanRecord(item, CARD_PRIVATE)) };
|
|
27
|
+
}
|
|
28
|
+
const spec = sql.tables.card;
|
|
29
|
+
const categories = query?.category == null ? undefined : Array.isArray(query.category) ? query.category : [query.category];
|
|
30
|
+
const rows = await sql.runner.query(`SELECT DISTINCT ON (${col(spec, 'category')}) * FROM ${spec.qualified}`
|
|
31
|
+
+ ` WHERE ${col(spec, 'entityId')} = $1 AND ${col(spec, 'kind')} = $2 AND ${col(spec, 'parent')} = $3`
|
|
32
|
+
+ `${categories != null ? ` AND ${col(spec, 'category')} = ANY($4)` : ''}`
|
|
33
|
+
+ ` ORDER BY ${col(spec, 'category')}, ${currentOrder(sql)}`, categories != null ? [entityId, WorkcardKind.Specification, parent, categories] : [entityId, WorkcardKind.Specification, parent]);
|
|
34
|
+
// One current document per category is a small set: its paging and sorting are the shared engine's.
|
|
35
|
+
return applyQuery(rows.map(row => specOf(row, sql)), undefined, listOptionsOf(query));
|
|
36
|
+
},
|
|
37
|
+
revisions: async (id, entityId, limit) => {
|
|
38
|
+
const sql = await deps.sql();
|
|
39
|
+
const spec = sql.tables.card;
|
|
40
|
+
const found = await sql.runner.query(`SELECT ${col(spec, 'id')} FROM ${spec.qualified} WHERE ${col(spec, 'id')} = $1 AND ${col(spec, 'entityId')} = $2 AND ${col(spec, 'kind')} = $3`, [id, entityId, WorkcardKind.Specification]);
|
|
41
|
+
if (found.length === 0) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
return revisionsFromLog((await listTransitions(sql, { entityId, card: id })).items, limit);
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=specs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specs.js","sourceRoot":"","sources":["../../src/store/specs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Transition, TransitionCommit, TransitionStore, TransitionWhere } from '@owlmeans/planning';
|
|
2
|
+
import type { Criteria, ListResult } from '@owlmeans/resource';
|
|
3
|
+
import type { SqlContext } from '../sql.js';
|
|
4
|
+
import type { PlanningTransitionResource } from '../types.js';
|
|
5
|
+
/** The portable criteria of a transition query — what a resource list reads the log with. */
|
|
6
|
+
export declare const transitionCriteria: (where: TransitionWhere) => Criteria<Transition>;
|
|
7
|
+
export declare const transitionOf: (row: Record<string, unknown>, sql: SqlContext) => Transition;
|
|
8
|
+
export declare const readTransition: (sql: SqlContext, id: string) => Promise<Transition | null>;
|
|
9
|
+
export declare const readTransitionByKey: (sql: SqlContext, entityId: string, key: string) => Promise<Transition | null>;
|
|
10
|
+
/**
|
|
11
|
+
* The log of one card (or several) in `seq` order, as a fold reads it: this package's own statement,
|
|
12
|
+
* so it runs inside a fold's transaction. `size` bounds it (0 is no limit); `total` tells a bounded
|
|
13
|
+
* read that more remain.
|
|
14
|
+
*/
|
|
15
|
+
export declare const listTransitions: (sql: SqlContext, where: TransitionWhere, size?: number) => Promise<ListResult<Transition>>;
|
|
16
|
+
export declare const commitTransition: (sql: SqlContext, id: string, commit: TransitionCommit) => Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Allocate the next seq — a compare-and-set of `head` on the card row, stamping `headAt`. A card
|
|
19
|
+
* whose create has not folded yet has no row to count on: it allocates `max(seq) + 1` from the log
|
|
20
|
+
* and lets the unique `(card, seq)` index refuse a repeat.
|
|
21
|
+
*
|
|
22
|
+
* @throws {WorkcardConflict}
|
|
23
|
+
*/
|
|
24
|
+
export declare const allocateSeq: (sql: SqlContext, card: string, expect: number | null | undefined, at: string) => Promise<number>;
|
|
25
|
+
export declare const lastSeq: (sql: SqlContext, card: string) => Promise<number>;
|
|
26
|
+
export interface TransitionPortDeps {
|
|
27
|
+
sql: () => Promise<SqlContext>;
|
|
28
|
+
resource: () => PlanningTransitionResource;
|
|
29
|
+
ids: () => string;
|
|
30
|
+
now: () => string;
|
|
31
|
+
/** The card-seq and entity-key unique index names — how a violation is told apart. */
|
|
32
|
+
indexes: () => Promise<{
|
|
33
|
+
cardSeq: string;
|
|
34
|
+
entityKey: string;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The log port. `append` is idempotent on its id; a lost race on the key releases the allocation
|
|
39
|
+
* and answers `PlanningError('duplicate-key')` (the executor then answers the winner's receipt); a
|
|
40
|
+
* lost race on `(card, seq)` — an allocation the fold gave up for lost and filled with a failed
|
|
41
|
+
* placeholder — re-allocates once and lands after it, then refuses with `WorkcardConflict`.
|
|
42
|
+
*/
|
|
43
|
+
export declare const makeTransitionPort: (deps: TransitionPortDeps) => TransitionStore;
|
|
44
|
+
//# sourceMappingURL=transitions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transitions.d.ts","sourceRoot":"","sources":["../../src/store/transitions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACxG,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAQ,MAAM,oBAAoB,CAAA;AAEpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAK7D,6FAA6F;AAC7F,eAAO,MAAM,kBAAkB,UAAW,eAAe,KAAG,QAAQ,CAAC,UAAU,CAOrD,CAAA;AAE1B,eAAO,MAAM,YAAY,QAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,UAAU,KAAG,UAC3B,CAAA;AAElD,eAAO,MAAM,cAAc,QAAe,UAAU,MAAM,MAAM,KAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAI3F,CAAA;AAED,eAAO,MAAM,mBAAmB,QAAe,UAAU,YAAY,MAAM,OAAO,MAAM,KAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAMnH,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,QACrB,UAAU,SAAS,eAAe,SAAQ,MAAM,KACpD,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAyBhC,CAAA;AAED,eAAO,MAAM,gBAAgB,QAAe,UAAU,MAAM,MAAM,UAAU,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAK1G,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,QACjB,UAAU,QAAQ,MAAM,UAAU,MAAM,GAAG,IAAI,GAAG,SAAS,MAAM,MAAM,KAC3E,OAAO,CAAC,MAAM,CAyBhB,CAAA;AAED,eAAO,MAAM,OAAO,QAAe,UAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CAM3E,CAAA;AAWD,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAA;IAC9B,QAAQ,EAAE,MAAM,0BAA0B,CAAA;IAC1C,GAAG,EAAE,MAAM,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,MAAM,CAAA;IACjB,sFAAsF;IACtF,OAAO,EAAE,MAAM,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC/D;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,SAAU,kBAAkB,KAAG,eA0E7D,CAAA"}
|