@routier/core 0.2.0 → 0.3.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/LICENSE +21 -0
- package/{readme.md → README.md} +2 -2
- package/dist/assertions/index.cjs +191 -0
- package/dist/assertions/index.cjs.map +1 -0
- package/dist/assertions/index.d.ts +30 -0
- package/dist/assertions/index.js +94 -30
- package/dist/assertions/index.js.map +1 -1
- package/dist/capabilities/index.cjs +820 -0
- package/dist/capabilities/index.cjs.map +1 -0
- package/dist/capabilities/index.js +580 -545
- package/dist/capabilities/index.js.map +1 -1
- package/dist/codegen/handlers/CloneHandlerBuilder.d.ts +10 -1
- package/dist/codegen/handlers/SetHandlerBuilder.d.ts +4 -0
- package/dist/codegen/handlers/clone/CloneArrayHandler.d.ts +3 -0
- package/dist/codegen/handlers/clone/CloneDateHandler.d.ts +13 -0
- package/dist/codegen/handlers/clone/CloneValueHandler.d.ts +16 -0
- package/dist/codegen/handlers/compare/CompareComputedHandler.d.ts +10 -0
- package/dist/codegen/handlers/compare/CompareFunctionHandler.d.ts +10 -0
- package/dist/codegen/handlers/deserialize/DeserializeArrayHandler.d.ts +14 -0
- package/dist/codegen/handlers/enableChangeTracking/EnableChangeTrackingArrayHandler.d.ts +11 -0
- package/dist/codegen/handlers/enrichment/EnrichmentArrayHandler.d.ts +11 -0
- package/dist/codegen/handlers/freeze/FreezeArrayHandler.d.ts +6 -0
- package/dist/codegen/handlers/hash/HashArrayHandler.d.ts +10 -0
- package/dist/codegen/handlers/hash/HashFileHandler.d.ts +24 -0
- package/dist/codegen/handlers/hash/HashObjectHandler.d.ts +10 -0
- package/dist/codegen/handlers/hash/HashTransformHandler.d.ts +23 -0
- package/dist/codegen/handlers/index.d.ts +1 -0
- package/dist/codegen/handlers/merge/MergeArrayHandler.d.ts +20 -0
- package/dist/codegen/handlers/merge/MergeObjectHandler.d.ts +10 -0
- package/dist/codegen/handlers/serialize/SerializeArrayHandler.d.ts +19 -0
- package/dist/codegen/handlers/serialize/SerializeComputedHandler.d.ts +6 -0
- package/dist/codegen/handlers/set/SetComplexHandler.d.ts +6 -0
- package/dist/codegen/handlers/strip/StripComputedHandler.d.ts +10 -0
- package/dist/codegen/handlers/strip/StripFunctionHandler.d.ts +9 -0
- package/dist/codegen/handlers/types.d.ts +55 -1
- package/dist/codegen/index.cjs +618 -0
- package/dist/codegen/index.cjs.map +1 -0
- package/dist/codegen/index.js +100 -127
- package/dist/codegen/index.js.map +1 -1
- package/dist/collections/Changes.d.ts +2 -2
- package/dist/collections/MemoryDataCollection.d.ts +15 -1
- package/dist/collections/TagCollection.d.ts +7 -8
- package/dist/collections/index.cjs +702 -0
- package/dist/collections/index.cjs.map +1 -0
- package/dist/collections/index.js +282 -276
- package/dist/collections/index.js.map +1 -1
- package/dist/errors/OptimisticConcurrencyError.d.ts +18 -0
- package/dist/errors/PluginDestroyedError.d.ts +10 -0
- package/dist/errors/index.cjs +132 -0
- package/dist/errors/index.cjs.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +61 -19
- package/dist/errors/index.js.map +1 -1
- package/dist/expressions/constants.d.ts +2 -0
- package/dist/expressions/evaluate.d.ts +53 -0
- package/dist/expressions/index.cjs +2087 -0
- package/dist/expressions/index.cjs.map +1 -0
- package/dist/expressions/index.d.ts +2 -0
- package/dist/expressions/index.js +1784 -772
- package/dist/expressions/index.js.map +1 -1
- package/dist/expressions/parser.d.ts +19 -0
- package/dist/expressions/types.d.ts +87 -2
- package/dist/expressions/utils.d.ts +1 -2
- package/dist/index.cjs +13925 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +12094 -7049
- package/dist/index.js.map +1 -1
- package/dist/performance/index.cjs +217 -0
- package/dist/performance/index.cjs.map +1 -0
- package/dist/performance/index.js +126 -50
- package/dist/performance/index.js.map +1 -1
- package/dist/pipeline/index.cjs +576 -0
- package/dist/pipeline/index.cjs.map +1 -0
- package/dist/pipeline/index.js +229 -156
- package/dist/pipeline/index.js.map +1 -1
- package/dist/plugins/BatchingDbPlugin.d.ts +139 -0
- package/dist/plugins/CacheDbPlugin.d.ts +70 -0
- package/dist/plugins/ConcurrencyDbPlugin.d.ts +78 -0
- package/dist/plugins/EphemeralDataPlugin.d.ts +57 -1
- package/dist/plugins/RetryDbPlugin.d.ts +77 -0
- package/dist/plugins/index.cjs +6104 -0
- package/dist/plugins/index.cjs.map +1 -0
- package/dist/plugins/index.d.ts +5 -1
- package/dist/plugins/index.js +5572 -1491
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/query/QueryOptionsCollection.d.ts +22 -0
- package/dist/plugins/query/index.d.ts +2 -0
- package/dist/plugins/query/join.d.ts +210 -0
- package/dist/plugins/query/similarity.d.ts +38 -0
- package/dist/plugins/query/types.d.ts +64 -1
- package/dist/plugins/translators/DataTranslator.d.ts +28 -0
- package/dist/plugins/translators/JsonTranslator.d.ts +27 -0
- package/dist/plugins/translators/SqlTranslator.d.ts +45 -0
- package/dist/plugins/translators/TranslatedArrayValue.d.ts +3 -1
- package/dist/plugins/translators/TranslatedGroupValue.d.ts +3 -1
- package/dist/plugins/translators/TranslatedSingleValue.d.ts +3 -1
- package/dist/plugins/translators/TupleTranslator.d.ts +45 -0
- package/dist/plugins/translators/index.d.ts +1 -0
- package/dist/plugins/translators/types.d.ts +8 -1
- package/dist/plugins/types.d.ts +87 -11
- package/dist/plugins/wire/handler.d.ts +122 -0
- package/dist/plugins/wire/index.d.ts +4 -0
- package/dist/plugins/wire/persist.d.ts +43 -0
- package/dist/plugins/wire/query.d.ts +49 -0
- package/dist/plugins/wire/types.d.ts +123 -0
- package/dist/results/Result.d.ts +2 -2
- package/dist/results/index.cjs +174 -0
- package/dist/results/index.cjs.map +1 -0
- package/dist/results/index.js +29 -44
- package/dist/results/index.js.map +1 -1
- package/dist/schema/PropertyInfo.d.ts +35 -2
- package/dist/schema/SchemaDefinition.d.ts +51 -1
- package/dist/schema/builder.d.ts +35 -1
- package/dist/schema/communication/broadcast.d.ts +17 -1
- package/dist/schema/index.cjs +6911 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.js +5781 -3973
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/property/base/SchemaBase.d.ts +50 -2
- package/dist/schema/property/modifiers/SchemaDeserialize.d.ts +5 -1
- package/dist/schema/property/modifiers/SchemaForeignKey.d.ts +15 -0
- package/dist/schema/property/modifiers/SchemaKey.d.ts +2 -0
- package/dist/schema/property/modifiers/SchemaNullable.d.ts +15 -1
- package/dist/schema/property/modifiers/SchemaOptional.d.ts +22 -1
- package/dist/schema/property/modifiers/SchemaSearchable.d.ts +34 -0
- package/dist/schema/property/modifiers/SchemaTag.d.ts +27 -0
- package/dist/schema/property/modifiers/SchemaTracked.d.ts +5 -1
- package/dist/schema/property/modifiers/index.d.ts +3 -0
- package/dist/schema/property/types/SchemaArray.d.ts +2 -0
- package/dist/schema/property/types/SchemaBoolean.d.ts +2 -0
- package/dist/schema/property/types/SchemaDate.d.ts +2 -0
- package/dist/schema/property/types/SchemaFile.d.ts +60 -0
- package/dist/schema/property/types/SchemaNumber.d.ts +5 -1
- package/dist/schema/property/types/SchemaObject.d.ts +2 -0
- package/dist/schema/property/types/SchemaString.d.ts +25 -1
- package/dist/schema/property/types/SchemaVector.d.ts +61 -0
- package/dist/schema/property/types/index.d.ts +2 -0
- package/dist/schema/table/SchemaTransform.d.ts +40 -0
- package/dist/schema/table/index.d.ts +1 -0
- package/dist/schema/types.d.ts +200 -32
- package/dist/schema/utils/propertyKind.d.ts +4 -0
- package/dist/schema/utils/standardJsonSchema.d.ts +90 -0
- package/dist/types/index.cjs +23 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.js +0 -14
- package/dist/types/index.js.map +1 -1
- package/dist/utilities/functions.d.ts +1 -1
- package/dist/utilities/index.cjs +982 -0
- package/dist/utilities/index.cjs.map +1 -0
- package/dist/utilities/index.js +590 -321
- package/dist/utilities/index.js.map +1 -1
- package/dist/utilities/logger.d.ts +48 -0
- package/package.json +152 -98
- package/dist/collections/Changes.test.d.ts +0 -1
- package/dist/collections/MemoryDataCollection.test.d.ts +0 -1
- package/dist/collections/TagCollection.test.d.ts +0 -1
- package/dist/expressions/parser.test.d.ts +0 -1
- package/dist/expressions/utils.test.d.ts +0 -1
- package/dist/pipeline/SyncronousQueue.test.d.ts +0 -1
- package/dist/pipeline/WorkPipeline.test.d.ts +0 -1
- package/dist/plugins/EphemeralDataPlugin.test.d.ts +0 -1
- package/dist/plugins/query/QueryOptionsCollection.test.d.ts +0 -1
- package/dist/plugins/replication/OptimisticReplicationDbPlugin.d.ts +0 -23
- package/dist/plugins/replication/ReplicationDbPlugin.d.ts +0 -22
- package/dist/plugins/replication/index.d.ts +0 -3
- package/dist/plugins/replication/types.d.ts +0 -5
- package/dist/plugins/translators/JsonTranslator.test.d.ts +0 -1
- package/dist/schema/PropertyInfo.test.d.ts +0 -1
- package/dist/schema/schemaGeneration.test.d.ts +0 -1
- package/dist/schema/testSchemas.test.d.ts +0 -314
- package/dist/utilities/arrays.test.d.ts +0 -1
- package/dist/utilities/dates.test.d.ts +0 -1
- package/dist/utilities/strings.test.d.ts +0 -1
package/dist/plugins/types.d.ts
CHANGED
|
@@ -7,6 +7,28 @@ import { ITranslatedValue } from "./translators";
|
|
|
7
7
|
* Interface for a database plugin, which provides query, destroy, and bulk operations.
|
|
8
8
|
*/
|
|
9
9
|
export interface IDbPlugin {
|
|
10
|
+
/**
|
|
11
|
+
* Uniquely identifies the database this plugin talks to, INCLUDING host or path where a
|
|
12
|
+
* bare name would collide — `orders.db` in two directories is two databases, and `mydb`
|
|
13
|
+
* on two hosts is two databases. Two instances over the same database must return the
|
|
14
|
+
* same string, in this process and in any other; two over different databases must not.
|
|
15
|
+
*
|
|
16
|
+
* Used to scope schema subscription channels, so instances of one database (another tab,
|
|
17
|
+
* a worker) see each other's change notifications and unrelated databases holding the
|
|
18
|
+
* same schema do not.
|
|
19
|
+
*
|
|
20
|
+
* Required rather than optional on purpose. An absent value used to fall back to scoping
|
|
21
|
+
* by schema alone, which shares one channel across every database holding that schema —
|
|
22
|
+
* the exact cross-talk this prevents, arrived at by omission. Requiring it also makes a
|
|
23
|
+
* wrapper that forgets to forward it a compile error rather than a silent regression.
|
|
24
|
+
*
|
|
25
|
+
* Derive it, never generate it: a random value is unique per PROCESS, not per database,
|
|
26
|
+
* so another tab would never match one and cross-context notifications would stop.
|
|
27
|
+
*
|
|
28
|
+
* Must not contain credentials — it becomes part of a channel key, so build it from
|
|
29
|
+
* host/port/database rather than returning a connection string.
|
|
30
|
+
*/
|
|
31
|
+
readonly databaseName: string;
|
|
10
32
|
/**
|
|
11
33
|
* Executes a query operation on the database.
|
|
12
34
|
* @param event The query event containing schema, parent, and query operation.
|
|
@@ -41,8 +63,12 @@ export type DbPluginEvent = {
|
|
|
41
63
|
schemas: SchemaCollection;
|
|
42
64
|
/** Unique id of the event. */
|
|
43
65
|
id: string;
|
|
44
|
-
/**
|
|
45
|
-
source:
|
|
66
|
+
/** The class/component that triggered this event */
|
|
67
|
+
source: string;
|
|
68
|
+
/** The action/operation type being performed */
|
|
69
|
+
action: "query" | "persist" | "destroy";
|
|
70
|
+
/** Optional context about why this operation is happening */
|
|
71
|
+
reason?: string;
|
|
46
72
|
};
|
|
47
73
|
/**
|
|
48
74
|
* Event for a specific plugin operation, extending the base event with an operation payload.
|
|
@@ -67,20 +93,69 @@ export type ReplicationPluginOptions = {
|
|
|
67
93
|
*/
|
|
68
94
|
read?: IDbPlugin;
|
|
69
95
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
96
|
+
/**
|
|
97
|
+
* A value inside a delta. Arrays and Dates are values, not sub-structures to descend into.
|
|
98
|
+
*
|
|
99
|
+
* Descending into them would be both wrong and useless: an element-wise array delta cannot
|
|
100
|
+
* express "the last element was removed", and a partial Date is meaningless.
|
|
101
|
+
*/
|
|
102
|
+
type DeltaValue<V> = V extends readonly unknown[] ? V : V extends Date ? V : V extends object ? DeltaProperties<V> : V;
|
|
103
|
+
type DeltaProperties<T> = {
|
|
104
|
+
[K in keyof T]?: DeltaValue<T[K]>;
|
|
77
105
|
};
|
|
106
|
+
/**
|
|
107
|
+
* What changed about an entity, expressed as a **partial entity**.
|
|
108
|
+
*
|
|
109
|
+
* A change two levels deep appears where it actually lives —
|
|
110
|
+
* `{ nested: { inner: { value } } }` — not as a flattened key.
|
|
111
|
+
*
|
|
112
|
+
* This deliberately carries no storage vocabulary. It used to be typed
|
|
113
|
+
* `{ [key: string]: string | number | Date }`, which was wrong twice over: it excluded
|
|
114
|
+
* booleans, nulls, arrays and objects that the schema happily allows, and its flat
|
|
115
|
+
* scalar shape was really a SQL `SET column = ?` list — one storage family's concern
|
|
116
|
+
* leaking into the contract every plugin sees.
|
|
117
|
+
*
|
|
118
|
+
* Translating this into storage terms belongs to the plugin. A document store can merge it
|
|
119
|
+
* as-is; a SQL plugin decides which columns it touches and how a nested value is encoded
|
|
120
|
+
* (see `toColumnAssignments` in `@routier/sql-plugin-core`, which stores nested objects and
|
|
121
|
+
* arrays as JSON). Core does not need to know, and must not.
|
|
122
|
+
*/
|
|
123
|
+
export type EntityDelta<T extends {}> = DeltaProperties<InferType<T>>;
|
|
78
124
|
export type EntityUpdateInfo<T extends {}> = {
|
|
79
125
|
entity: InferType<T>;
|
|
80
126
|
changeType: EntityChangeType;
|
|
81
|
-
delta:
|
|
82
|
-
|
|
127
|
+
delta: EntityDelta<T>;
|
|
128
|
+
/**
|
|
129
|
+
* Present when the schema declares a `.concurrency()` token: the update must be
|
|
130
|
+
* applied ONLY IF the stored row's `column` still equals `expected` (the value the
|
|
131
|
+
* writer read). The entity/delta already carry the bumped value to store on success.
|
|
132
|
+
* A plugin that finds a mismatch must fail the whole save with an
|
|
133
|
+
* OptimisticConcurrencyError naming the conflicted rows — never apply partially.
|
|
134
|
+
*/
|
|
135
|
+
concurrency?: {
|
|
136
|
+
column: string;
|
|
137
|
+
expected: number;
|
|
83
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* The values these properties held BEFORE this update — keyed like `delta`, which holds
|
|
141
|
+
* the values they hold after.
|
|
142
|
+
*
|
|
143
|
+
* DATASTORE-INTERNAL. The datastore strips it before the plugin is called
|
|
144
|
+
* (`DataStore.onSavePreparedChanges`), so no plugin ever receives it and nothing goes over
|
|
145
|
+
* a wire. It exists for save-pipeline participants that must undo work keyed by an old
|
|
146
|
+
* value — a search index has to delete the rows for terms that just left a field, and
|
|
147
|
+
* `delta` only says what the field says now.
|
|
148
|
+
*
|
|
149
|
+
* Always populated for an update. It is part of what an update IS, not something a
|
|
150
|
+
* declaration switches on — a consumer can rely on it without knowing what else the store
|
|
151
|
+
* declared, and there is one code path to reason about rather than two.
|
|
152
|
+
*
|
|
153
|
+
* Which properties appear depends on what the change-tracking mode can know. Proxy and
|
|
154
|
+
* immutable name exactly the properties that changed. Diff detects change by comparing a
|
|
155
|
+
* content hash, so it cannot say WHICH property moved and reports every root property —
|
|
156
|
+
* the same "assume everything" convention its empty `delta` already uses.
|
|
157
|
+
*/
|
|
158
|
+
previous?: EntityDelta<T>;
|
|
84
159
|
};
|
|
85
160
|
export type TaggedEntity<T> = {
|
|
86
161
|
entity: T;
|
|
@@ -100,3 +175,4 @@ export type IQuery<TRoot extends {}, TShape> = {
|
|
|
100
175
|
get changeTracking(): boolean;
|
|
101
176
|
};
|
|
102
177
|
export type EntityChangeType = "propertiesChanged" | "markedDirty" | "notModified";
|
|
178
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { ReadonlySchemaCollection } from "../../collections/ReadonlySchemaCollection";
|
|
2
|
+
import { Filter, ParamsFilter } from "../../expressions";
|
|
3
|
+
import { CompiledSchema } from "../../schema";
|
|
4
|
+
import { IDbPlugin } from "../types";
|
|
5
|
+
import { ScopeProvider } from "./query";
|
|
6
|
+
import { SerializedRequest, SerializedResponse } from "./types";
|
|
7
|
+
/**
|
|
8
|
+
* The receiving half: takes a serialized request, executes it, returns a serialized response.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately not a server. It is one async function from JSON to JSON, with no notion of HTTP, so
|
|
11
|
+
* the same handler sits behind Express, a Cloudflare Worker, a Lambda, a WebSocket message, or a
|
|
12
|
+
* worker `postMessage`. Transport is the caller's business; this is the part that would otherwise be
|
|
13
|
+
* rewritten per framework.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const handle = createRequestHandler({ plugin, schemas });
|
|
17
|
+
*
|
|
18
|
+
* app.post("/routier", async (req, res) => res.json(await handle(req.body)));
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* ## Security is YOURS, and this gives you the two places to put it
|
|
22
|
+
*
|
|
23
|
+
* There is no built-in notion of a user, a tenant, a role or a token, and there should not be: this
|
|
24
|
+
* library cannot know what your identities are or what they may see. What it can do is make sure
|
|
25
|
+
* there is nowhere for a decision to be forgotten. Two hooks, and both receive a `context` you built
|
|
26
|
+
* from the request:
|
|
27
|
+
*
|
|
28
|
+
* - **`authorize`** — may this caller do this at all? Called once per request, before anything is
|
|
29
|
+
* deserialized or executed, with the action and every collection the request touches.
|
|
30
|
+
* - **`scope`** — which ROWS may this caller see? A filter the receiver ANDs into every read of a
|
|
31
|
+
* collection, and checks every written row against.
|
|
32
|
+
*
|
|
33
|
+
* With neither supplied, the endpoint answers anything for anyone. That is the correct default for a
|
|
34
|
+
* function with no idea who is calling it — and the moment you name a context type, passing one
|
|
35
|
+
* becomes required, so a policy cannot be half-wired.
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* const handle = createRequestHandler<{ tenantId: string }>({
|
|
39
|
+
* plugin,
|
|
40
|
+
* schemas,
|
|
41
|
+
* authorize: ({ action, context }) => context.tenantId != null || "not signed in",
|
|
42
|
+
* scope: ({ context }) => ({ filter: ([row, p]) => row.tenantId === p.tenantId, params: context }),
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* app.post("/routier", async (req, res) => {
|
|
46
|
+
* const context = { tenantId: req.user?.tenantId }; // from the REQUEST, never from the body
|
|
47
|
+
* res.json(await handle(req.body, context));
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* ## Errors are values
|
|
52
|
+
*
|
|
53
|
+
* A failure comes back as `{ ok: false, error }` rather than as a rejected promise, so a transport
|
|
54
|
+
* cannot accidentally turn a query error into a 500 with no body. The caller decides the status.
|
|
55
|
+
*/
|
|
56
|
+
/** What a hook is told about the request it is judging. */
|
|
57
|
+
export type RequestInfo<TContext> = {
|
|
58
|
+
action: "query" | "persist" | "destroy";
|
|
59
|
+
/** Every collection this request touches, including the inner side of any join. */
|
|
60
|
+
collectionNames: string[];
|
|
61
|
+
/** Whatever the transport built from the request — a user, a tenant, a token. Never the body. */
|
|
62
|
+
context: TContext;
|
|
63
|
+
/** The raw request, for a policy that needs to look closer. Treat it as caller-controlled input. */
|
|
64
|
+
request: SerializedRequest;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* May this request proceed?
|
|
68
|
+
*
|
|
69
|
+
* `true` to allow. `false` or a string to refuse — a string becomes the error message, which is the
|
|
70
|
+
* cheapest way to say WHY without inventing an error type. Throwing also refuses.
|
|
71
|
+
*
|
|
72
|
+
* Called once, before deserialization, so a refused request never reaches a schema or a plugin.
|
|
73
|
+
*/
|
|
74
|
+
export type AuthorizeHook<TContext> = (info: RequestInfo<TContext>) => boolean | string | Promise<boolean | string>;
|
|
75
|
+
/** What a scope hook is asked. One collection at a time, since each may be scoped differently. */
|
|
76
|
+
export type ScopeInfo<TContext> = {
|
|
77
|
+
collectionName: string;
|
|
78
|
+
schema: CompiledSchema<any>;
|
|
79
|
+
context: TContext;
|
|
80
|
+
action: "query" | "persist";
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* The rows of one collection this caller may touch, as a filter.
|
|
84
|
+
*
|
|
85
|
+
* Written exactly like a collection's own `.scope()` — a filter, optionally with params — so the same
|
|
86
|
+
* expression is pushed into the database on reads and checked against each row on writes. Return
|
|
87
|
+
* `null` for a collection this caller may see in full.
|
|
88
|
+
*
|
|
89
|
+
* ```ts
|
|
90
|
+
* scope: ({ collectionName, context }) =>
|
|
91
|
+
* collectionName === "orders"
|
|
92
|
+
* ? { filter: ([row, p]) => row.tenantId === p.tenantId, params: { tenantId: context.tenantId } }
|
|
93
|
+
* : null
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export type ScopeHook<TContext> = (info: ScopeInfo<TContext>) => {
|
|
97
|
+
filter: Filter<any> | ParamsFilter<any, any>;
|
|
98
|
+
params?: {};
|
|
99
|
+
} | null;
|
|
100
|
+
export type RequestHandlerOptions<TContext> = {
|
|
101
|
+
/** The plugin that actually holds the data. Anything implementing `IDbPlugin`. */
|
|
102
|
+
plugin: IDbPlugin;
|
|
103
|
+
/** Every collection this endpoint will answer for. A name absent from here is refused. */
|
|
104
|
+
schemas: ReadonlySchemaCollection;
|
|
105
|
+
/** May this caller do this? See `AuthorizeHook`. Absent means yes, to everyone. */
|
|
106
|
+
authorize?: AuthorizeHook<TContext>;
|
|
107
|
+
/** Which rows may this caller touch? See `ScopeHook`. Absent means all of them. */
|
|
108
|
+
scope?: ScopeHook<TContext>;
|
|
109
|
+
/**
|
|
110
|
+
* Whether a `destroy` request may drop the database. **Defaults to false.**
|
|
111
|
+
*
|
|
112
|
+
* `HttpTransportDbPlugin` never sends one, but an endpoint answers whatever arrives — and a
|
|
113
|
+
* hand-written `{"kind":"destroy"}` would otherwise wipe the store for anyone who could reach
|
|
114
|
+
* the route. Destroying a database is not something a remote caller should be able to ask for by
|
|
115
|
+
* default, so it is opt-in and still passes through `authorize`.
|
|
116
|
+
*/
|
|
117
|
+
allowDestroy?: boolean;
|
|
118
|
+
};
|
|
119
|
+
export type RequestHandler<TContext> = (request: SerializedRequest, context: TContext) => Promise<SerializedResponse>;
|
|
120
|
+
export declare const createRequestHandler: <TContext = void>(options: RequestHandlerOptions<TContext>) => RequestHandler<TContext>;
|
|
121
|
+
/** Re-exported so a caller can type its own scope provider without reaching for the query module. */
|
|
122
|
+
export type { ScopeProvider };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BulkPersistChanges, BulkPersistResult } from "../../collections";
|
|
2
|
+
import { CompiledSchema } from "../../schema";
|
|
3
|
+
import { ReadonlySchemaCollection } from "../../collections/ReadonlySchemaCollection";
|
|
4
|
+
import { SchemaResolver } from "./query";
|
|
5
|
+
import { SerializedPersistRequest, SerializedResponse } from "./types";
|
|
6
|
+
/**
|
|
7
|
+
* Saves, in the form that survives a wire.
|
|
8
|
+
*
|
|
9
|
+
* Simpler than a query, because a change set holds no functions: adds, updates and removes are
|
|
10
|
+
* entities, and an entity reaching a plugin has already been through `preprocess` — so it is in
|
|
11
|
+
* STORAGE shape, where a Date is already an ISO string and a nested object is already whatever the
|
|
12
|
+
* schema said to store. It is JSON by the time it gets here.
|
|
13
|
+
*
|
|
14
|
+
* Two things are deliberately left behind:
|
|
15
|
+
*
|
|
16
|
+
* - **Tags.** `SchemaPersistChanges.tags` is caller-side metadata for correlating a save with its
|
|
17
|
+
* echo locally. The receiver has no use for it and no business seeing it.
|
|
18
|
+
* - **Schema ids.** Collections are NAMED. An id is a hash of the schema's own shape, so it would
|
|
19
|
+
* couple both sides to identical schema definitions; a name lets the receiver resolve its own.
|
|
20
|
+
*/
|
|
21
|
+
export declare const serializeBulkPersist: (changes: BulkPersistChanges, schemas: ReadonlySchemaCollection) => SerializedPersistRequest;
|
|
22
|
+
/**
|
|
23
|
+
* Rebuilds a change set from its wire form, keyed by the RECEIVER's schema ids.
|
|
24
|
+
*
|
|
25
|
+
* @throws when a named collection is not one this store declares. A save aimed at data this side
|
|
26
|
+
* does not have must not be silently dropped — the caller would be told it succeeded.
|
|
27
|
+
*/
|
|
28
|
+
export declare const deserializeBulkPersist: (request: SerializedPersistRequest, resolveSchema: SchemaResolver) => {
|
|
29
|
+
changes: BulkPersistChanges;
|
|
30
|
+
schemas: CompiledSchema<any>[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Serializes the ECHO of a save — the part the change tracker cannot do without.
|
|
34
|
+
*
|
|
35
|
+
* A save's result is not a receipt. It carries the rows as the database wrote them, including any
|
|
36
|
+
* identity the database assigned, and the change tracker matches each one back to the addition that
|
|
37
|
+
* produced it. Returning a count instead would leave every inserted entity without its key.
|
|
38
|
+
*/
|
|
39
|
+
export declare const serializePersistResult: (result: BulkPersistResult, schemas: ReadonlySchemaCollection) => SerializedResponse;
|
|
40
|
+
/** Rebuilds a save's echo against the SENDER's schema ids, which is what its change tracker holds. */
|
|
41
|
+
export declare const deserializePersistResult: (response: Extract<SerializedResponse, {
|
|
42
|
+
kind: "persist";
|
|
43
|
+
}>, resolveSchema: SchemaResolver) => BulkPersistResult;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Expression } from "../../expressions";
|
|
2
|
+
import { CompiledSchema } from "../../schema";
|
|
3
|
+
import { QueryOptionsCollection } from "../query/QueryOptionsCollection";
|
|
4
|
+
import { SerializedQueryOption } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Splits options into the PREFIX that can be sent and the remainder that cannot.
|
|
7
|
+
*
|
|
8
|
+
* A prefix, not a filtered subset, and that is the whole correctness argument. Options are ordered,
|
|
9
|
+
* and most are not idempotent: sending `count` while keeping `map` local would count unmapped rows,
|
|
10
|
+
* and applying `take` on both sides would window twice. So the split stops at the first option that
|
|
11
|
+
* cannot travel, and everything from there on runs where the closures are.
|
|
12
|
+
*
|
|
13
|
+
* It is the same shape as the database/memory split this composes with — one more cut of the same
|
|
14
|
+
* ordered list, for one more reason.
|
|
15
|
+
*/
|
|
16
|
+
export declare const splitSendableOptions: <T>(options: QueryOptionsCollection<T>) => {
|
|
17
|
+
sendable: QueryOptionsCollection<T>;
|
|
18
|
+
local: QueryOptionsCollection<T>;
|
|
19
|
+
};
|
|
20
|
+
export declare const serializeQueryOptions: <T>(options: QueryOptionsCollection<T>) => SerializedQueryOption[];
|
|
21
|
+
/** How the receiver finds a collection it was sent the NAME of. */
|
|
22
|
+
export type SchemaResolver = (collectionName: string) => CompiledSchema<any> | null;
|
|
23
|
+
/**
|
|
24
|
+
* A filter the RECEIVER adds to every read of a collection, whatever the sender asked for.
|
|
25
|
+
*
|
|
26
|
+
* Returns `null` for a collection with nothing to add. See `createRequestHandler` for the policy
|
|
27
|
+
* side; this is only how it reaches the options.
|
|
28
|
+
*/
|
|
29
|
+
export type ScopeProvider = (schema: CompiledSchema<any>) => Expression | null;
|
|
30
|
+
/**
|
|
31
|
+
* Rebuilds query options from their wire form, against the receiver's own schemas.
|
|
32
|
+
*
|
|
33
|
+
* The closures that were dropped are reconstructed here rather than sent:
|
|
34
|
+
*
|
|
35
|
+
* - a **sort selector** from its property, which is all `JsonTranslator.sort` reads;
|
|
36
|
+
* - a **filter predicate** from its expression tree, via `toStrictPredicate` — which THROWS rather
|
|
37
|
+
* than keeping a row it cannot judge, because on a receiver a filter that quietly stops filtering
|
|
38
|
+
* returns rows the requester excluded.
|
|
39
|
+
*
|
|
40
|
+
* @throws when a named property or collection is not declared by the receiver's schemas. A payload
|
|
41
|
+
* describing data this side does not have is a disagreement, and it has to be loud.
|
|
42
|
+
*/
|
|
43
|
+
export declare const deserializeQueryOptions: (serialized: SerializedQueryOption[], schema: CompiledSchema<any>, resolveSchema: SchemaResolver,
|
|
44
|
+
/**
|
|
45
|
+
* A receiver-side filter per collection, applied to this collection AND to every collection a
|
|
46
|
+
* join reaches. Prepended, so it is ANDed with whatever the sender sent and there is no order of
|
|
47
|
+
* options that removes it.
|
|
48
|
+
*/
|
|
49
|
+
scopeFor?: ScopeProvider) => QueryOptionsCollection<any>;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SerializedExpression } from "../../expressions";
|
|
2
|
+
import { JoinKind } from "../query/join";
|
|
3
|
+
import { QueryOrdering } from "../query/types";
|
|
4
|
+
/**
|
|
5
|
+
* The wire format for a whole Routier operation.
|
|
6
|
+
*
|
|
7
|
+
* This is what makes a plugin that owns no database possible: the query itself travels, and a
|
|
8
|
+
* receiver executes it against whatever plugin IT has. Nothing here is HTTP-specific — it is plain
|
|
9
|
+
* JSON, so the same payload works over fetch, a WebSocket, a worker `postMessage`, or a queue.
|
|
10
|
+
*
|
|
11
|
+
* ## Two rules shape every type below
|
|
12
|
+
*
|
|
13
|
+
* 1. **No functions cross.** A query option carries live closures — a sort selector, a filter
|
|
14
|
+
* predicate, a map projection — and none of them survive `JSON.stringify`. Where a closure can
|
|
15
|
+
* be REBUILT from data it is dropped and reconstructed on arrival (a sort selector from its
|
|
16
|
+
* property, a filter predicate from its expression tree). Where it cannot, the option does not
|
|
17
|
+
* travel at all and the sender runs it locally; see `map` and `group`.
|
|
18
|
+
* 2. **The receiver's schema is the authority.** Collections are named, never described. A payload
|
|
19
|
+
* says "teams", and the receiver resolves its own compiled schema for that name. Sending a
|
|
20
|
+
* schema would let the sender decide what its properties are, which is backwards for anything
|
|
21
|
+
* crossing a trust boundary — and it is the same reason `expressionFromJson` takes the schema
|
|
22
|
+
* rather than reading an id out of the payload.
|
|
23
|
+
*/
|
|
24
|
+
/** A query option, in the form that survives a wire. */
|
|
25
|
+
export type SerializedQueryOption = {
|
|
26
|
+
name: "skip";
|
|
27
|
+
value: number;
|
|
28
|
+
} | {
|
|
29
|
+
name: "take";
|
|
30
|
+
value: number;
|
|
31
|
+
}
|
|
32
|
+
/** The selector is dropped and rebuilt from the property on arrival. */
|
|
33
|
+
| {
|
|
34
|
+
name: "sort";
|
|
35
|
+
value: {
|
|
36
|
+
propertyName: string;
|
|
37
|
+
direction: QueryOrdering;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The expression only — no closure and no params bag.
|
|
42
|
+
*
|
|
43
|
+
* A filter reaching a query option is already BOUND: `ParamReferenceExpression` never escapes
|
|
44
|
+
* the parser, so every param value is already a literal in the tree. The receiver rebuilds a
|
|
45
|
+
* runnable predicate from the tree with `toStrictPredicate`.
|
|
46
|
+
*/
|
|
47
|
+
| {
|
|
48
|
+
name: "filter";
|
|
49
|
+
value: {
|
|
50
|
+
expression: SerializedExpression;
|
|
51
|
+
};
|
|
52
|
+
} | {
|
|
53
|
+
name: "nearest";
|
|
54
|
+
value: {
|
|
55
|
+
propertyName: string;
|
|
56
|
+
vector: number[];
|
|
57
|
+
count: number;
|
|
58
|
+
};
|
|
59
|
+
} | {
|
|
60
|
+
name: "join";
|
|
61
|
+
value: {
|
|
62
|
+
kind: JoinKind;
|
|
63
|
+
/** Named, not described — the receiver resolves its own schema for it. */
|
|
64
|
+
innerCollectionName: string;
|
|
65
|
+
outerKeyPath: string;
|
|
66
|
+
innerKeyPath: string;
|
|
67
|
+
innerOptions: SerializedQueryOption[];
|
|
68
|
+
semiJoinKeyThreshold: number;
|
|
69
|
+
};
|
|
70
|
+
} | {
|
|
71
|
+
name: "count" | "min" | "max" | "sum" | "distinct";
|
|
72
|
+
value: true;
|
|
73
|
+
};
|
|
74
|
+
export type SerializedQueryRequest = {
|
|
75
|
+
kind: "query";
|
|
76
|
+
collectionName: string;
|
|
77
|
+
options: SerializedQueryOption[];
|
|
78
|
+
};
|
|
79
|
+
/** One entity update, as `EntityUpdateInfo` minus nothing — every field of it is already JSON. */
|
|
80
|
+
export type SerializedUpdate = {
|
|
81
|
+
entity: unknown;
|
|
82
|
+
changeType: "propertiesChanged" | "markedDirty" | "notModified";
|
|
83
|
+
delta: unknown;
|
|
84
|
+
concurrency?: {
|
|
85
|
+
column: string;
|
|
86
|
+
expected: number;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
export type SerializedSchemaChanges = {
|
|
90
|
+
collectionName: string;
|
|
91
|
+
adds: unknown[];
|
|
92
|
+
updates: SerializedUpdate[];
|
|
93
|
+
removes: unknown[];
|
|
94
|
+
};
|
|
95
|
+
export type SerializedPersistRequest = {
|
|
96
|
+
kind: "persist";
|
|
97
|
+
changes: SerializedSchemaChanges[];
|
|
98
|
+
};
|
|
99
|
+
export type SerializedDestroyRequest = {
|
|
100
|
+
kind: "destroy";
|
|
101
|
+
};
|
|
102
|
+
export type SerializedRequest = SerializedQueryRequest | SerializedPersistRequest | SerializedDestroyRequest;
|
|
103
|
+
/** What a receiver sends back. Errors are a value, not a transport status. */
|
|
104
|
+
export type SerializedResponse = {
|
|
105
|
+
ok: true;
|
|
106
|
+
kind: "query";
|
|
107
|
+
value: unknown;
|
|
108
|
+
} | {
|
|
109
|
+
ok: true;
|
|
110
|
+
kind: "persist";
|
|
111
|
+
changes: Array<{
|
|
112
|
+
collectionName: string;
|
|
113
|
+
adds: unknown[];
|
|
114
|
+
updates: unknown[];
|
|
115
|
+
removes: unknown[];
|
|
116
|
+
}>;
|
|
117
|
+
} | {
|
|
118
|
+
ok: true;
|
|
119
|
+
kind: "destroy";
|
|
120
|
+
} | {
|
|
121
|
+
ok: false;
|
|
122
|
+
error: string;
|
|
123
|
+
};
|
package/dist/results/Result.d.ts
CHANGED
|
@@ -11,13 +11,13 @@ declare abstract class BaseResult {
|
|
|
11
11
|
}
|
|
12
12
|
export declare class Result extends BaseResult {
|
|
13
13
|
static success<T>(data: T): ResultType<T>;
|
|
14
|
-
static success
|
|
14
|
+
static success(): ResultType<never>;
|
|
15
15
|
static error<T>(error: any): ResultType<T>;
|
|
16
16
|
static partial<T>(data: T, error: any): PartialResultType<T>;
|
|
17
17
|
}
|
|
18
18
|
export declare class PluginEventResult extends BaseResult {
|
|
19
19
|
static success<T>(id: string, data: T): PluginEventResultType<T>;
|
|
20
|
-
static success
|
|
20
|
+
static success(id: string): PluginEventResultType<never>;
|
|
21
21
|
static error<T>(id: string, error: any): PluginEventResultType<T>;
|
|
22
22
|
static partial<T>(id: string, data: T, error: any): PluginEventPartialResultType<T>;
|
|
23
23
|
static assertSuccess<T>(result: PluginEventResultType<T>): asserts result is {
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
"use strict";
|
|
3
|
+
var __webpack_modules__ = ({
|
|
4
|
+
718(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
5
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
6
|
+
D: () => (PluginEventResult),
|
|
7
|
+
Q: () => (Result)
|
|
8
|
+
});
|
|
9
|
+
class BaseResult {
|
|
10
|
+
static ERROR = "error";
|
|
11
|
+
static SUCCESS = "success";
|
|
12
|
+
static PARTIAL = "partial";
|
|
13
|
+
static resolve(result, resolve, reject) {
|
|
14
|
+
if (result.ok === BaseResult.SUCCESS) {
|
|
15
|
+
resolve(result.data);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (result.ok === BaseResult.PARTIAL) {
|
|
19
|
+
reject({
|
|
20
|
+
partial: result.data,
|
|
21
|
+
error: result.error
|
|
22
|
+
});
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
reject(result.error);
|
|
26
|
+
}
|
|
27
|
+
static assertSuccess(result) {
|
|
28
|
+
if (result.ok !== BaseResult.SUCCESS) {
|
|
29
|
+
throw new Error(`Expected success result, but got ${result.ok}: ${result.error}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
class Result extends BaseResult {
|
|
34
|
+
static success(data) {
|
|
35
|
+
return {
|
|
36
|
+
ok: Result.SUCCESS,
|
|
37
|
+
data
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
static error(error) {
|
|
41
|
+
return {
|
|
42
|
+
ok: Result.ERROR,
|
|
43
|
+
error
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
static partial(data, error) {
|
|
47
|
+
return {
|
|
48
|
+
ok: Result.PARTIAL,
|
|
49
|
+
data,
|
|
50
|
+
error
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
class PluginEventResult extends BaseResult {
|
|
55
|
+
static success(id, data) {
|
|
56
|
+
return {
|
|
57
|
+
id,
|
|
58
|
+
ok: Result.SUCCESS,
|
|
59
|
+
data
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
static error(id, error) {
|
|
63
|
+
return {
|
|
64
|
+
id,
|
|
65
|
+
ok: Result.ERROR,
|
|
66
|
+
error
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
static partial(id, data, error) {
|
|
70
|
+
return {
|
|
71
|
+
id,
|
|
72
|
+
ok: Result.PARTIAL,
|
|
73
|
+
data,
|
|
74
|
+
error
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
static assertSuccess(result) {
|
|
78
|
+
if (result.ok !== Result.SUCCESS) {
|
|
79
|
+
throw new Error(`Expected success result, but got ${result.ok}: ${result.error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
});
|
|
88
|
+
// The module cache
|
|
89
|
+
var __webpack_module_cache__ = {};
|
|
90
|
+
|
|
91
|
+
// The require function
|
|
92
|
+
function __webpack_require__(moduleId) {
|
|
93
|
+
|
|
94
|
+
// Check if module is in cache
|
|
95
|
+
var cachedModule = __webpack_module_cache__[moduleId];
|
|
96
|
+
if (cachedModule !== undefined) {
|
|
97
|
+
return cachedModule.exports;
|
|
98
|
+
}
|
|
99
|
+
// Create a new module (and put it into the cache)
|
|
100
|
+
var module = (__webpack_module_cache__[moduleId] = {
|
|
101
|
+
exports: {}
|
|
102
|
+
});
|
|
103
|
+
// Execute the module function
|
|
104
|
+
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
105
|
+
|
|
106
|
+
// Return the exports of the module
|
|
107
|
+
return module.exports;
|
|
108
|
+
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// webpack/runtime/define_property_getters
|
|
112
|
+
(() => {
|
|
113
|
+
__webpack_require__.d = (exports, definition) => {
|
|
114
|
+
for(var key in definition) {
|
|
115
|
+
if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
116
|
+
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
})();
|
|
121
|
+
// webpack/runtime/has_own_property
|
|
122
|
+
(() => {
|
|
123
|
+
__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
124
|
+
})();
|
|
125
|
+
// webpack/runtime/make_namespace_object
|
|
126
|
+
(() => {
|
|
127
|
+
// define __esModule on exports
|
|
128
|
+
__webpack_require__.r = (exports) => {
|
|
129
|
+
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
130
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
131
|
+
}
|
|
132
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
133
|
+
};
|
|
134
|
+
})();
|
|
135
|
+
var __webpack_exports__ = {};
|
|
136
|
+
// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
|
|
137
|
+
(() => {
|
|
138
|
+
// ESM COMPAT FLAG
|
|
139
|
+
__webpack_require__.r(__webpack_exports__);
|
|
140
|
+
|
|
141
|
+
// EXPORTS
|
|
142
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
143
|
+
PluginEventResult: () => (/* reexport */ Result/* .PluginEventResult */.D),
|
|
144
|
+
toPromise: () => (/* reexport */ toPromise),
|
|
145
|
+
Result: () => (/* reexport */ Result/* .Result */.Q)
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// EXTERNAL MODULE: ./src/results/Result.ts
|
|
149
|
+
var Result = __webpack_require__(718);
|
|
150
|
+
;// CONCATENATED MODULE: ./src/results/utils.ts
|
|
151
|
+
|
|
152
|
+
function toPromise(fn) {
|
|
153
|
+
return new Promise((resolve, reject)=>{
|
|
154
|
+
fn((r)=>{
|
|
155
|
+
if (r.ok === Result/* .Result.ERROR */.Q.ERROR) {
|
|
156
|
+
reject(r.error);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
resolve(r.data);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
;// CONCATENATED MODULE: ./src/results/index.ts
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
})();
|
|
170
|
+
|
|
171
|
+
module.exports = __webpack_exports__;
|
|
172
|
+
})()
|
|
173
|
+
;
|
|
174
|
+
//# sourceMappingURL=index.cjs.map
|