ultimabase 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +4 -2
- package/dist/access.d.ts +62 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/access.js +258 -0
- package/dist/adapter-errors.d.ts +43 -0
- package/dist/adapter-errors.d.ts.map +1 -0
- package/dist/adapter-errors.js +72 -0
- package/dist/adapter-json.d.ts +20 -0
- package/dist/adapter-json.d.ts.map +1 -0
- package/dist/adapter-json.js +2 -0
- package/dist/adapter-migrations.d.ts +90 -0
- package/dist/adapter-migrations.d.ts.map +1 -0
- package/dist/adapter-migrations.js +1 -0
- package/dist/adapter.d.ts +333 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +5 -0
- package/dist/aggregate.d.ts +31 -0
- package/dist/aggregate.d.ts.map +1 -0
- package/dist/aggregate.js +99 -0
- package/dist/app-internals.d.ts +10 -0
- package/dist/app-internals.d.ts.map +1 -0
- package/dist/app-internals.js +12 -0
- package/dist/app-options.d.ts +22 -0
- package/dist/app-options.d.ts.map +1 -0
- package/dist/app-options.js +3 -0
- package/dist/cascade.d.ts +47 -0
- package/dist/cascade.d.ts.map +1 -0
- package/dist/cascade.js +209 -0
- package/dist/cli-config.d.ts +6 -0
- package/dist/cli-config.d.ts.map +1 -0
- package/dist/cli-config.js +45 -0
- package/dist/cli-deploy.d.ts +14 -0
- package/dist/cli-deploy.d.ts.map +1 -0
- package/dist/cli-deploy.js +193 -0
- package/dist/cli-main.d.ts +15 -0
- package/dist/cli-main.d.ts.map +1 -0
- package/dist/cli-main.js +155 -0
- package/dist/cli-migrate.d.ts +20 -0
- package/dist/cli-migrate.d.ts.map +1 -0
- package/dist/cli-migrate.js +105 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +4 -0
- package/dist/complete.d.ts +13 -0
- package/dist/complete.d.ts.map +1 -0
- package/dist/complete.js +60 -0
- package/dist/console-logger.d.ts +3 -0
- package/dist/console-logger.d.ts.map +1 -0
- package/dist/console-logger.js +62 -0
- package/dist/create-many.d.ts +7 -0
- package/dist/create-many.d.ts.map +1 -0
- package/dist/create-many.js +88 -0
- package/dist/decimal.d.ts +23 -0
- package/dist/decimal.d.ts.map +1 -0
- package/dist/decimal.js +50 -0
- package/dist/define-app.d.ts +59 -0
- package/dist/define-app.d.ts.map +1 -0
- package/dist/define-app.js +5 -0
- package/dist/define-enum.d.ts +6 -0
- package/dist/define-enum.d.ts.map +1 -0
- package/dist/define-enum.js +18 -0
- package/dist/define-function.d.ts +25 -0
- package/dist/define-function.d.ts.map +1 -0
- package/dist/define-function.js +111 -0
- package/dist/define-model.d.ts +48 -0
- package/dist/define-model.d.ts.map +1 -0
- package/dist/define-model.js +85 -0
- package/dist/definition.d.ts +179 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +165 -0
- package/dist/delete-many.d.ts +13 -0
- package/dist/delete-many.d.ts.map +1 -0
- package/dist/delete-many.js +58 -0
- package/dist/engine.d.ts +16 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +174 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +43 -0
- package/dist/exact.d.ts +20 -0
- package/dist/exact.d.ts.map +1 -0
- package/dist/exact.js +1 -0
- package/dist/feed.d.ts +6 -0
- package/dist/feed.d.ts.map +1 -0
- package/dist/feed.js +33 -0
- package/dist/field-codec.d.ts +11 -0
- package/dist/field-codec.d.ts.map +1 -0
- package/dist/field-codec.js +48 -0
- package/dist/field-rules.d.ts +57 -0
- package/dist/field-rules.d.ts.map +1 -0
- package/dist/field-rules.js +1 -0
- package/dist/field-type.d.ts +51 -0
- package/dist/field-type.d.ts.map +1 -0
- package/dist/field-type.js +106 -0
- package/dist/fields.d.ts +295 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +1 -0
- package/dist/function.d.ts +126 -0
- package/dist/function.d.ts.map +1 -0
- package/dist/function.js +1 -0
- package/dist/functions.d.ts +18 -0
- package/dist/functions.d.ts.map +1 -0
- package/dist/functions.js +99 -0
- package/dist/group-by.d.ts +10 -0
- package/dist/group-by.d.ts.map +1 -0
- package/dist/group-by.js +145 -0
- package/dist/group-having.d.ts +8 -0
- package/dist/group-having.d.ts.map +1 -0
- package/dist/group-having.js +97 -0
- package/dist/hooks.d.ts +41 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +149 -0
- package/dist/hosts.d.ts +3 -0
- package/dist/hosts.d.ts.map +1 -0
- package/dist/hosts.js +8 -0
- package/dist/identify.d.ts +15 -0
- package/dist/identify.d.ts.map +1 -0
- package/dist/identify.js +71 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/internal.d.ts +28 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +39 -0
- package/dist/lifecycle.d.ts +21 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +149 -0
- package/dist/list-update.d.ts +12 -0
- package/dist/list-update.d.ts.map +1 -0
- package/dist/list-update.js +52 -0
- package/dist/live.d.ts +37 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +139 -0
- package/dist/manifest.d.ts +11 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +60 -0
- package/dist/memory-aggregate.d.ts +7 -0
- package/dist/memory-aggregate.d.ts.map +1 -0
- package/dist/memory-aggregate.js +107 -0
- package/dist/memory-conditions.d.ts +8 -0
- package/dist/memory-conditions.d.ts.map +1 -0
- package/dist/memory-conditions.js +82 -0
- package/dist/memory-draft.d.ts +34 -0
- package/dist/memory-draft.d.ts.map +1 -0
- package/dist/memory-draft.js +255 -0
- package/dist/memory-json.d.ts +6 -0
- package/dist/memory-json.d.ts.map +1 -0
- package/dist/memory-json.js +86 -0
- package/dist/memory-read.d.ts +45 -0
- package/dist/memory-read.d.ts.map +1 -0
- package/dist/memory-read.js +244 -0
- package/dist/memory-search.d.ts +16 -0
- package/dist/memory-search.d.ts.map +1 -0
- package/dist/memory-search.js +110 -0
- package/dist/memory-values.d.ts +23 -0
- package/dist/memory-values.d.ts.map +1 -0
- package/dist/memory-values.js +82 -0
- package/dist/memory.d.ts +4 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +157 -0
- package/dist/migrate.d.ts +22 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +131 -0
- package/dist/model.d.ts +239 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +1 -0
- package/dist/nested-write.d.ts +64 -0
- package/dist/nested-write.d.ts.map +1 -0
- package/dist/nested-write.js +274 -0
- package/dist/number-update.d.ts +18 -0
- package/dist/number-update.d.ts.map +1 -0
- package/dist/number-update.js +96 -0
- package/dist/plugin-app.d.ts +48 -0
- package/dist/plugin-app.d.ts.map +1 -0
- package/dist/plugin-app.js +230 -0
- package/dist/plugin-code.d.ts +17 -0
- package/dist/plugin-code.d.ts.map +1 -0
- package/dist/plugin-code.js +125 -0
- package/dist/plugin-use.d.ts +22 -0
- package/dist/plugin-use.d.ts.map +1 -0
- package/dist/plugin-use.js +161 -0
- package/dist/plugin.d.ts +357 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +17 -0
- package/dist/query-aggregate.d.ts +82 -0
- package/dist/query-aggregate.d.ts.map +1 -0
- package/dist/query-aggregate.js +1 -0
- package/dist/query-args.d.ts +41 -0
- package/dist/query-args.d.ts.map +1 -0
- package/dist/query-args.js +263 -0
- package/dist/query-bulk.d.ts +35 -0
- package/dist/query-bulk.d.ts.map +1 -0
- package/dist/query-bulk.js +1 -0
- package/dist/query-conditions.d.ts +9 -0
- package/dist/query-conditions.d.ts.map +1 -0
- package/dist/query-conditions.js +46 -0
- package/dist/query-context.d.ts +32 -0
- package/dist/query-context.d.ts.map +1 -0
- package/dist/query-context.js +55 -0
- package/dist/query-filter.d.ts +46 -0
- package/dist/query-filter.d.ts.map +1 -0
- package/dist/query-filter.js +1 -0
- package/dist/query-group.d.ts +82 -0
- package/dist/query-group.d.ts.map +1 -0
- package/dist/query-group.js +1 -0
- package/dist/query-json.d.ts +9 -0
- package/dist/query-json.d.ts.map +1 -0
- package/dist/query-json.js +66 -0
- package/dist/query-order.d.ts +15 -0
- package/dist/query-order.d.ts.map +1 -0
- package/dist/query-order.js +115 -0
- package/dist/query-project.d.ts +15 -0
- package/dist/query-project.d.ts.map +1 -0
- package/dist/query-project.js +45 -0
- package/dist/query-search.d.ts +24 -0
- package/dist/query-search.d.ts.map +1 -0
- package/dist/query-search.js +2 -0
- package/dist/query-values.d.ts +28 -0
- package/dist/query-values.d.ts.map +1 -0
- package/dist/query-values.js +91 -0
- package/dist/query-where.d.ts +46 -0
- package/dist/query-where.d.ts.map +1 -0
- package/dist/query-where.js +200 -0
- package/dist/query-write.d.ts +14 -0
- package/dist/query-write.d.ts.map +1 -0
- package/dist/query-write.js +260 -0
- package/dist/query.d.ts +254 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +1 -0
- package/dist/record.d.ts +257 -0
- package/dist/record.d.ts.map +1 -0
- package/dist/record.js +1 -0
- package/dist/recorder.d.ts +32 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +152 -0
- package/dist/relation-write.d.ts +41 -0
- package/dist/relation-write.d.ts.map +1 -0
- package/dist/relation-write.js +112 -0
- package/dist/relations.d.ts +42 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/relations.js +119 -0
- package/dist/rules.d.ts +97 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +71 -0
- package/dist/running.d.ts +29 -0
- package/dist/running.d.ts.map +1 -0
- package/dist/running.js +39 -0
- package/dist/schema-indexes.d.ts +11 -0
- package/dist/schema-indexes.d.ts.map +1 -0
- package/dist/schema-indexes.js +59 -0
- package/dist/schema-virtuals.d.ts +19 -0
- package/dist/schema-virtuals.d.ts.map +1 -0
- package/dist/schema-virtuals.js +100 -0
- package/dist/schema.d.ts +35 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +267 -0
- package/dist/scope.d.ts +46 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +82 -0
- package/dist/scratch.d.ts +14 -0
- package/dist/scratch.d.ts.map +1 -0
- package/dist/scratch.js +10 -0
- package/dist/serve.d.ts +2 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +4 -0
- package/dist/symbols.d.ts +10 -0
- package/dist/symbols.d.ts.map +1 -0
- package/dist/symbols.js +1 -0
- package/dist/transaction.d.ts +28 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +156 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/update-many.d.ts +7 -0
- package/dist/update-many.d.ts.map +1 -0
- package/dist/update-many.js +182 -0
- package/dist/uuid.d.ts +7 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +48 -0
- package/dist/validation.d.ts +24 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +72 -0
- package/dist/virtual-read.d.ts +9 -0
- package/dist/virtual-read.d.ts.map +1 -0
- package/dist/virtual-read.js +145 -0
- package/dist/virtual.d.ts +142 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +1 -0
- package/dist/write-context.d.ts +46 -0
- package/dist/write-context.d.ts.map +1 -0
- package/dist/write-context.js +102 -0
- package/dist/write-data.d.ts +26 -0
- package/dist/write-data.d.ts.map +1 -0
- package/dist/write-data.js +144 -0
- package/dist/write-plan.d.ts +107 -0
- package/dist/write-plan.d.ts.map +1 -0
- package/dist/write-plan.js +170 -0
- package/dist/write-target.d.ts +17 -0
- package/dist/write-target.d.ts.map +1 -0
- package/dist/write-target.js +59 -0
- package/dist/writes.d.ts +23 -0
- package/dist/writes.d.ts.map +1 -0
- package/dist/writes.js +246 -0
- package/dist/writing.d.ts +10 -0
- package/dist/writing.d.ts.map +1 -0
- package/dist/writing.js +66 -0
- package/package.json +42 -3
- package/src/access.ts +329 -0
- package/src/adapter-errors.ts +89 -0
- package/src/adapter-json.ts +21 -0
- package/src/adapter-migrations.ts +98 -0
- package/src/adapter.ts +363 -0
- package/src/aggregate.ts +136 -0
- package/src/app-internals.ts +26 -0
- package/src/app-options.ts +24 -0
- package/src/cascade.ts +297 -0
- package/src/cli-config.ts +45 -0
- package/src/cli-deploy.ts +235 -0
- package/src/cli-main.ts +166 -0
- package/src/cli-migrate.ts +143 -0
- package/src/cli.ts +5 -0
- package/src/complete.ts +73 -0
- package/src/console-logger.ts +87 -0
- package/src/create-many.ts +126 -0
- package/src/decimal.ts +74 -0
- package/src/define-app.ts +108 -0
- package/src/define-enum.ts +26 -0
- package/src/define-function.ts +188 -0
- package/src/define-model.ts +220 -0
- package/src/definition.ts +352 -0
- package/src/delete-many.ts +76 -0
- package/src/engine.ts +281 -0
- package/src/errors.ts +97 -0
- package/src/exact.ts +49 -0
- package/src/feed.ts +39 -0
- package/src/field-codec.ts +72 -0
- package/src/field-rules.ts +77 -0
- package/src/field-type.ts +219 -0
- package/src/fields.ts +383 -0
- package/src/function.ts +143 -0
- package/src/functions.ts +154 -0
- package/src/group-by.ts +186 -0
- package/src/group-having.ts +143 -0
- package/src/hooks.ts +215 -0
- package/src/hosts.ts +11 -0
- package/src/identify.ts +95 -0
- package/src/index.ts +125 -0
- package/src/internal.ts +68 -0
- package/src/lifecycle.ts +214 -0
- package/src/list-update.ts +71 -0
- package/src/live.ts +199 -0
- package/src/manifest.ts +71 -0
- package/src/memory-aggregate.ts +162 -0
- package/src/memory-conditions.ts +88 -0
- package/src/memory-draft.ts +319 -0
- package/src/memory-json.ts +91 -0
- package/src/memory-read.ts +311 -0
- package/src/memory-search.ts +149 -0
- package/src/memory-values.ts +106 -0
- package/src/memory.ts +173 -0
- package/src/migrate.ts +152 -0
- package/src/model.ts +312 -0
- package/src/nested-write.ts +390 -0
- package/src/number-update.ts +142 -0
- package/src/plugin-app.ts +308 -0
- package/src/plugin-code.ts +158 -0
- package/src/plugin-use.ts +217 -0
- package/src/plugin.ts +400 -0
- package/src/query-aggregate.ts +96 -0
- package/src/query-args.ts +375 -0
- package/src/query-bulk.ts +53 -0
- package/src/query-conditions.ts +53 -0
- package/src/query-context.ts +104 -0
- package/src/query-filter.ts +54 -0
- package/src/query-group.ts +137 -0
- package/src/query-json.ts +90 -0
- package/src/query-order.ts +158 -0
- package/src/query-project.ts +73 -0
- package/src/query-search.ts +31 -0
- package/src/query-values.ts +131 -0
- package/src/query-where.ts +318 -0
- package/src/query-write.ts +360 -0
- package/src/query.ts +400 -0
- package/src/record.ts +379 -0
- package/src/recorder.ts +212 -0
- package/src/relation-write.ts +176 -0
- package/src/relations.ts +165 -0
- package/src/rules.ts +188 -0
- package/src/running.ts +62 -0
- package/src/schema-indexes.ts +88 -0
- package/src/schema-virtuals.ts +134 -0
- package/src/schema.ts +367 -0
- package/src/scope.ts +123 -0
- package/src/scratch.ts +28 -0
- package/src/serve.ts +5 -0
- package/src/symbols.ts +11 -0
- package/src/transaction.ts +211 -0
- package/src/types.ts +79 -0
- package/src/update-many.ts +268 -0
- package/src/uuid.ts +51 -0
- package/src/validation.ts +107 -0
- package/src/virtual-read.ts +198 -0
- package/src/virtual.ts +187 -0
- package/src/write-context.ts +170 -0
- package/src/write-data.ts +188 -0
- package/src/write-plan.ts +273 -0
- package/src/write-target.ts +92 -0
- package/src/writes.ts +361 -0
- package/src/writing.ts +93 -0
package/src/errors.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// The errors a client may see (D-28, D-72). Any other error is masked as
|
|
2
|
+
// `INTERNAL` with a correlation id. `Refused` is for the developer (D-119).
|
|
3
|
+
import type { JsonValue } from './fields.ts'
|
|
4
|
+
|
|
5
|
+
/** The kernel's codes; a transport gives each its own status (D-72). */
|
|
6
|
+
export type ErrorCode =
|
|
7
|
+
| 'ACCESS_DENIED'
|
|
8
|
+
| 'NOT_FOUND'
|
|
9
|
+
| 'VALIDATION_FAILED'
|
|
10
|
+
| 'UNIQUE_VIOLATION'
|
|
11
|
+
| 'RELATION_RESTRICTED'
|
|
12
|
+
| 'UNAUTHENTICATED'
|
|
13
|
+
| 'INVALID_CREDENTIALS'
|
|
14
|
+
| 'TOO_MANY_ATTEMPTS'
|
|
15
|
+
| 'INTERNAL'
|
|
16
|
+
|
|
17
|
+
/** One failing value, as Standard Schema reports it (D-23). */
|
|
18
|
+
export type Issue = {
|
|
19
|
+
readonly path: readonly (string | number)[]
|
|
20
|
+
readonly message: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type Details<C> = C extends 'VALIDATION_FAILED'
|
|
24
|
+
? { readonly issues: readonly Issue[] }
|
|
25
|
+
: C extends 'TOO_MANY_ATTEMPTS'
|
|
26
|
+
? { /** In seconds (D-113). */ readonly retryAfter: number }
|
|
27
|
+
: JsonValue
|
|
28
|
+
|
|
29
|
+
/** An error whose code, message and details reach the client. */
|
|
30
|
+
export interface PublicError extends Error {
|
|
31
|
+
readonly code: ErrorCode | Uppercase<string>
|
|
32
|
+
readonly details?: JsonValue
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type PublicErrorConstructor = {
|
|
36
|
+
new <const C extends string>(
|
|
37
|
+
code: C extends Uppercase<C> ? C : Uppercase<C>,
|
|
38
|
+
message: string,
|
|
39
|
+
options?: { readonly details?: Details<C>; readonly cause?: unknown },
|
|
40
|
+
): PublicError
|
|
41
|
+
readonly prototype: PublicError
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class PublicErrorClass extends Error {
|
|
45
|
+
readonly code: string
|
|
46
|
+
readonly details?: JsonValue
|
|
47
|
+
|
|
48
|
+
constructor(
|
|
49
|
+
code: string,
|
|
50
|
+
message: string,
|
|
51
|
+
options?: { readonly details?: JsonValue; readonly cause?: unknown },
|
|
52
|
+
) {
|
|
53
|
+
super(
|
|
54
|
+
message,
|
|
55
|
+
options && 'cause' in options ? { cause: options.cause } : {},
|
|
56
|
+
)
|
|
57
|
+
this.name = 'PublicError'
|
|
58
|
+
this.code = code
|
|
59
|
+
if (options?.details !== undefined) this.details = options.details
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The code is a kernel code, which keeps its meaning, or the application's
|
|
65
|
+
* own, in capitals. Only the constructor is generic: `instanceof` would type
|
|
66
|
+
* a generic class's members as `any`.
|
|
67
|
+
*/
|
|
68
|
+
export const PublicError: PublicErrorConstructor =
|
|
69
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the class is the constructor; only its generic signature is added.
|
|
70
|
+
PublicErrorClass as unknown as PublicErrorConstructor
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* A query argument the kernel does not know (D-20): a bug of the server
|
|
74
|
+
* code, never public.
|
|
75
|
+
*/
|
|
76
|
+
export class InvalidQuery extends Error {
|
|
77
|
+
readonly code = 'INVALID_QUERY'
|
|
78
|
+
readonly path: string
|
|
79
|
+
|
|
80
|
+
constructor(path: string, message: string) {
|
|
81
|
+
super(message)
|
|
82
|
+
this.name = 'InvalidQuery'
|
|
83
|
+
this.path = path
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* A configuration refused while the application is defined or starts, whose
|
|
89
|
+
* message says what is wrong and how to fix it: a command prints it without
|
|
90
|
+
* its stack (D-119).
|
|
91
|
+
*/
|
|
92
|
+
export class Refused extends Error {
|
|
93
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
94
|
+
super(message, options)
|
|
95
|
+
this.name = 'Refused'
|
|
96
|
+
}
|
|
97
|
+
}
|
package/src/exact.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Query arguments are inferred (`const A`), so TypeScript skips the excess
|
|
2
|
+
// property check: a misspelled key next to a valid one would pass. `Exact`
|
|
3
|
+
// walks the written arguments against their schema and turns every unknown
|
|
4
|
+
// key into a message, reported on that key's line. It is `unknown` where the
|
|
5
|
+
// arguments fit, so a valid query costs one walk and no comparison.
|
|
6
|
+
type Leaf =
|
|
7
|
+
string | number | boolean | bigint | symbol | Date | null | undefined
|
|
8
|
+
type Shapes<S> = Exclude<
|
|
9
|
+
Extract<S, object>,
|
|
10
|
+
Date | readonly unknown[] | ((...args: never[]) => unknown)
|
|
11
|
+
>
|
|
12
|
+
type Keys<S> = S extends unknown ? keyof S : never
|
|
13
|
+
type At<S, K> = S extends unknown ? (K extends keyof S ? S[K] : never) : never
|
|
14
|
+
type Items<S> = Extract<S, readonly unknown[]>[number]
|
|
15
|
+
// Identical, not only assignable both ways: an index signature is not.
|
|
16
|
+
type Same<A, S> =
|
|
17
|
+
// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- `T` probes how each type relates, the usual identity test.
|
|
18
|
+
(<T>() => T extends A ? 1 : 2) extends <T>() => T extends S ? 1 : 2
|
|
19
|
+
? true
|
|
20
|
+
: false
|
|
21
|
+
type Fine<O> = [keyof O] extends [never] ? unknown : O
|
|
22
|
+
// Only the misspelled keys, and the keys whose value holds one, are kept.
|
|
23
|
+
type Fields<A, S> = Fine<{
|
|
24
|
+
readonly [
|
|
25
|
+
K in keyof A as K extends Keys<S>
|
|
26
|
+
? unknown extends Exact<A[K], At<S, K>>
|
|
27
|
+
? never
|
|
28
|
+
: K
|
|
29
|
+
: K
|
|
30
|
+
]: K extends Keys<S>
|
|
31
|
+
? Exact<A[K], At<S, K>>
|
|
32
|
+
: { readonly error: `'${K & string}' is not a key here` }
|
|
33
|
+
}>
|
|
34
|
+
// A written key is required; a type whose keys are all optional, such as a
|
|
35
|
+
// variable typed `Where<F>`, was checked where it was written. Walking it
|
|
36
|
+
// would recurse through every relation. So would arguments inferred as their
|
|
37
|
+
// own schema, as on a failed call.
|
|
38
|
+
export type Exact<A, S> = [A] extends [Leaf]
|
|
39
|
+
? unknown
|
|
40
|
+
: {} extends A
|
|
41
|
+
? unknown
|
|
42
|
+
: Same<A, S> extends true
|
|
43
|
+
? unknown
|
|
44
|
+
: A extends readonly unknown[]
|
|
45
|
+
? Fits<A, { readonly [I in keyof A]: Exact<A[I], Items<S>> }>
|
|
46
|
+
: Fields<A, Shapes<S>>
|
|
47
|
+
// A list whose every item fits is `unknown`, like an object: a list of rows
|
|
48
|
+
// to create sits inside another one (D-128).
|
|
49
|
+
type Fits<A, E> = { readonly [I in keyof A]: unknown } extends E ? unknown : E
|
package/src/feed.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// The change feed (D-154): what each commit changed, to the plugins that
|
|
2
|
+
// take it. The adapter feeds nothing when none does.
|
|
3
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
4
|
+
import type { Feed } from './adapter.ts'
|
|
5
|
+
import type { PluginRecord } from './definition.ts'
|
|
6
|
+
import { inOrder, type Installed } from './plugin-app.ts'
|
|
7
|
+
|
|
8
|
+
// Outside every async context: an adapter may deliver from within the write,
|
|
9
|
+
// whose transaction and recording a hook's queries must not join.
|
|
10
|
+
const outside = AsyncLocalStorage.snapshot()
|
|
11
|
+
|
|
12
|
+
/** Calls each plugin's `changed` and `missed`, in declaration order. */
|
|
13
|
+
export function feedOf(
|
|
14
|
+
records: readonly PluginRecord[],
|
|
15
|
+
plugins: readonly Installed[],
|
|
16
|
+
): Feed | undefined {
|
|
17
|
+
const takers = inOrder(records, plugins).filter(
|
|
18
|
+
({ code }) => code.changed !== undefined,
|
|
19
|
+
)
|
|
20
|
+
if (takers.length === 0) return undefined
|
|
21
|
+
// A plugin failing on a change must not stop the others nor the write.
|
|
22
|
+
const each = (hook: 'changed' | 'missed', args: readonly unknown[]): void => {
|
|
23
|
+
for (const { code, context } of takers) {
|
|
24
|
+
const run = code[hook]
|
|
25
|
+
if (run === undefined) continue
|
|
26
|
+
try {
|
|
27
|
+
outside(() => {
|
|
28
|
+
Reflect.apply(run, undefined, [...args, context])
|
|
29
|
+
})
|
|
30
|
+
} catch (error) {
|
|
31
|
+
context.logger.error({ err: error }, `The plugin's ${hook} failed.`)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
changed: (changes) => each('changed', [changes]),
|
|
37
|
+
missed: () => each('missed', []),
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Plugin field values decoded as rows leave the adapter (D-122): code, rules
|
|
2
|
+
// and hooks read the value, the adapter its stored form.
|
|
3
|
+
import type { Nested, Row } from './adapter.ts'
|
|
4
|
+
import type { Codec } from './definition.ts'
|
|
5
|
+
import { isObject } from './query-where.ts'
|
|
6
|
+
import type { ModelInfo } from './schema.ts'
|
|
7
|
+
|
|
8
|
+
type Models = ReadonlyMap<string, ModelInfo>
|
|
9
|
+
type Codecs = readonly (readonly [string, Codec])[]
|
|
10
|
+
|
|
11
|
+
const known = new WeakMap<ModelInfo, Codecs>()
|
|
12
|
+
|
|
13
|
+
function codecsOf(model: ModelInfo): Codecs {
|
|
14
|
+
const found = known.get(model)
|
|
15
|
+
if (found !== undefined) return found
|
|
16
|
+
const codecs = [...model.fields.values()].flatMap((field) =>
|
|
17
|
+
field.kind === 'scalar' && field.codec !== undefined
|
|
18
|
+
? [[field.name, field.codec] as const]
|
|
19
|
+
: [],
|
|
20
|
+
)
|
|
21
|
+
known.set(model, codecs)
|
|
22
|
+
return codecs
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The row with its plugin fields decoded, its included rows' too. */
|
|
26
|
+
function decodedRow(
|
|
27
|
+
models: Models,
|
|
28
|
+
model: ModelInfo,
|
|
29
|
+
read: Nested,
|
|
30
|
+
row: Row,
|
|
31
|
+
): Row {
|
|
32
|
+
const changed: { [field: string]: unknown } = {}
|
|
33
|
+
// `null` is stored as is, never decoded.
|
|
34
|
+
for (const [name, codec] of codecsOf(model)) {
|
|
35
|
+
const value = row[name]
|
|
36
|
+
if (value !== undefined && value !== null) {
|
|
37
|
+
changed[name] = codec.decode(value)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const [name, nested] of Object.entries(read.include ?? {})) {
|
|
41
|
+
const field = model.fields.get(name)
|
|
42
|
+
const target =
|
|
43
|
+
field === undefined || field.kind === 'scalar'
|
|
44
|
+
? undefined
|
|
45
|
+
: models.get(field.target)
|
|
46
|
+
const value = row[name]
|
|
47
|
+
if (target === undefined) continue
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
changed[name] = value.map((item: unknown) =>
|
|
50
|
+
isRow(item) ? decodedRow(models, target, nested, item) : item,
|
|
51
|
+
)
|
|
52
|
+
} else if (isRow(value)) {
|
|
53
|
+
changed[name] = decodedRow(models, target, nested, value)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return Object.keys(changed).length === 0 ? row : { ...row, ...changed }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** A value the kernel reads as a row: an object with a string `id`. */
|
|
60
|
+
export const isRow = (value: unknown): value is Row =>
|
|
61
|
+
isObject(value) && typeof value['id'] === 'string'
|
|
62
|
+
|
|
63
|
+
/** The rows `read` returned, decoded. */
|
|
64
|
+
export function decoded(
|
|
65
|
+
models: Models,
|
|
66
|
+
read: (Nested & { readonly model: string }) | undefined,
|
|
67
|
+
rows: Row[],
|
|
68
|
+
): Row[] {
|
|
69
|
+
const model = read === undefined ? undefined : models.get(read.model)
|
|
70
|
+
if (read === undefined || model === undefined) return rows
|
|
71
|
+
return rows.map((row) => decodedRow(models, model, read, row))
|
|
72
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// The rules a field's `.with` takes (D-44), and the plugins' own (D-57).
|
|
2
|
+
import type { RecordFor } from './record.ts'
|
|
3
|
+
import type { Caller } from './rules.ts'
|
|
4
|
+
import type { declaredRecord } from './symbols.ts'
|
|
5
|
+
|
|
6
|
+
// `R` is the record type the developer declares for the rules (D-44). It
|
|
7
|
+
// never derives from the model, which is still being typed here: that would
|
|
8
|
+
// be a cycle (TS7022).
|
|
9
|
+
type ReadFacts<R extends object> = {
|
|
10
|
+
readonly caller: Caller
|
|
11
|
+
readonly operation: 'read'
|
|
12
|
+
readonly record: RecordFor<R>
|
|
13
|
+
}
|
|
14
|
+
type CreateFacts<V> = {
|
|
15
|
+
readonly caller: Caller
|
|
16
|
+
readonly operation: 'create'
|
|
17
|
+
readonly value: V
|
|
18
|
+
}
|
|
19
|
+
type UpdateFacts<R extends object, V> = {
|
|
20
|
+
readonly caller: Caller
|
|
21
|
+
readonly operation: 'update'
|
|
22
|
+
readonly record: RecordFor<R>
|
|
23
|
+
readonly value: V
|
|
24
|
+
}
|
|
25
|
+
type Rule<F> = (facts: F) => boolean
|
|
26
|
+
// Named, so a type error shows the rule the developer wrote.
|
|
27
|
+
type FieldReadRule<R extends object> = Rule<ReadFacts<R>>
|
|
28
|
+
type FieldCreateRule<V> = Rule<CreateFacts<V>>
|
|
29
|
+
type FieldUpdateRule<R extends object, V> = Rule<UpdateFacts<R, V>>
|
|
30
|
+
type FieldWriteRule<R extends object, V> = Rule<
|
|
31
|
+
CreateFacts<V> | UpdateFacts<R, V>
|
|
32
|
+
>
|
|
33
|
+
type FieldRule<R extends object, V> = Rule<
|
|
34
|
+
ReadFacts<R> | CreateFacts<V> | UpdateFacts<R, V>
|
|
35
|
+
>
|
|
36
|
+
|
|
37
|
+
/** A field keeps its declared record type, which `defineModel` checks. */
|
|
38
|
+
// Each declared field is kept as `(value: T) => T`, which only the same `T`
|
|
39
|
+
// fits: a wider or a narrower type fails, and the error shows the model's.
|
|
40
|
+
export type Declared<R> = [R] extends [never]
|
|
41
|
+
? unknown
|
|
42
|
+
: {
|
|
43
|
+
readonly [declaredRecord]: {
|
|
44
|
+
readonly [P in keyof R]: (value: R[P]) => R[P]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** One rule, or one rule per operation (D-44). */
|
|
49
|
+
export type FieldAccess<R extends object, V> =
|
|
50
|
+
| FieldRule<R, V>
|
|
51
|
+
| {
|
|
52
|
+
readonly read?: FieldReadRule<R>
|
|
53
|
+
readonly create?: FieldCreateRule<V>
|
|
54
|
+
readonly update?: FieldUpdateRule<R, V>
|
|
55
|
+
readonly write?: FieldWriteRule<R, V>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The rules of the model's plugins for one field, each under the plugin's
|
|
60
|
+
* name and typed by the field's value (D-12, D-57).
|
|
61
|
+
*/
|
|
62
|
+
type PluginFieldRules<T, V> = {
|
|
63
|
+
readonly [
|
|
64
|
+
X in T as X extends {
|
|
65
|
+
readonly name: infer N extends string
|
|
66
|
+
readonly fieldWith: object
|
|
67
|
+
}
|
|
68
|
+
? N
|
|
69
|
+
: never
|
|
70
|
+
]?: X extends { readonly fieldWith: object }
|
|
71
|
+
? (X & { readonly value: V })['fieldWith']
|
|
72
|
+
: never
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type FieldWith<R extends object, V, T = never> = {
|
|
76
|
+
readonly access?: FieldAccess<R, V>
|
|
77
|
+
} & PluginFieldRules<T, V>
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// `defineFieldType` (D-32, D-122): a plugin's field type, stored through a
|
|
2
|
+
// kernel field and seen by code as the value its `decode` gives.
|
|
3
|
+
import type { Codec, FieldDefinition, FieldOptions } from './definition.ts'
|
|
4
|
+
import { build, fieldBuilders, fieldDefinitions } from './definition.ts'
|
|
5
|
+
import type {
|
|
6
|
+
DefaultFunction,
|
|
7
|
+
Described,
|
|
8
|
+
Field,
|
|
9
|
+
FieldBuilders,
|
|
10
|
+
JsonValue,
|
|
11
|
+
SchemaTypes,
|
|
12
|
+
StandardSchema,
|
|
13
|
+
} from './fields.ts'
|
|
14
|
+
import type { fieldType } from './symbols.ts'
|
|
15
|
+
import { standardOf } from './validation.ts'
|
|
16
|
+
|
|
17
|
+
/** A kernel scalar field, as `stored` returns it. */
|
|
18
|
+
type Stored = {
|
|
19
|
+
readonly [fieldType]: {
|
|
20
|
+
readonly kind: 'scalar'
|
|
21
|
+
readonly value: unknown
|
|
22
|
+
readonly options: unknown
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
type StoredValue<S> = S extends {
|
|
26
|
+
readonly [fieldType]: { readonly value: infer V }
|
|
27
|
+
}
|
|
28
|
+
? V
|
|
29
|
+
: never
|
|
30
|
+
type StoredOptions<S> = S extends {
|
|
31
|
+
readonly [fieldType]: { readonly options: infer O }
|
|
32
|
+
}
|
|
33
|
+
? O
|
|
34
|
+
: never
|
|
35
|
+
|
|
36
|
+
/** What `defineFieldType` takes (D-122), each function given the options. */
|
|
37
|
+
export type FieldTypeDefinition<P extends string, S, V, X, O extends object> = {
|
|
38
|
+
/** The plugin that provides the field type, which `plugins` lists (D-32). */
|
|
39
|
+
readonly plugin: P
|
|
40
|
+
/** The names of the field type's own options, beside `default` (D-152). */
|
|
41
|
+
readonly options?: readonly NoInfer<keyof O & string>[]
|
|
42
|
+
/** The kernel field that stores, filters and indexes the value. */
|
|
43
|
+
readonly stored: (f: FieldBuilders<never>, options: O) => S
|
|
44
|
+
readonly decode: (stored: StoredValue<S>, options: O) => V
|
|
45
|
+
readonly encode: (value: V, options: O) => StoredValue<S>
|
|
46
|
+
/** Takes the value or its JSON, and gives the value. */
|
|
47
|
+
readonly schema: X | ((options: O) => X)
|
|
48
|
+
/** What a client reads. */
|
|
49
|
+
readonly toJSON: (value: V, options: O) => JsonValue
|
|
50
|
+
/** What `toJSON` gives, which types it for clients (D-152). */
|
|
51
|
+
readonly shape?: StandardSchema | ((options: O) => StandardSchema)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** A field type's options: the stored field says whether it may be `null`. */
|
|
55
|
+
export type FieldTypeOptions<I> = Described & {
|
|
56
|
+
readonly default?: I | DefaultFunction<I>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** The builder `defineFieldType` returns (D-122). */
|
|
60
|
+
export type FieldType<
|
|
61
|
+
P extends string,
|
|
62
|
+
S,
|
|
63
|
+
V,
|
|
64
|
+
I,
|
|
65
|
+
// Weak, as `Described` is, so a name it lacks fails to compile.
|
|
66
|
+
O extends object = Described,
|
|
67
|
+
> = <const G extends FieldTypeOptions<I> & Partial<O> = {}>(
|
|
68
|
+
options?: G,
|
|
69
|
+
) => Field<V, StoredOptions<S> & G, P, never, I, true, S>
|
|
70
|
+
|
|
71
|
+
const storedOptions = new Set(['list', 'optional', 'precision', 'scale'])
|
|
72
|
+
const kernelOptions = new Set(['default', 'description'])
|
|
73
|
+
type Options = { readonly [key: string]: unknown }
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The stored field `stored` returns, a scalar with no rules; a value as its
|
|
77
|
+
* default fills the rows stored before the field (D-152).
|
|
78
|
+
*/
|
|
79
|
+
function storedOf(
|
|
80
|
+
plugin: string,
|
|
81
|
+
stored: unknown,
|
|
82
|
+
options: Options,
|
|
83
|
+
): FieldDefinition & { readonly kind: 'scalar' } {
|
|
84
|
+
if (typeof stored !== 'function') {
|
|
85
|
+
throw new TypeError(`defineFieldType(${plugin}): stored is a function.`)
|
|
86
|
+
}
|
|
87
|
+
const field: unknown = Reflect.apply(stored, undefined, [
|
|
88
|
+
fieldBuilders,
|
|
89
|
+
options,
|
|
90
|
+
])
|
|
91
|
+
const definition =
|
|
92
|
+
typeof field === 'object' && field !== null
|
|
93
|
+
? fieldDefinitions.get(field)
|
|
94
|
+
: undefined
|
|
95
|
+
if (definition?.kind !== 'scalar' || definition.rules !== undefined) {
|
|
96
|
+
throw new TypeError(
|
|
97
|
+
`defineFieldType(${plugin}): stored returns a kernel scalar field, without .with.`,
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
for (const [option, value] of Object.entries(definition.options)) {
|
|
101
|
+
const filled = option === 'default' && typeof value !== 'function'
|
|
102
|
+
if (!storedOptions.has(option) && !filled) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`defineFieldType(${plugin}): the stored field takes list, optional, precision, scale or a value as its default only, not ${option}.`,
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return definition
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function functionOf(
|
|
112
|
+
plugin: string,
|
|
113
|
+
definition: Options,
|
|
114
|
+
key: string,
|
|
115
|
+
options: Options,
|
|
116
|
+
): (value: unknown) => unknown {
|
|
117
|
+
const value = definition[key]
|
|
118
|
+
if (typeof value !== 'function') {
|
|
119
|
+
throw new TypeError(`defineFieldType(${plugin}): ${key} is a function.`)
|
|
120
|
+
}
|
|
121
|
+
return (given) => {
|
|
122
|
+
const result: unknown = Reflect.apply(value, undefined, [given, options])
|
|
123
|
+
return result
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** One field's codec, its functions given that field's options. */
|
|
128
|
+
function codecOf(plugin: string, definition: Options, options: Options): Codec {
|
|
129
|
+
const schemaOf = (key: string) => {
|
|
130
|
+
const given = definition[key]
|
|
131
|
+
const standard = standardOf(
|
|
132
|
+
typeof given === 'function'
|
|
133
|
+
? Reflect.apply(given, undefined, [options])
|
|
134
|
+
: given,
|
|
135
|
+
)
|
|
136
|
+
if (standard === undefined) {
|
|
137
|
+
throw new TypeError(
|
|
138
|
+
`defineFieldType(${plugin}): ${key} is a Standard Schema.`,
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
return standard
|
|
142
|
+
}
|
|
143
|
+
const shape =
|
|
144
|
+
definition['shape'] === undefined ? undefined : schemaOf('shape').schema
|
|
145
|
+
return Object.freeze({
|
|
146
|
+
plugin,
|
|
147
|
+
options,
|
|
148
|
+
decode: functionOf(plugin, definition, 'decode', options),
|
|
149
|
+
encode: functionOf(plugin, definition, 'encode', options),
|
|
150
|
+
schema: schemaOf('schema'),
|
|
151
|
+
toJSON: functionOf(plugin, definition, 'toJSON', options),
|
|
152
|
+
...(shape === undefined ? {} : { shape }),
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** The names a builder takes, `default`, `description` and the type's own. */
|
|
157
|
+
function namesOf(plugin: string, definition: Options): ReadonlySet<string> {
|
|
158
|
+
const names = definition['options'] ?? []
|
|
159
|
+
if (
|
|
160
|
+
!Array.isArray(names) ||
|
|
161
|
+
!names.every((name) => typeof name === 'string')
|
|
162
|
+
) {
|
|
163
|
+
throw new TypeError(
|
|
164
|
+
`defineFieldType(${plugin}): options is a list of option names.`,
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
return new Set([...kernelOptions, ...names])
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* A plugin's field type (D-122): its builder takes `default`, `description`
|
|
172
|
+
* (D-150) and the type's own options (D-152), and its value is stored through
|
|
173
|
+
* `stored`, encoded after the hooks and decoded on each read.
|
|
174
|
+
*/
|
|
175
|
+
export function defineFieldType<
|
|
176
|
+
const P extends string,
|
|
177
|
+
S extends Stored,
|
|
178
|
+
V,
|
|
179
|
+
X extends StandardSchema<unknown, V>,
|
|
180
|
+
O extends object = Described,
|
|
181
|
+
>(
|
|
182
|
+
definition: FieldTypeDefinition<P, S, V, X, O>,
|
|
183
|
+
): FieldType<P, S, V, SchemaTypes<X>['input'], O>
|
|
184
|
+
export function defineFieldType(
|
|
185
|
+
definition: Options,
|
|
186
|
+
): (options?: FieldOptions) => object {
|
|
187
|
+
const plugin = definition['plugin']
|
|
188
|
+
if (typeof plugin !== 'string' || plugin === '') {
|
|
189
|
+
throw new TypeError('defineFieldType takes the name of its plugin.')
|
|
190
|
+
}
|
|
191
|
+
const names = namesOf(plugin, definition)
|
|
192
|
+
// A definition fails at once, not at its first field.
|
|
193
|
+
codecOf(plugin, definition, {})
|
|
194
|
+
storedOf(plugin, definition['stored'], {})
|
|
195
|
+
return (given = {}) => {
|
|
196
|
+
const own: Record<string, unknown> = {}
|
|
197
|
+
const kernel: Record<string, unknown> = {}
|
|
198
|
+
for (const [option, value] of Object.entries(given)) {
|
|
199
|
+
if (!names.has(option)) {
|
|
200
|
+
throw new Error(
|
|
201
|
+
names.size === kernelOptions.size
|
|
202
|
+
? `A ${plugin} field takes default and description only, not ${option}: its stored field says the rest.`
|
|
203
|
+
: `A ${plugin} field takes ${[...names].join(', ')} only, not ${option}.`,
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
if (kernelOptions.has(option)) kernel[option] = value
|
|
207
|
+
else own[option] = value
|
|
208
|
+
}
|
|
209
|
+
const options = Object.freeze(own)
|
|
210
|
+
const stored = storedOf(plugin, definition['stored'], options)
|
|
211
|
+
const { default: filled, ...rest } = stored.options
|
|
212
|
+
const codec = codecOf(plugin, definition, options)
|
|
213
|
+
return build({
|
|
214
|
+
...stored,
|
|
215
|
+
options: { ...rest, ...kernel },
|
|
216
|
+
codec: filled === undefined ? codec : Object.freeze({ ...codec, filled }),
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
}
|