@afora/core 0.0.9 → 0.0.12
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 +62 -189
- package/dist/adapters.js +31 -55
- package/dist/core/application/application.d.ts +30 -0
- package/dist/core/application/application.js +1291 -0
- package/dist/core/application/exceptions.js +85 -0
- package/dist/core/application/migrate.js +67 -0
- package/dist/core/application/providers.js +108 -0
- package/dist/core/application/registry.js +23 -0
- package/dist/core/application/schema.js +398 -0
- package/dist/core/application/start.js +162 -0
- package/dist/core/application/types/application.interface.d.ts +23 -3
- package/dist/core/auth/jwt.js +200 -0
- package/dist/core/auth/types/jwt.interface.d.ts +10 -2
- package/dist/core/blueprint/blueprint-plugin.js +7 -0
- package/dist/core/blueprint/blueprint.js +146 -0
- package/dist/core/blueprint/callable.js +13 -0
- package/dist/core/blueprint/exceptions.js +20 -0
- package/dist/core/blueprint/is-blueprint.js +4 -0
- package/dist/core/blueprint/list.js +19 -0
- package/dist/core/blueprint/optional.js +69 -0
- package/dist/core/blueprint/record-field.js +14 -0
- package/dist/core/blueprint/slice.js +127 -0
- package/dist/core/blueprint/types/blueprint.interface.d.ts +16 -0
- package/dist/core/blueprint/variant.js +72 -0
- package/dist/core/command/command.js +428 -0
- package/dist/core/command/exceptions.js +30 -0
- package/dist/core/command/types/command.interface.d.ts +10 -1
- package/dist/core/entity/abstract-entity.d.ts +19 -0
- package/dist/core/entity/abstract-entity.js +181 -0
- package/dist/core/entity/entity.js +209 -0
- package/dist/core/entity/event.d.ts +39 -0
- package/dist/core/entity/event.js +80 -0
- package/dist/core/entity/exceptions.js +27 -0
- package/dist/core/entity/trust.js +7 -0
- package/dist/core/entity/version.js +13 -0
- package/dist/core/environment/environment.d.ts +26 -3
- package/dist/core/environment/environment.js +71 -0
- package/dist/core/event-policy/event-policy.js +76 -0
- package/dist/core/event-policy/exceptions.js +12 -0
- package/dist/core/event-policy/publish.js +98 -0
- package/dist/core/event-policy/publishers.js +18 -0
- package/dist/core/event-policy/types/event-policy.interface.d.ts +8 -2
- package/dist/core/exception/enums/exception-layers.js +15 -0
- package/dist/core/exception/exception.d.ts +15 -0
- package/dist/core/exception/exception.js +128 -0
- package/dist/core/exception/exported.js +49 -0
- package/dist/core/exception/guard.d.ts +20 -1
- package/dist/core/exception/guard.js +16 -0
- package/dist/core/exception/types/exception.interface.d.ts +13 -0
- package/dist/core/json.js +19 -0
- package/dist/core/logger/exceptions.js +7 -0
- package/dist/core/logger/logger.d.ts +14 -1
- package/dist/core/logger/logger.js +178 -0
- package/dist/core/openapi/exceptions.js +7 -0
- package/dist/core/openapi/openapi.js +132 -0
- package/dist/core/openapi/types/openapi.interface.d.ts +7 -1
- package/dist/core/output/access.js +66 -0
- package/dist/core/output/coerce.js +38 -0
- package/dist/core/output/exceptions.js +22 -0
- package/dist/{index-y280ew0k.js → core/output/http.js} +35 -80
- package/dist/core/output/openapi-sink.d.ts +10 -2
- package/dist/{index-hg1z2s2v.js → core/output/openapi-sink.js} +60 -544
- package/dist/core/output/output.js +192 -0
- package/dist/core/output/problem.js +30 -0
- package/dist/core/output/select.js +28 -0
- package/dist/core/output/stage.js +111 -0
- package/dist/core/output/status.js +52 -0
- package/dist/core/output/types/http.interface.d.ts +5 -1
- package/dist/core/output/types/output.interface.d.ts +24 -0
- package/dist/core/parse/issue.js +31 -0
- package/dist/core/parse/parse.d.ts +8 -1
- package/dist/core/parse/parse.js +323 -0
- package/dist/core/parse/strip.js +48 -0
- package/dist/core/property/abstract-property.js +37 -0
- package/dist/core/property/define-property.js +209 -0
- package/dist/core/property/enums/property-states.js +8 -0
- package/dist/core/property/exceptions.js +12 -0
- package/dist/core/property/input.js +10 -0
- package/dist/core/property/is-property.js +3 -0
- package/dist/core/property/lineage.js +8 -0
- package/dist/core/property/property.d.ts +27 -0
- package/dist/core/property/property.js +46 -0
- package/dist/core/property/refine.js +103 -0
- package/dist/core/record/abstract-record.d.ts +2 -1
- package/dist/core/record/abstract-record.js +307 -0
- package/dist/core/record/exceptions.js +49 -0
- package/dist/core/record/marks.js +7 -0
- package/dist/core/record/mask.js +60 -0
- package/dist/core/record/name.js +23 -0
- package/dist/core/record/plugin-catalog.js +115 -0
- package/dist/core/record/plugin.js +198 -0
- package/dist/core/record/record.js +117 -0
- package/dist/core/record/types/record.interface.d.ts +5 -0
- package/dist/core/repository/cursor.js +83 -0
- package/dist/core/repository/exceptions.js +72 -0
- package/dist/core/repository/in-memory.js +196 -0
- package/dist/core/repository/migrate.js +254 -0
- package/dist/core/repository/plan.js +27 -0
- package/dist/core/repository/provider.js +29 -0
- package/dist/core/repository/query.js +153 -0
- package/dist/core/repository/references.js +196 -0
- package/dist/core/repository/repository.d.ts +22 -2
- package/dist/core/repository/repository.js +720 -0
- package/dist/core/repository/state.js +138 -0
- package/dist/core/repository/types/query.interface.d.ts +13 -0
- package/dist/core/repository/types/repository.interface.d.ts +20 -8
- package/dist/core/repository/types/schema.interface.d.ts +8 -2
- package/dist/core/repository/upcast.js +179 -0
- package/dist/core/schema/schema.d.ts +9 -0
- package/dist/core/schema/schema.js +542 -0
- package/dist/core/standard/standard-schema.js +1 -0
- package/dist/core/standard/standard.js +23 -0
- package/dist/core/symbols/demo.d.ts +4 -0
- package/dist/core/symbols/demo.js +1 -0
- package/dist/core/symbols/kind.js +1 -0
- package/dist/core/symbols/meta.js +1 -0
- package/dist/core/symbols/state.d.ts +5 -0
- package/dist/core/symbols/state.js +1 -0
- package/dist/core/tracing/exceptions.d.ts +4 -0
- package/dist/core/tracing/exceptions.js +7 -0
- package/dist/core/tracing/tracing.d.ts +72 -0
- package/dist/core/tracing/tracing.js +101 -0
- package/dist/core/use-case/access.js +56 -0
- package/dist/core/use-case/decorators.js +65 -0
- package/dist/core/use-case/exceptions.d.ts +5 -1
- package/dist/core/use-case/exceptions.js +48 -0
- package/dist/core/use-case/plugin-catalog.js +68 -0
- package/dist/core/use-case/plugin.js +133 -0
- package/dist/core/use-case/route.js +200 -0
- package/dist/core/use-case/scope.d.ts +5 -0
- package/dist/core/use-case/scope.js +4 -0
- package/dist/core/use-case/steps/describe.d.ts +5 -1
- package/dist/core/use-case/steps/describe.js +24 -0
- package/dist/core/use-case/steps/references.js +105 -0
- package/dist/core/use-case/steps/run.js +139 -0
- package/dist/core/use-case/steps/types/check.interface.d.ts +27 -8
- package/dist/core/use-case/steps/types/steps.interface.d.ts +8 -1
- package/dist/core/use-case/steps/validate.js +368 -0
- package/dist/core/use-case/target.js +100 -0
- package/dist/core/use-case/types/route.interface.d.ts +25 -5
- package/dist/core/use-case/use-case.d.ts +77 -2
- package/dist/core/use-case/use-case.js +493 -0
- package/dist/experimental.d.ts +5 -0
- package/dist/experimental.js +18 -161
- package/dist/index.d.ts +7 -5
- package/dist/index.js +213 -367
- package/dist/std/blueprint-plugin.js +42 -0
- package/dist/std/blueprint.d.ts +21 -0
- package/dist/std/blueprint.js +3 -0
- package/dist/std/command.js +3 -0
- package/dist/std/entity.d.ts +20 -1
- package/dist/std/entity.js +30 -0
- package/dist/std/event-policies.js +3 -0
- package/dist/std/properties/contact.d.ts +3 -0
- package/dist/std/properties/contact.js +29 -0
- package/dist/std/properties/enum.js +26 -0
- package/dist/std/properties/exceptions.js +14 -0
- package/dist/std/properties/headless.js +45 -0
- package/dist/std/properties/identity.js +28 -0
- package/dist/std/properties/json.js +161 -0
- package/dist/std/properties/password.js +79 -0
- package/dist/std/properties/primitives.d.ts +4 -0
- package/dist/std/properties/primitives.js +28 -0
- package/dist/std/properties/time.js +55 -0
- package/dist/std/record-plugins.js +73 -0
- package/dist/std/record.d.ts +20 -1
- package/dist/std/record.js +3 -0
- package/dist/std/resource.js +39 -0
- package/dist/std/runtime.js +193 -0
- package/dist/std/stages.js +4 -0
- package/dist/std/use-cases/auth.js +193 -0
- package/dist/std/use-cases/crud.js +261 -0
- package/dist/std/use-cases/index.js +12 -0
- package/dist/std/use-cases/lifecycle.js +97 -0
- package/dist/std/use-cases/shared.js +232 -0
- package/dist/std/use-cases/types.d.ts +5 -1
- package/dist/std/use-cases/types.js +0 -0
- package/dist/testing/http-provider-contract.js +344 -0
- package/dist/testing/index.js +3 -1435
- package/dist/testing/memory-publisher.js +12 -0
- package/dist/testing/provider-contract.d.ts +12 -3
- package/dist/testing/provider-contract.js +1071 -0
- package/package.json +17 -5
- package/dist/index-3aae5jfq.js +0 -2997
- package/dist/index-ny3as79r.js +0 -4567
- package/dist/index-xegv6a1p.js +0 -4291
package/dist/index-xegv6a1p.js
DELETED
|
@@ -1,4291 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __returnValue = (v) => v;
|
|
3
|
-
function __exportSetter(name, newValue) {
|
|
4
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
-
}
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, {
|
|
9
|
-
get: all[name],
|
|
10
|
-
enumerable: true,
|
|
11
|
-
configurable: true,
|
|
12
|
-
set: __exportSetter.bind(all, name)
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// src/core/blueprint/exceptions.ts
|
|
17
|
-
var exports_exceptions3 = {};
|
|
18
|
-
__export(exports_exceptions3, {
|
|
19
|
-
InvalidBlueprintVariant: () => InvalidBlueprintVariant2,
|
|
20
|
-
ReservedBlueprintKey: () => ReservedBlueprintKey2,
|
|
21
|
-
UndeclaredBlueprintProperty: () => UndeclaredBlueprintProperty2
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
// src/core/property/exceptions.ts
|
|
25
|
-
var exports_exceptions4 = {};
|
|
26
|
-
__export(exports_exceptions4, {
|
|
27
|
-
InvalidPropertyValue: () => InvalidPropertyValue2,
|
|
28
|
-
PropertyRequired: () => PropertyRequired2
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// src/core/environment/environment.ts
|
|
32
|
-
var exports_environment = {};
|
|
33
|
-
__export(exports_environment, {
|
|
34
|
-
InvalidEnvironment: () => InvalidEnvironment2,
|
|
35
|
-
environmentOf: () => environmentOf2,
|
|
36
|
-
isEnvironment: () => isEnvironment,
|
|
37
|
-
loadEnvironments: () => loadEnvironments
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// src/core/application/exceptions.ts
|
|
41
|
-
var exports_exceptions5 = {};
|
|
42
|
-
__export(exports_exceptions5, {
|
|
43
|
-
ApplicationAlreadyStarted: () => ApplicationAlreadyStarted2,
|
|
44
|
-
ApplicationConflict: () => ApplicationConflict2,
|
|
45
|
-
ApplicationNotStarted: () => ApplicationNotStarted2,
|
|
46
|
-
DuplicateApplicationDeclaration: () => DuplicateApplicationDeclaration2,
|
|
47
|
-
InvalidApplicationDeclaration: () => InvalidApplicationDeclaration2,
|
|
48
|
-
InvalidApplicationEnvironment: () => InvalidApplicationEnvironment2,
|
|
49
|
-
InvalidSchemaMigration: () => InvalidSchemaMigration2,
|
|
50
|
-
ProviderNotBound: () => ProviderNotBound2,
|
|
51
|
-
SchemaLockMismatch: () => SchemaLockMismatch2,
|
|
52
|
-
UnregisteredApplicationReference: () => UnregisteredApplicationReference2,
|
|
53
|
-
UnregisteredRepositoryDependency: () => UnregisteredRepositoryDependency2,
|
|
54
|
-
UnregisteredUseCaseDependency: () => UnregisteredUseCaseDependency2
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// src/core/logger/exceptions.ts
|
|
58
|
-
var exports_exceptions6 = {};
|
|
59
|
-
__export(exports_exceptions6, {
|
|
60
|
-
InvalidLogDeclaration: () => InvalidLogDeclaration2
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// src/core/record/exceptions.ts
|
|
64
|
-
var exports_exceptions7 = {};
|
|
65
|
-
__export(exports_exceptions7, {
|
|
66
|
-
IncompatibleRecordPlugin: () => IncompatibleRecordPlugin2,
|
|
67
|
-
InvalidRecordDeclaration: () => InvalidRecordDeclaration2,
|
|
68
|
-
InvalidRecordPlugin: () => InvalidRecordPlugin2,
|
|
69
|
-
InvalidRecordValue: () => InvalidRecordValue2,
|
|
70
|
-
RecordPluginConflict: () => RecordPluginConflict2,
|
|
71
|
-
ReservedRecordKey: () => ReservedRecordKey2,
|
|
72
|
-
UndeclaredRecordProperty: () => UndeclaredRecordProperty2,
|
|
73
|
-
UnknownRecordPlugin: () => UnknownRecordPlugin2
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// src/core/entity/exceptions.ts
|
|
77
|
-
var exports_exceptions8 = {};
|
|
78
|
-
__export(exports_exceptions8, {
|
|
79
|
-
DeletedEntity: () => DeletedEntity2,
|
|
80
|
-
ImmutableEntityKey: () => ImmutableEntityKey2,
|
|
81
|
-
InvalidEntityExpiry: () => InvalidEntityExpiry2,
|
|
82
|
-
InvalidEntitySchemaVersion: () => InvalidEntitySchemaVersion2,
|
|
83
|
-
ReservedEntityKey: () => ReservedEntityKey2
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// src/core/repository/exceptions.ts
|
|
87
|
-
var exports_exceptions9 = {};
|
|
88
|
-
__export(exports_exceptions9, {
|
|
89
|
-
InvalidRepositoryCursor: () => InvalidRepositoryCursor2,
|
|
90
|
-
InvalidRepositoryData: () => InvalidRepositoryData2,
|
|
91
|
-
InvalidRepositoryDeclaration: () => InvalidRepositoryDeclaration2,
|
|
92
|
-
InvalidRepositoryEntity: () => InvalidRepositoryEntity2,
|
|
93
|
-
InvalidRepositoryIncrement: () => InvalidRepositoryIncrement2,
|
|
94
|
-
InvalidRepositoryQuery: () => InvalidRepositoryQuery2,
|
|
95
|
-
InvalidStoredSchemaVersion: () => InvalidStoredSchemaVersion2,
|
|
96
|
-
RepositoryConcurrencyConflict: () => RepositoryConcurrencyConflict2,
|
|
97
|
-
RepositoryEntityNotFound: () => RepositoryEntityNotFound2,
|
|
98
|
-
RepositoryUniqueViolation: () => RepositoryUniqueViolation2,
|
|
99
|
-
RepositoryUsedOutsideApplication: () => RepositoryUsedOutsideApplication2
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// src/core/openapi/exceptions.ts
|
|
103
|
-
var exports_exceptions10 = {};
|
|
104
|
-
__export(exports_exceptions10, {
|
|
105
|
-
InvalidOpenAPIModel: () => InvalidOpenAPIModel2
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// src/core/output/exceptions.ts
|
|
109
|
-
var exports_exceptions11 = {};
|
|
110
|
-
__export(exports_exceptions11, {
|
|
111
|
-
DuplicateOperation: () => DuplicateOperation2,
|
|
112
|
-
Forbidden: () => Forbidden2,
|
|
113
|
-
InvalidOutputStage: () => InvalidOutputStage2,
|
|
114
|
-
Unauthenticated: () => Unauthenticated2
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// src/core/property/is-property.ts
|
|
118
|
-
function isProperty(value) {
|
|
119
|
-
return typeof value === "function" && typeof value.type === "object";
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// src/core/schema/schema.ts
|
|
123
|
-
import Compile from "typebox/compile";
|
|
124
|
-
import * as System from "typebox/system";
|
|
125
|
-
var KEPT_KEYWORDS = new Set([
|
|
126
|
-
"type",
|
|
127
|
-
"required",
|
|
128
|
-
"$ref",
|
|
129
|
-
"$id",
|
|
130
|
-
"$anchor",
|
|
131
|
-
"$dynamicRef",
|
|
132
|
-
"$dynamicAnchor"
|
|
133
|
-
]);
|
|
134
|
-
var SCHEMA_KEYWORDS = new Set([
|
|
135
|
-
"additionalProperties",
|
|
136
|
-
"items",
|
|
137
|
-
"additionalItems",
|
|
138
|
-
"prefixItems",
|
|
139
|
-
"anyOf",
|
|
140
|
-
"oneOf",
|
|
141
|
-
"allOf",
|
|
142
|
-
"contains",
|
|
143
|
-
"propertyNames"
|
|
144
|
-
]);
|
|
145
|
-
var SCHEMA_MAP_KEYWORDS = new Set([
|
|
146
|
-
"properties",
|
|
147
|
-
"patternProperties",
|
|
148
|
-
"dependentSchemas",
|
|
149
|
-
"$defs",
|
|
150
|
-
"definitions"
|
|
151
|
-
]);
|
|
152
|
-
var JSON_TYPES = new Set([
|
|
153
|
-
"null",
|
|
154
|
-
"array",
|
|
155
|
-
"string",
|
|
156
|
-
"number",
|
|
157
|
-
"boolean",
|
|
158
|
-
"object"
|
|
159
|
-
]);
|
|
160
|
-
function typeOfValue(value) {
|
|
161
|
-
const type = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
162
|
-
return JSON_TYPES.has(type) ? type : undefined;
|
|
163
|
-
}
|
|
164
|
-
function shapeOf(schema) {
|
|
165
|
-
if (Array.isArray(schema))
|
|
166
|
-
return schema.map(shapeOf);
|
|
167
|
-
if (typeof schema !== "object" || schema === null)
|
|
168
|
-
return schema;
|
|
169
|
-
const shape = {};
|
|
170
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
171
|
-
if (KEPT_KEYWORDS.has(key))
|
|
172
|
-
shape[key] = value;
|
|
173
|
-
else if (SCHEMA_KEYWORDS.has(key))
|
|
174
|
-
shape[key] = shapeOf(value);
|
|
175
|
-
else if (SCHEMA_MAP_KEYWORDS.has(key)) {
|
|
176
|
-
shape[key] = Object.fromEntries(Object.entries(value).map(([name, item]) => [
|
|
177
|
-
name,
|
|
178
|
-
shapeOf(item)
|
|
179
|
-
]));
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
if (!("type" in shape)) {
|
|
183
|
-
const values = "const" in schema ? [schema.const] : schema.enum;
|
|
184
|
-
if (Array.isArray(values)) {
|
|
185
|
-
const types = values.map(typeOfValue);
|
|
186
|
-
if (types.every((type) => type !== undefined)) {
|
|
187
|
-
shape.type = [...new Set(types)];
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return shape;
|
|
192
|
-
}
|
|
193
|
-
function describeError(error) {
|
|
194
|
-
return `${error.instancePath || "/"}: ${error.message}`;
|
|
195
|
-
}
|
|
196
|
-
var INERT_KEYWORDS = new Set([
|
|
197
|
-
"~kind",
|
|
198
|
-
"~optional",
|
|
199
|
-
"~readonly",
|
|
200
|
-
"~unsafe",
|
|
201
|
-
"title",
|
|
202
|
-
"description",
|
|
203
|
-
"default",
|
|
204
|
-
"examples",
|
|
205
|
-
"deprecated",
|
|
206
|
-
"readOnly",
|
|
207
|
-
"writeOnly",
|
|
208
|
-
"$comment"
|
|
209
|
-
]);
|
|
210
|
-
var isNumeric = (value) => typeof value === "number" || typeof value === "bigint";
|
|
211
|
-
var LEAF_KEYWORDS = [
|
|
212
|
-
[
|
|
213
|
-
"type",
|
|
214
|
-
(value) => typeof value === "string" || Array.isArray(value) && value.every((item) => typeof item === "string"),
|
|
215
|
-
(type) => ({ type })
|
|
216
|
-
],
|
|
217
|
-
["minLength", (value) => typeof value === "number", (limit) => ({ limit })],
|
|
218
|
-
["maxLength", (value) => typeof value === "number", (limit) => ({ limit })],
|
|
219
|
-
["format", (value) => typeof value === "string", (format) => ({ format })],
|
|
220
|
-
["pattern", (value) => typeof value === "string", (pattern) => ({ pattern })],
|
|
221
|
-
["exclusiveMinimum", isNumeric, (limit) => ({ comparison: ">", limit })],
|
|
222
|
-
["exclusiveMaximum", isNumeric, (limit) => ({ comparison: "<", limit })],
|
|
223
|
-
["minimum", isNumeric, (limit) => ({ comparison: ">=", limit })],
|
|
224
|
-
["maximum", isNumeric, (limit) => ({ comparison: "<=", limit })],
|
|
225
|
-
["multipleOf", isNumeric, (multipleOf) => ({ multipleOf })],
|
|
226
|
-
["const", () => true, (allowedValue) => ({ allowedValue })],
|
|
227
|
-
["enum", Array.isArray, (allowedValues) => ({ allowedValues })]
|
|
228
|
-
];
|
|
229
|
-
var LEAF_KEYWORD_NAMES = new Set(LEAF_KEYWORDS.map(([keyword]) => keyword));
|
|
230
|
-
function leafChecksOf(schema) {
|
|
231
|
-
if (typeof schema !== "object" || schema === null)
|
|
232
|
-
return;
|
|
233
|
-
for (const key of Reflect.ownKeys(schema)) {
|
|
234
|
-
if (!LEAF_KEYWORD_NAMES.has(key) && !INERT_KEYWORDS.has(key)) {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
const checks = [];
|
|
239
|
-
for (const [keyword, reads, params] of LEAF_KEYWORDS) {
|
|
240
|
-
if (!Object.hasOwn(schema, keyword))
|
|
241
|
-
continue;
|
|
242
|
-
const value = schema[keyword];
|
|
243
|
-
if (!reads(value))
|
|
244
|
-
return;
|
|
245
|
-
const validator = Compile({ [keyword]: value });
|
|
246
|
-
checks.push({
|
|
247
|
-
keyword,
|
|
248
|
-
params: params(value),
|
|
249
|
-
check: (candidate) => validator.Check(candidate)
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
return checks;
|
|
253
|
-
}
|
|
254
|
-
var { Locale, Settings } = System;
|
|
255
|
-
var leafChecks = new WeakMap;
|
|
256
|
-
function addError(sink, keyword, schemaPath, instancePath, params) {
|
|
257
|
-
if (sink.errors.length < sink.max) {
|
|
258
|
-
const error = { keyword, schemaPath, instancePath, params };
|
|
259
|
-
sink.errors.push({ ...error, message: sink.locale(error) });
|
|
260
|
-
}
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
var segmentOf = (key) => key.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
264
|
-
var hasKey = (value, key) => key === "__proto__" || key === "constructor" || key === "prototype" ? Object.hasOwn(value, key) : (key in value);
|
|
265
|
-
var STRUCTURE_KEYWORDS = new Set([
|
|
266
|
-
"required",
|
|
267
|
-
"properties",
|
|
268
|
-
"additionalProperties",
|
|
269
|
-
"items",
|
|
270
|
-
"minItems",
|
|
271
|
-
"maxItems",
|
|
272
|
-
"anyOf"
|
|
273
|
-
]);
|
|
274
|
-
function explainerOf(schema) {
|
|
275
|
-
if (!isRecord(schema))
|
|
276
|
-
return;
|
|
277
|
-
for (const key of Reflect.ownKeys(schema)) {
|
|
278
|
-
if (!LEAF_KEYWORD_NAMES.has(key) && !INERT_KEYWORDS.has(key) && !STRUCTURE_KEYWORDS.has(key)) {
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
let type;
|
|
283
|
-
const leaves = [];
|
|
284
|
-
for (const [keyword, reads, params] of LEAF_KEYWORDS) {
|
|
285
|
-
if (!Object.hasOwn(schema, keyword))
|
|
286
|
-
continue;
|
|
287
|
-
const value = schema[keyword];
|
|
288
|
-
if (!reads(value))
|
|
289
|
-
return;
|
|
290
|
-
const validator = Compile({ [keyword]: value });
|
|
291
|
-
const leaf = {
|
|
292
|
-
keyword,
|
|
293
|
-
params: params(value),
|
|
294
|
-
check: (candidate) => validator.Check(candidate)
|
|
295
|
-
};
|
|
296
|
-
if (keyword === "type")
|
|
297
|
-
type = leaf;
|
|
298
|
-
else
|
|
299
|
-
leaves.push(leaf);
|
|
300
|
-
}
|
|
301
|
-
let required;
|
|
302
|
-
if (Object.hasOwn(schema, "required")) {
|
|
303
|
-
const value = schema.required;
|
|
304
|
-
if (!Array.isArray(value))
|
|
305
|
-
return;
|
|
306
|
-
if (!value.every((key) => typeof key === "string"))
|
|
307
|
-
return;
|
|
308
|
-
required = value;
|
|
309
|
-
}
|
|
310
|
-
let properties;
|
|
311
|
-
if (Object.hasOwn(schema, "properties")) {
|
|
312
|
-
if (!isRecord(schema.properties))
|
|
313
|
-
return;
|
|
314
|
-
const list = [];
|
|
315
|
-
for (const [key, property] of Object.entries(schema.properties)) {
|
|
316
|
-
const explain = explainerOf(property);
|
|
317
|
-
if (!explain)
|
|
318
|
-
return;
|
|
319
|
-
list.push({
|
|
320
|
-
key,
|
|
321
|
-
segment: segmentOf(key),
|
|
322
|
-
required: required?.includes(key) ?? false,
|
|
323
|
-
explain
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
properties = list;
|
|
327
|
-
}
|
|
328
|
-
let declared;
|
|
329
|
-
if (Object.hasOwn(schema, "additionalProperties")) {
|
|
330
|
-
if (schema.additionalProperties !== false)
|
|
331
|
-
return;
|
|
332
|
-
declared = new Set(properties?.map(({ key }) => key));
|
|
333
|
-
}
|
|
334
|
-
let items;
|
|
335
|
-
if (Object.hasOwn(schema, "items")) {
|
|
336
|
-
items = explainerOf(schema.items);
|
|
337
|
-
if (!items)
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
const limits = [];
|
|
341
|
-
for (const keyword of ["minItems", "maxItems"]) {
|
|
342
|
-
if (!Object.hasOwn(schema, keyword))
|
|
343
|
-
continue;
|
|
344
|
-
const limit = schema[keyword];
|
|
345
|
-
if (typeof limit !== "number")
|
|
346
|
-
return;
|
|
347
|
-
const validator = Compile({ [keyword]: limit });
|
|
348
|
-
limits.push({
|
|
349
|
-
keyword,
|
|
350
|
-
params: { limit },
|
|
351
|
-
check: (candidate) => validator.Check(candidate)
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
let anyOf;
|
|
355
|
-
if (Object.hasOwn(schema, "anyOf")) {
|
|
356
|
-
if (!Array.isArray(schema.anyOf))
|
|
357
|
-
return;
|
|
358
|
-
const list = [];
|
|
359
|
-
for (const option of schema.anyOf) {
|
|
360
|
-
const explain = explainerOf(option);
|
|
361
|
-
if (!explain)
|
|
362
|
-
return;
|
|
363
|
-
list.push(explain);
|
|
364
|
-
}
|
|
365
|
-
anyOf = list;
|
|
366
|
-
}
|
|
367
|
-
return (value, schemaPath, instancePath, sink) => {
|
|
368
|
-
if (sink.errors.length >= sink.max)
|
|
369
|
-
return false;
|
|
370
|
-
let accepted = true;
|
|
371
|
-
if (type && !type.check(value)) {
|
|
372
|
-
accepted = addError(sink, "type", schemaPath, instancePath, type.params);
|
|
373
|
-
}
|
|
374
|
-
if (isRecord(value)) {
|
|
375
|
-
if (required) {
|
|
376
|
-
const missing = required.filter((key) => !hasKey(value, key));
|
|
377
|
-
if (missing.length > 0) {
|
|
378
|
-
accepted = addError(sink, "required", schemaPath, instancePath, {
|
|
379
|
-
requiredProperties: missing
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
if (declared) {
|
|
384
|
-
const undeclared = [];
|
|
385
|
-
for (const key of Object.getOwnPropertyNames(value)) {
|
|
386
|
-
if (declared.has(key))
|
|
387
|
-
continue;
|
|
388
|
-
undeclared.push(key);
|
|
389
|
-
addError(sink, "boolean", `${schemaPath}/additionalProperties`, `${instancePath}/${segmentOf(key)}`, {});
|
|
390
|
-
}
|
|
391
|
-
if (undeclared.length > 0) {
|
|
392
|
-
accepted = addError(sink, "additionalProperties", schemaPath, instancePath, { additionalProperties: undeclared });
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
if (properties) {
|
|
396
|
-
for (const property of properties) {
|
|
397
|
-
const { key } = property;
|
|
398
|
-
if (!property.required && !sink.exact && value[key] === undefined) {
|
|
399
|
-
continue;
|
|
400
|
-
}
|
|
401
|
-
if (!hasKey(value, key))
|
|
402
|
-
continue;
|
|
403
|
-
const explained = property.explain(value[key], `${schemaPath}/properties/${property.segment}`, `${instancePath}/${property.segment}`, sink);
|
|
404
|
-
if (!explained)
|
|
405
|
-
accepted = false;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
if (Array.isArray(value)) {
|
|
410
|
-
if (items) {
|
|
411
|
-
const explain = items;
|
|
412
|
-
value.forEach((item, index) => {
|
|
413
|
-
const explained = explain(item, `${schemaPath}/items`, `${instancePath}/${index}`, sink);
|
|
414
|
-
if (!explained)
|
|
415
|
-
accepted = false;
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
for (const limit of limits) {
|
|
419
|
-
if (limit.check(value))
|
|
420
|
-
continue;
|
|
421
|
-
accepted = addError(sink, limit.keyword, schemaPath, instancePath, limit.params);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
for (const leaf of leaves) {
|
|
425
|
-
if (leaf.check(value))
|
|
426
|
-
continue;
|
|
427
|
-
accepted = addError(sink, leaf.keyword, schemaPath, instancePath, leaf.params);
|
|
428
|
-
}
|
|
429
|
-
if (anyOf) {
|
|
430
|
-
const failed = [];
|
|
431
|
-
let matched = false;
|
|
432
|
-
for (const [index, explain] of anyOf.entries()) {
|
|
433
|
-
const own = { ...sink, errors: [] };
|
|
434
|
-
const explained = explain(value, `${schemaPath}/anyOf/${index}`, instancePath, own);
|
|
435
|
-
if (explained)
|
|
436
|
-
matched = true;
|
|
437
|
-
else
|
|
438
|
-
failed.push(own.errors);
|
|
439
|
-
}
|
|
440
|
-
if (!matched) {
|
|
441
|
-
for (const errors of failed) {
|
|
442
|
-
for (const error of errors) {
|
|
443
|
-
if (sink.errors.length < sink.max)
|
|
444
|
-
sink.errors.push(error);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
accepted = addError(sink, "anyOf", schemaPath, instancePath, {});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return accepted;
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
var explainers = new WeakMap;
|
|
454
|
-
function sinkOf() {
|
|
455
|
-
const settings = Settings?.Get?.();
|
|
456
|
-
const locale = Locale?.Get?.();
|
|
457
|
-
if (typeof settings?.maxErrors !== "number" || typeof locale !== "function") {
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
return {
|
|
461
|
-
errors: [],
|
|
462
|
-
max: settings.maxErrors,
|
|
463
|
-
locale,
|
|
464
|
-
exact: settings.exactOptionalPropertyTypes === true
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
468
|
-
function literalOf(variant, key) {
|
|
469
|
-
if (!isRecord(variant) || variant.type !== "object")
|
|
470
|
-
return;
|
|
471
|
-
const { properties, required } = variant;
|
|
472
|
-
if (!isRecord(properties) || !Array.isArray(required))
|
|
473
|
-
return;
|
|
474
|
-
if (!required.includes(key) || !Object.hasOwn(properties, key)) {
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
const property = properties[key];
|
|
478
|
-
if (!isRecord(property) || !Object.hasOwn(property, "const"))
|
|
479
|
-
return;
|
|
480
|
-
const value = property.const;
|
|
481
|
-
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? { value } : undefined;
|
|
482
|
-
}
|
|
483
|
-
function discriminatedUnionOf(schema) {
|
|
484
|
-
if (!isRecord(schema) || !Array.isArray(schema.anyOf))
|
|
485
|
-
return;
|
|
486
|
-
for (const key of Reflect.ownKeys(schema)) {
|
|
487
|
-
if (key !== "anyOf" && !INERT_KEYWORDS.has(key))
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
const options = schema.anyOf;
|
|
491
|
-
const [first] = options;
|
|
492
|
-
if (options.length < 2 || !isRecord(first) || !isRecord(first.properties)) {
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
for (const key of Object.keys(first.properties)) {
|
|
496
|
-
const variants = new Map;
|
|
497
|
-
for (const [index, option] of options.entries()) {
|
|
498
|
-
const literal = literalOf(option, key);
|
|
499
|
-
if (!literal || variants.has(literal.value))
|
|
500
|
-
break;
|
|
501
|
-
let validator;
|
|
502
|
-
variants.set(literal.value, {
|
|
503
|
-
index,
|
|
504
|
-
explain: explainerOf(option),
|
|
505
|
-
Errors: (value) => {
|
|
506
|
-
validator ??= Compile(option);
|
|
507
|
-
return validator.Errors(value);
|
|
508
|
-
}
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
if (variants.size !== options.length)
|
|
512
|
-
continue;
|
|
513
|
-
return {
|
|
514
|
-
key,
|
|
515
|
-
segment: segmentOf(key),
|
|
516
|
-
allowedValues: [...variants.keys()],
|
|
517
|
-
variants
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
var discriminatedUnions = new WeakMap;
|
|
523
|
-
function errorsOfVariant(union, value) {
|
|
524
|
-
const variant = union.variants.get(value[union.key]);
|
|
525
|
-
if (variant) {
|
|
526
|
-
const at = `#/anyOf/${variant.index}`;
|
|
527
|
-
const sink = variant.explain && sinkOf();
|
|
528
|
-
if (variant.explain && sink) {
|
|
529
|
-
variant.explain(value, at, "", sink);
|
|
530
|
-
return sink.errors.length > 0 ? sink.errors : undefined;
|
|
531
|
-
}
|
|
532
|
-
const errors = variant.Errors(value);
|
|
533
|
-
if (errors.length === 0)
|
|
534
|
-
return;
|
|
535
|
-
return errors.map((error) => ({
|
|
536
|
-
...error,
|
|
537
|
-
schemaPath: at + error.schemaPath.slice(1)
|
|
538
|
-
}));
|
|
539
|
-
}
|
|
540
|
-
const maxErrors = Settings?.Get?.().maxErrors;
|
|
541
|
-
const locale = Locale?.Get?.();
|
|
542
|
-
if (typeof maxErrors !== "number" || typeof locale !== "function") {
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
if (maxErrors < 1)
|
|
546
|
-
return [];
|
|
547
|
-
const error = {
|
|
548
|
-
keyword: "enum",
|
|
549
|
-
schemaPath: "#/anyOf",
|
|
550
|
-
instancePath: `/${union.segment}`,
|
|
551
|
-
params: { allowedValues: union.allowedValues }
|
|
552
|
-
};
|
|
553
|
-
return [{ ...error, message: locale(error) }];
|
|
554
|
-
}
|
|
555
|
-
function errorsOfSchema(schema, value) {
|
|
556
|
-
let checks = leafChecks.get(schema);
|
|
557
|
-
if (checks === undefined) {
|
|
558
|
-
checks = leafChecksOf(schema.type.Type()) ?? null;
|
|
559
|
-
leafChecks.set(schema, checks);
|
|
560
|
-
}
|
|
561
|
-
const maxErrors = Settings?.Get?.().maxErrors;
|
|
562
|
-
const locale = Locale?.Get?.();
|
|
563
|
-
if (checks !== null && typeof maxErrors === "number" && typeof locale === "function") {
|
|
564
|
-
const errors = [];
|
|
565
|
-
for (const { keyword, params, check } of checks) {
|
|
566
|
-
if (errors.length >= maxErrors)
|
|
567
|
-
break;
|
|
568
|
-
if (check(value))
|
|
569
|
-
continue;
|
|
570
|
-
const error = { keyword, schemaPath: "#", instancePath: "", params };
|
|
571
|
-
errors.push({ ...error, message: locale(error) });
|
|
572
|
-
}
|
|
573
|
-
if (errors.length > 0)
|
|
574
|
-
return errors;
|
|
575
|
-
}
|
|
576
|
-
if (checks === null && isRecord(value)) {
|
|
577
|
-
let union = discriminatedUnions.get(schema);
|
|
578
|
-
if (union === undefined) {
|
|
579
|
-
union = discriminatedUnionOf(schema.type.Type()) ?? null;
|
|
580
|
-
discriminatedUnions.set(schema, union);
|
|
581
|
-
}
|
|
582
|
-
const errors = union && errorsOfVariant(union, value);
|
|
583
|
-
if (errors)
|
|
584
|
-
return errors;
|
|
585
|
-
}
|
|
586
|
-
if (checks === null) {
|
|
587
|
-
let explain = explainers.get(schema);
|
|
588
|
-
if (explain === undefined) {
|
|
589
|
-
explain = explainerOf(schema.type.Type()) ?? null;
|
|
590
|
-
explainers.set(schema, explain);
|
|
591
|
-
}
|
|
592
|
-
const sink = explain && sinkOf();
|
|
593
|
-
if (explain && sink) {
|
|
594
|
-
explain(value, "#", "", sink);
|
|
595
|
-
if (sink.errors.length > 0)
|
|
596
|
-
return sink.errors;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
return schema.type.Errors(value);
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
class AbstractSchema {
|
|
603
|
-
_type;
|
|
604
|
-
validator;
|
|
605
|
-
shapeValidator;
|
|
606
|
-
constructor(_type) {
|
|
607
|
-
this._type = _type;
|
|
608
|
-
}
|
|
609
|
-
match(value) {
|
|
610
|
-
return this.type.Check(value);
|
|
611
|
-
}
|
|
612
|
-
matchShape(value) {
|
|
613
|
-
this.shapeValidator ??= Compile(shapeOf(this._type));
|
|
614
|
-
return this.shapeValidator.Check(value);
|
|
615
|
-
}
|
|
616
|
-
checks() {
|
|
617
|
-
const validator = this.type;
|
|
618
|
-
const shape = shapeOf(this._type);
|
|
619
|
-
if (shape.type === "string" && Object.keys(shape).length === 1) {
|
|
620
|
-
return {
|
|
621
|
-
match: (value) => validator.Check(value),
|
|
622
|
-
matchShape: (value) => typeof value === "string"
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
return {
|
|
626
|
-
match: (value) => validator.Check(value),
|
|
627
|
-
matchShape: (value) => this.matchShape(value)
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
errors(value) {
|
|
631
|
-
return this.type.Errors(value).map(describeError);
|
|
632
|
-
}
|
|
633
|
-
toString() {
|
|
634
|
-
return JSON.stringify(this._type);
|
|
635
|
-
}
|
|
636
|
-
get type() {
|
|
637
|
-
this.validator ??= Compile(this._type);
|
|
638
|
-
return this.validator;
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
function checksOfSchema(schema) {
|
|
642
|
-
return schema instanceof AbstractSchema ? schema.checks() : {
|
|
643
|
-
match: (value) => schema.match(value),
|
|
644
|
-
matchShape: (value) => schema.matchShape(value)
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
function schemaOf(name, schema) {
|
|
648
|
-
|
|
649
|
-
class Schema extends AbstractSchema {
|
|
650
|
-
constructor(type = schema) {
|
|
651
|
-
super(type);
|
|
652
|
-
}
|
|
653
|
-
static fromString(value) {
|
|
654
|
-
return new Schema(JSON.parse(value));
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
Object.defineProperty(Schema, "name", { value: name });
|
|
658
|
-
Object.defineProperty(Schema, Symbol.for("nodejs.util.inspect.custom"), {
|
|
659
|
-
value: () => `@afora::schema:${name}`
|
|
660
|
-
});
|
|
661
|
-
return Schema;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
// src/core/symbols/demo.ts
|
|
665
|
-
var Demo2 = Symbol("demo");
|
|
666
|
-
|
|
667
|
-
// src/core/property/lineage.ts
|
|
668
|
-
var lineages = new WeakMap;
|
|
669
|
-
function recordPropertyLineage(Property, lineage) {
|
|
670
|
-
if (!lineages.has(Property))
|
|
671
|
-
lineages.set(Property, lineage);
|
|
672
|
-
}
|
|
673
|
-
function propertyLineageOf2(Property) {
|
|
674
|
-
return typeof Property === "function" ? lineages.get(Property) : undefined;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
// src/core/property/refine.ts
|
|
678
|
-
var METADATA_KEYS = [
|
|
679
|
-
"title",
|
|
680
|
-
"description",
|
|
681
|
-
"examples",
|
|
682
|
-
"deprecated",
|
|
683
|
-
"readOnly",
|
|
684
|
-
"writeOnly"
|
|
685
|
-
];
|
|
686
|
-
var LOWER_BOUNDS = {
|
|
687
|
-
min: ["minimum", "minLength"],
|
|
688
|
-
exclusiveMin: ["exclusiveMinimum"]
|
|
689
|
-
};
|
|
690
|
-
var UPPER_BOUNDS = {
|
|
691
|
-
max: ["maximum", "maxLength"],
|
|
692
|
-
exclusiveMax: ["exclusiveMaximum"]
|
|
693
|
-
};
|
|
694
|
-
function derivePropertyOf(Property, type) {
|
|
695
|
-
const Base = Property;
|
|
696
|
-
|
|
697
|
-
class Derived extends Base {
|
|
698
|
-
static type = type;
|
|
699
|
-
createDefinition() {
|
|
700
|
-
const definition = super.createDefinition();
|
|
701
|
-
Object.defineProperty(definition, "type", {
|
|
702
|
-
value: type,
|
|
703
|
-
configurable: true
|
|
704
|
-
});
|
|
705
|
-
return definition;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
Object.defineProperty(Derived, "name", { value: Property.name });
|
|
709
|
-
return Derived;
|
|
710
|
-
}
|
|
711
|
-
function copyOf(schema) {
|
|
712
|
-
return Object.defineProperties({}, Object.getOwnPropertyDescriptors(schema));
|
|
713
|
-
}
|
|
714
|
-
function addAllOf(schema, constraint) {
|
|
715
|
-
schema.allOf = [...schema.allOf ?? [], constraint];
|
|
716
|
-
}
|
|
717
|
-
function refinedSchemaOf(base, options) {
|
|
718
|
-
const schema = copyOf(base);
|
|
719
|
-
const keyword = (keys) => keys.length === 1 || schema.type !== "string" ? keys[0] : keys[1];
|
|
720
|
-
for (const key of METADATA_KEYS) {
|
|
721
|
-
if (options[key] !== undefined)
|
|
722
|
-
schema[key] = options[key];
|
|
723
|
-
}
|
|
724
|
-
for (const [option, keys] of Object.entries(LOWER_BOUNDS)) {
|
|
725
|
-
const value = options[option];
|
|
726
|
-
if (value === undefined)
|
|
727
|
-
continue;
|
|
728
|
-
const name = keyword(keys);
|
|
729
|
-
const current = schema[name];
|
|
730
|
-
schema[name] = current === undefined ? value : Math.max(current, value);
|
|
731
|
-
}
|
|
732
|
-
for (const [option, keys] of Object.entries(UPPER_BOUNDS)) {
|
|
733
|
-
const value = options[option];
|
|
734
|
-
if (value === undefined)
|
|
735
|
-
continue;
|
|
736
|
-
const name = keyword(keys);
|
|
737
|
-
const current = schema[name];
|
|
738
|
-
schema[name] = current === undefined ? value : Math.min(current, value);
|
|
739
|
-
}
|
|
740
|
-
if (options.multipleOf !== undefined) {
|
|
741
|
-
if (schema.multipleOf === undefined)
|
|
742
|
-
schema.multipleOf = options.multipleOf;
|
|
743
|
-
else
|
|
744
|
-
addAllOf(schema, { multipleOf: options.multipleOf });
|
|
745
|
-
}
|
|
746
|
-
if (options.pattern !== undefined) {
|
|
747
|
-
const pattern = options.pattern instanceof RegExp ? options.pattern.source : options.pattern;
|
|
748
|
-
if (schema.pattern === undefined)
|
|
749
|
-
schema.pattern = pattern;
|
|
750
|
-
else
|
|
751
|
-
addAllOf(schema, { pattern });
|
|
752
|
-
}
|
|
753
|
-
return schema;
|
|
754
|
-
}
|
|
755
|
-
function refinePropertyOf(Property, options) {
|
|
756
|
-
const base = Property.type;
|
|
757
|
-
const settings = options;
|
|
758
|
-
const schema = refinedSchemaOf(base.schema.type.Type(), settings);
|
|
759
|
-
const SchemaConstructor = schemaOf(base.name, schema);
|
|
760
|
-
const examples = settings.examples;
|
|
761
|
-
const type = {
|
|
762
|
-
...base,
|
|
763
|
-
[Demo2]: settings.default ?? examples?.[0] ?? base[Demo2],
|
|
764
|
-
schema: new SchemaConstructor,
|
|
765
|
-
...settings.fill !== undefined && { fill: settings.fill },
|
|
766
|
-
...typeof settings.renamedFrom === "string" && {
|
|
767
|
-
renamedFrom: settings.renamedFrom
|
|
768
|
-
}
|
|
769
|
-
};
|
|
770
|
-
const Refined = derivePropertyOf(Property, type);
|
|
771
|
-
recordPropertyLineage(Refined, {
|
|
772
|
-
kind: "refined",
|
|
773
|
-
base: Property,
|
|
774
|
-
options: Object.freeze({ ...settings })
|
|
775
|
-
});
|
|
776
|
-
return Refined;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
// src/core/blueprint/callable.ts
|
|
780
|
-
var targets = new WeakMap;
|
|
781
|
-
function callableOf(Property) {
|
|
782
|
-
const callable = new Proxy(Property, {
|
|
783
|
-
apply: (target, _this, [options]) => refinePropertyOf(target, options ?? {})
|
|
784
|
-
});
|
|
785
|
-
targets.set(callable, Property);
|
|
786
|
-
return callable;
|
|
787
|
-
}
|
|
788
|
-
function fieldOf(field) {
|
|
789
|
-
return (isProperty(field) ? targets.get(field) : undefined) ?? field;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
// src/core/symbols/kind.ts
|
|
793
|
-
var Kind2 = Symbol("kind");
|
|
794
|
-
|
|
795
|
-
// src/core/blueprint/is-blueprint.ts
|
|
796
|
-
function isBlueprint(value) {
|
|
797
|
-
return typeof value === "object" && value !== null && value[Kind2] === "blueprint";
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
// src/core/blueprint/record-field.ts
|
|
801
|
-
function isRecordClass(value) {
|
|
802
|
-
return typeof value === "function" && value[Kind2] === "record";
|
|
803
|
-
}
|
|
804
|
-
function isOptionalRecord(value) {
|
|
805
|
-
return typeof value === "object" && value !== null && value[Kind2] === "record";
|
|
806
|
-
}
|
|
807
|
-
function recordFieldOf(field) {
|
|
808
|
-
if (isRecordClass(field))
|
|
809
|
-
return { record: field, optional: false };
|
|
810
|
-
if (isOptionalRecord(field))
|
|
811
|
-
return field;
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// src/core/standard/standard-schema.ts
|
|
816
|
-
var STANDARD_VENDOR = "afora";
|
|
817
|
-
|
|
818
|
-
// src/core/standard/standard.ts
|
|
819
|
-
function standardOf(parse) {
|
|
820
|
-
return Object.freeze({
|
|
821
|
-
version: 1,
|
|
822
|
-
vendor: STANDARD_VENDOR,
|
|
823
|
-
validate: parse
|
|
824
|
-
});
|
|
825
|
-
}
|
|
826
|
-
function withStandard(target, parse) {
|
|
827
|
-
return Object.defineProperty(target, "~standard", {
|
|
828
|
-
value: standardOf(parse),
|
|
829
|
-
enumerable: false
|
|
830
|
-
});
|
|
831
|
-
}
|
|
832
|
-
var cache = new WeakMap;
|
|
833
|
-
function standardOfClass(Class) {
|
|
834
|
-
let standard = cache.get(Class);
|
|
835
|
-
if (!standard) {
|
|
836
|
-
standard = standardOf((value) => Class.safeParse(value));
|
|
837
|
-
cache.set(Class, standard);
|
|
838
|
-
}
|
|
839
|
-
return standard;
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
// src/core/exception/enums/exception-layers.ts
|
|
843
|
-
var ExceptionLayers2;
|
|
844
|
-
((ExceptionLayers) => {
|
|
845
|
-
ExceptionLayers["Schema"] = "schema";
|
|
846
|
-
ExceptionLayers["Property"] = "property";
|
|
847
|
-
ExceptionLayers["Blueprint"] = "blueprint";
|
|
848
|
-
ExceptionLayers["Record"] = "record";
|
|
849
|
-
ExceptionLayers["Entity"] = "entity";
|
|
850
|
-
ExceptionLayers["UseCase"] = "use-case";
|
|
851
|
-
ExceptionLayers["Repository"] = "repository";
|
|
852
|
-
ExceptionLayers["Environment"] = "environment";
|
|
853
|
-
ExceptionLayers["Event"] = "event";
|
|
854
|
-
ExceptionLayers["Command"] = "command";
|
|
855
|
-
ExceptionLayers["Application"] = "application";
|
|
856
|
-
ExceptionLayers["Output"] = "output";
|
|
857
|
-
})(ExceptionLayers2 ||= {});
|
|
858
|
-
|
|
859
|
-
// src/core/exception/exception.ts
|
|
860
|
-
var UNEXPECTED_ERROR = "UnexpectedError";
|
|
861
|
-
|
|
862
|
-
class Exception2 extends Error {
|
|
863
|
-
name;
|
|
864
|
-
layer;
|
|
865
|
-
source;
|
|
866
|
-
details;
|
|
867
|
-
cause;
|
|
868
|
-
constructor({
|
|
869
|
-
layer,
|
|
870
|
-
name,
|
|
871
|
-
source,
|
|
872
|
-
message,
|
|
873
|
-
details,
|
|
874
|
-
cause
|
|
875
|
-
}) {
|
|
876
|
-
super(message, cause === undefined ? undefined : { cause });
|
|
877
|
-
this.name = name;
|
|
878
|
-
this.layer = layer;
|
|
879
|
-
this.source = source;
|
|
880
|
-
this.details = details;
|
|
881
|
-
this.cause = cause;
|
|
882
|
-
}
|
|
883
|
-
static from(error, scope) {
|
|
884
|
-
if (error instanceof Exception2)
|
|
885
|
-
return error;
|
|
886
|
-
return new Exception2({
|
|
887
|
-
...scope,
|
|
888
|
-
name: UNEXPECTED_ERROR,
|
|
889
|
-
message: error instanceof Error ? error.message : String(error),
|
|
890
|
-
cause: error
|
|
891
|
-
});
|
|
892
|
-
}
|
|
893
|
-
get frame() {
|
|
894
|
-
const { layer, name, source, message, details } = this;
|
|
895
|
-
return { layer, name, source, message, details };
|
|
896
|
-
}
|
|
897
|
-
get trace() {
|
|
898
|
-
return this.chain().map((exception) => exception.frame).reverse();
|
|
899
|
-
}
|
|
900
|
-
get origin() {
|
|
901
|
-
return this.chain().at(-1);
|
|
902
|
-
}
|
|
903
|
-
find(target) {
|
|
904
|
-
return this.chain().find((exception) => typeof target === "string" ? exception.name === target : exception instanceof target);
|
|
905
|
-
}
|
|
906
|
-
is(target) {
|
|
907
|
-
return this.find(target) !== undefined;
|
|
908
|
-
}
|
|
909
|
-
passedThrough(layer) {
|
|
910
|
-
return this.chain().some((exception) => exception.layer === layer);
|
|
911
|
-
}
|
|
912
|
-
propagate({
|
|
913
|
-
layer,
|
|
914
|
-
source,
|
|
915
|
-
name = this.name,
|
|
916
|
-
message = this.message,
|
|
917
|
-
details
|
|
918
|
-
}) {
|
|
919
|
-
const keepsClass = name === this.name && details === undefined && isDeclaredInstance(this);
|
|
920
|
-
const init = {
|
|
921
|
-
layer,
|
|
922
|
-
source,
|
|
923
|
-
name,
|
|
924
|
-
message,
|
|
925
|
-
details: keepsClass ? this.details : details,
|
|
926
|
-
cause: this
|
|
927
|
-
};
|
|
928
|
-
return keepsClass ? Reflect.construct(Exception2, [init], this.constructor) : new Exception2(init);
|
|
929
|
-
}
|
|
930
|
-
toJSON() {
|
|
931
|
-
return { ...this.frame, trace: this.trace };
|
|
932
|
-
}
|
|
933
|
-
toString() {
|
|
934
|
-
return this.chain().map((exception, index) => `${index === 0 ? "" : " <- "}${exception.name} [${exception.layer} @ ${exception.source}]: ${exception.message}`).join(`
|
|
935
|
-
`);
|
|
936
|
-
}
|
|
937
|
-
chain() {
|
|
938
|
-
const chain = [];
|
|
939
|
-
for (let current = this;current instanceof Exception2; current = current.cause) {
|
|
940
|
-
chain.push(current);
|
|
941
|
-
}
|
|
942
|
-
return chain;
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
var declarations = new WeakMap;
|
|
946
|
-
function isDeclaredInstance(exception) {
|
|
947
|
-
for (let current = exception.constructor;typeof current === "function"; current = Object.getPrototypeOf(current)) {
|
|
948
|
-
if (declarations.has(current))
|
|
949
|
-
return true;
|
|
950
|
-
}
|
|
951
|
-
return false;
|
|
952
|
-
}
|
|
953
|
-
function isDeclaredException(value) {
|
|
954
|
-
return typeof value === "function" && declarations.has(value);
|
|
955
|
-
}
|
|
956
|
-
function declaredMessageOf(Declared) {
|
|
957
|
-
const { message } = declarations.get(Declared) ?? {};
|
|
958
|
-
return typeof message === "string" ? message : undefined;
|
|
959
|
-
}
|
|
960
|
-
function exceptionOf2({
|
|
961
|
-
layer,
|
|
962
|
-
name,
|
|
963
|
-
message
|
|
964
|
-
}) {
|
|
965
|
-
|
|
966
|
-
class DeclaredException extends Exception2 {
|
|
967
|
-
static layer = layer;
|
|
968
|
-
constructor({
|
|
969
|
-
source,
|
|
970
|
-
details,
|
|
971
|
-
cause,
|
|
972
|
-
message: custom
|
|
973
|
-
}) {
|
|
974
|
-
super({
|
|
975
|
-
layer,
|
|
976
|
-
name,
|
|
977
|
-
source,
|
|
978
|
-
details,
|
|
979
|
-
cause,
|
|
980
|
-
message: custom ?? (typeof message === "function" ? message(details, source) : message)
|
|
981
|
-
});
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
Object.defineProperty(DeclaredException, "name", { value: name });
|
|
985
|
-
declarations.set(DeclaredException, { message });
|
|
986
|
-
return DeclaredException;
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
// src/core/blueprint/exceptions.ts
|
|
990
|
-
var ReservedBlueprintKey2 = exceptionOf2({
|
|
991
|
-
layer: "blueprint" /* Blueprint */,
|
|
992
|
-
name: "ReservedBlueprintKey",
|
|
993
|
-
message: ({ key }) => `"${key}" is reserved and cannot be a plugin property.`
|
|
994
|
-
});
|
|
995
|
-
var InvalidBlueprintVariant2 = exceptionOf2({
|
|
996
|
-
layer: "blueprint" /* Blueprint */,
|
|
997
|
-
name: "InvalidBlueprintVariant",
|
|
998
|
-
message: ({
|
|
999
|
-
key,
|
|
1000
|
-
reason
|
|
1001
|
-
}) => `The variant field of key "${key}" cannot be declared: ${reason}.`
|
|
1002
|
-
});
|
|
1003
|
-
var UndeclaredBlueprintProperty2 = exceptionOf2({
|
|
1004
|
-
layer: "blueprint" /* Blueprint */,
|
|
1005
|
-
name: "UndeclaredBlueprintProperty",
|
|
1006
|
-
message: ({ key }) => `Property "${key}" of the blueprint is not declared.`
|
|
1007
|
-
});
|
|
1008
|
-
|
|
1009
|
-
// src/core/blueprint/variant.ts
|
|
1010
|
-
function variantOf2(key, variants) {
|
|
1011
|
-
const fail = (reason) => {
|
|
1012
|
-
throw new InvalidBlueprintVariant2({
|
|
1013
|
-
source: "blueprint",
|
|
1014
|
-
details: { key: String(key), reason }
|
|
1015
|
-
});
|
|
1016
|
-
};
|
|
1017
|
-
if (typeof key !== "string" || key === "") {
|
|
1018
|
-
fail("its key must be a string that is not empty");
|
|
1019
|
-
}
|
|
1020
|
-
const tags = Object.keys(variants);
|
|
1021
|
-
if (tags.length === 0)
|
|
1022
|
-
fail("it needs at least one variant");
|
|
1023
|
-
const classes = new Set;
|
|
1024
|
-
for (const tag of tags) {
|
|
1025
|
-
const variant = variants[tag];
|
|
1026
|
-
if (!isBlueprint(variant) && !isRecordClass(variant)) {
|
|
1027
|
-
fail(`the variant "${tag}" is not a blueprint nor a record class`);
|
|
1028
|
-
}
|
|
1029
|
-
if (classes.has(variant)) {
|
|
1030
|
-
fail(`the variant "${tag}" is a class another variant already is`);
|
|
1031
|
-
}
|
|
1032
|
-
if (isRecordClass(variant))
|
|
1033
|
-
classes.add(variant);
|
|
1034
|
-
if (Object.hasOwn(blueprintOfVariant(variant).properties, key)) {
|
|
1035
|
-
fail(`the variant "${tag}" declares "${key}", which the field adds`);
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
return standardVariantOf({
|
|
1039
|
-
[Kind2]: "variant",
|
|
1040
|
-
key,
|
|
1041
|
-
variants: Object.freeze({ ...variants }),
|
|
1042
|
-
optional: false
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
function standardVariantOf(variant) {
|
|
1046
|
-
return Object.freeze(withStandard(variant, (value) => parseField(variant, value, [], "variant")));
|
|
1047
|
-
}
|
|
1048
|
-
function blueprintOfVariant(variant) {
|
|
1049
|
-
return isRecordClass(variant) ? variant.blueprint : variant;
|
|
1050
|
-
}
|
|
1051
|
-
function namedVariantOf(field, value) {
|
|
1052
|
-
if (typeof value !== "object" || value === null)
|
|
1053
|
-
return;
|
|
1054
|
-
const tag = value[field.key];
|
|
1055
|
-
const variants = field.variants;
|
|
1056
|
-
return typeof tag === "string" && Object.hasOwn(variants, tag) ? variants[tag] : undefined;
|
|
1057
|
-
}
|
|
1058
|
-
function variantOfValue(field, value) {
|
|
1059
|
-
const variant = namedVariantOf(field, value);
|
|
1060
|
-
return variant && blueprintOfVariant(variant);
|
|
1061
|
-
}
|
|
1062
|
-
function variantNameOf(field, instance) {
|
|
1063
|
-
if (typeof instance !== "object" || instance === null)
|
|
1064
|
-
return;
|
|
1065
|
-
const variants = field.variants;
|
|
1066
|
-
for (const tag of Object.keys(variants)) {
|
|
1067
|
-
const variant = variants[tag];
|
|
1068
|
-
if (isRecordClass(variant) && instance instanceof variant)
|
|
1069
|
-
return tag;
|
|
1070
|
-
}
|
|
1071
|
-
return;
|
|
1072
|
-
}
|
|
1073
|
-
function isBlueprintVariant(value) {
|
|
1074
|
-
return typeof value === "object" && value !== null && value[Kind2] === "variant";
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
// src/core/symbols/state.ts
|
|
1078
|
-
var State2 = Symbol("state");
|
|
1079
|
-
|
|
1080
|
-
// src/core/property/abstract-property.ts
|
|
1081
|
-
var parsingDefinitions = new WeakMap;
|
|
1082
|
-
function parsingDefinitionOf(Class) {
|
|
1083
|
-
let definition = parsingDefinitions.get(Class);
|
|
1084
|
-
if (!definition) {
|
|
1085
|
-
definition = Object.create(Class.prototype).createDefinition();
|
|
1086
|
-
parsingDefinitions.set(Class, definition);
|
|
1087
|
-
}
|
|
1088
|
-
return definition;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
class AbstractProperty {
|
|
1092
|
-
get [State2]() {
|
|
1093
|
-
return this.definition[State2];
|
|
1094
|
-
}
|
|
1095
|
-
definition;
|
|
1096
|
-
value;
|
|
1097
|
-
constructor(value) {
|
|
1098
|
-
this.definition = this.createDefinition();
|
|
1099
|
-
this.value = this.definition.make(value === Demo2 ? this.definition.type[Demo2] : value);
|
|
1100
|
-
}
|
|
1101
|
-
static demo() {
|
|
1102
|
-
return new this(Demo2);
|
|
1103
|
-
}
|
|
1104
|
-
static safeParse(value) {
|
|
1105
|
-
return parsingDefinitionOf(this).parse(value);
|
|
1106
|
-
}
|
|
1107
|
-
static with(options) {
|
|
1108
|
-
return refinePropertyOf(this, options);
|
|
1109
|
-
}
|
|
1110
|
-
static get "~standard"() {
|
|
1111
|
-
return standardOfClass(this);
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
// src/core/parse/issue.ts
|
|
1116
|
-
var REJECTED = Symbol("rejected");
|
|
1117
|
-
|
|
1118
|
-
class LazyIssue {
|
|
1119
|
-
message;
|
|
1120
|
-
path;
|
|
1121
|
-
code;
|
|
1122
|
-
source;
|
|
1123
|
-
#origin;
|
|
1124
|
-
constructor(message, path, code, source, origin) {
|
|
1125
|
-
this.message = message;
|
|
1126
|
-
this.path = path;
|
|
1127
|
-
this.code = code;
|
|
1128
|
-
this.source = source;
|
|
1129
|
-
this.#origin = origin;
|
|
1130
|
-
}
|
|
1131
|
-
get cause() {
|
|
1132
|
-
return this.#origin.exception();
|
|
1133
|
-
}
|
|
1134
|
-
at(path) {
|
|
1135
|
-
return new LazyIssue(this.message, path, this.code, this.source, this.#origin);
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
function movedIssue(issue, path) {
|
|
1139
|
-
if (issue instanceof LazyIssue)
|
|
1140
|
-
return issue.at(path);
|
|
1141
|
-
const moved = { ...issue, path };
|
|
1142
|
-
const cause = Object.getOwnPropertyDescriptor(issue, "cause");
|
|
1143
|
-
if (cause && !cause.enumerable)
|
|
1144
|
-
Object.defineProperty(moved, "cause", cause);
|
|
1145
|
-
return moved;
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
// src/core/property/exceptions.ts
|
|
1149
|
-
var PropertyRequired2 = exceptionOf2({
|
|
1150
|
-
layer: "property" /* Property */,
|
|
1151
|
-
name: "PropertyRequired",
|
|
1152
|
-
message: (_, source) => `Property "${source}" is required.`
|
|
1153
|
-
});
|
|
1154
|
-
var InvalidPropertyValue2 = exceptionOf2({
|
|
1155
|
-
layer: "property" /* Property */,
|
|
1156
|
-
name: "InvalidPropertyValue",
|
|
1157
|
-
message: ({ errors }, source) => `Invalid value for property "${source}": ${errors.join("; ")}`
|
|
1158
|
-
});
|
|
1159
|
-
|
|
1160
|
-
// src/core/property/define-property.ts
|
|
1161
|
-
var MISMATCH = Symbol("mismatch");
|
|
1162
|
-
|
|
1163
|
-
class Failure {
|
|
1164
|
-
source;
|
|
1165
|
-
raised;
|
|
1166
|
-
errors;
|
|
1167
|
-
cause;
|
|
1168
|
-
constructor(source, raised, errors) {
|
|
1169
|
-
this.source = source;
|
|
1170
|
-
this.raised = raised;
|
|
1171
|
-
this.errors = errors;
|
|
1172
|
-
this.cause = raised;
|
|
1173
|
-
}
|
|
1174
|
-
exception() {
|
|
1175
|
-
if (this.cause === undefined) {
|
|
1176
|
-
const { source, errors } = this;
|
|
1177
|
-
this.cause = errors ? new InvalidPropertyValue2({
|
|
1178
|
-
source,
|
|
1179
|
-
details: { errors: errors.map(describeError) }
|
|
1180
|
-
}) : new PropertyRequired2({ source });
|
|
1181
|
-
}
|
|
1182
|
-
return this.cause;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
var rejection;
|
|
1186
|
-
function reject(failure) {
|
|
1187
|
-
rejection = failure;
|
|
1188
|
-
return REJECTED;
|
|
1189
|
-
}
|
|
1190
|
-
function segmentsOf(pointer) {
|
|
1191
|
-
return pointer.slice(1).split("/").map((segment) => {
|
|
1192
|
-
const key = segment.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
1193
|
-
return /^(0|[1-9]\d*)$/.test(key) ? Number(key) : key;
|
|
1194
|
-
});
|
|
1195
|
-
}
|
|
1196
|
-
function issueOf(failure, message, path, code) {
|
|
1197
|
-
return new LazyIssue(message, path, code, failure.source, failure);
|
|
1198
|
-
}
|
|
1199
|
-
function takeRejectionIssues(path, issues) {
|
|
1200
|
-
const failure = rejection;
|
|
1201
|
-
rejection = undefined;
|
|
1202
|
-
const { raised, errors, source } = failure;
|
|
1203
|
-
if (raised) {
|
|
1204
|
-
issues.push({
|
|
1205
|
-
message: raised.message,
|
|
1206
|
-
path,
|
|
1207
|
-
code: "invalid_value",
|
|
1208
|
-
source,
|
|
1209
|
-
cause: raised
|
|
1210
|
-
});
|
|
1211
|
-
} else if (!errors) {
|
|
1212
|
-
issues.push(issueOf(failure, "is required", path, "required"));
|
|
1213
|
-
} else if (errors.length === 0) {
|
|
1214
|
-
issues.push(issueOf(failure, "is invalid", path, "invalid_value"));
|
|
1215
|
-
} else {
|
|
1216
|
-
for (const { message, instancePath } of errors) {
|
|
1217
|
-
issues.push(issueOf(failure, message, instancePath === "" ? path : [...path, ...segmentsOf(instancePath)], "invalid_value"));
|
|
1218
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
class AbstractDefineProperty {
|
|
1223
|
-
[State2] = 0 /* Declared */;
|
|
1224
|
-
make(value) {
|
|
1225
|
-
const handled = this.attempt(value);
|
|
1226
|
-
if (handled !== REJECTED)
|
|
1227
|
-
return handled;
|
|
1228
|
-
const failure = rejection;
|
|
1229
|
-
rejection = undefined;
|
|
1230
|
-
throw failure.exception();
|
|
1231
|
-
}
|
|
1232
|
-
parse(value) {
|
|
1233
|
-
const handled = this.attemptWithoutThrowing(value);
|
|
1234
|
-
if (handled !== REJECTED)
|
|
1235
|
-
return { value: handled };
|
|
1236
|
-
const issues = [];
|
|
1237
|
-
takeRejectionIssues([], issues);
|
|
1238
|
-
return { issues };
|
|
1239
|
-
}
|
|
1240
|
-
preHandle(value) {
|
|
1241
|
-
return value;
|
|
1242
|
-
}
|
|
1243
|
-
afterHandle(value) {
|
|
1244
|
-
return value;
|
|
1245
|
-
}
|
|
1246
|
-
handle(value) {
|
|
1247
|
-
return this.type.schema.match(value) ? value : MISMATCH;
|
|
1248
|
-
}
|
|
1249
|
-
attemptWithoutThrowing(value) {
|
|
1250
|
-
try {
|
|
1251
|
-
return this.attempt(value);
|
|
1252
|
-
} catch (error) {
|
|
1253
|
-
return this.raise(error instanceof Exception2 ? error : this.invalidValue(error));
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
attempt(value) {
|
|
1257
|
-
const { name, optional, schema } = this.type;
|
|
1258
|
-
this[State2] = 0 /* Declared */;
|
|
1259
|
-
if (value === undefined) {
|
|
1260
|
-
if (!optional)
|
|
1261
|
-
return reject(new Failure(name, undefined, undefined));
|
|
1262
|
-
this[State2] = 4 /* Done */;
|
|
1263
|
-
return value;
|
|
1264
|
-
}
|
|
1265
|
-
const preHandles = this.preHandle !== PASS.preHandle;
|
|
1266
|
-
const handles = this.handle !== PASS.handle;
|
|
1267
|
-
if ((preHandles || handles) && !schema.matchShape(value)) {
|
|
1268
|
-
return this.mismatch(value);
|
|
1269
|
-
}
|
|
1270
|
-
try {
|
|
1271
|
-
if (preHandles) {
|
|
1272
|
-
this[State2] = 1 /* PreHandling */;
|
|
1273
|
-
value = this.runHandler(this.preHandle, value);
|
|
1274
|
-
}
|
|
1275
|
-
this[State2] = 2 /* Handling */;
|
|
1276
|
-
if (handles) {
|
|
1277
|
-
const handled = this.handle(value);
|
|
1278
|
-
if (handled === MISMATCH)
|
|
1279
|
-
return this.mismatch(value);
|
|
1280
|
-
value = handled;
|
|
1281
|
-
} else if (!schema.match(value)) {
|
|
1282
|
-
if (!preHandles && !schema.matchShape(value)) {
|
|
1283
|
-
this[State2] = 0 /* Declared */;
|
|
1284
|
-
}
|
|
1285
|
-
return this.mismatch(value);
|
|
1286
|
-
}
|
|
1287
|
-
if (this.afterHandle !== PASS.afterHandle) {
|
|
1288
|
-
this[State2] = 3 /* AfterHandling */;
|
|
1289
|
-
value = this.runHandler(this.afterHandle, value);
|
|
1290
|
-
}
|
|
1291
|
-
} catch (error) {
|
|
1292
|
-
if (error instanceof Exception2)
|
|
1293
|
-
return this.raise(error);
|
|
1294
|
-
throw error;
|
|
1295
|
-
}
|
|
1296
|
-
this[State2] = 4 /* Done */;
|
|
1297
|
-
return value;
|
|
1298
|
-
}
|
|
1299
|
-
runHandler(handler, value) {
|
|
1300
|
-
try {
|
|
1301
|
-
return handler.call(this, value);
|
|
1302
|
-
} catch (error) {
|
|
1303
|
-
if (error instanceof Exception2)
|
|
1304
|
-
throw error;
|
|
1305
|
-
throw this.invalidValue(error);
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
invalidValue(error) {
|
|
1309
|
-
return new InvalidPropertyValue2({
|
|
1310
|
-
source: this.type.name,
|
|
1311
|
-
details: {
|
|
1312
|
-
errors: [error instanceof Error ? error.message : String(error)]
|
|
1313
|
-
},
|
|
1314
|
-
cause: error
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
raise(exception) {
|
|
1318
|
-
return reject(new Failure(this.type.name, exception, undefined));
|
|
1319
|
-
}
|
|
1320
|
-
mismatch(value) {
|
|
1321
|
-
const { name, schema } = this.type;
|
|
1322
|
-
return reject(new Failure(name, undefined, errorsOfSchema(schema, value)));
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
var PASS = AbstractDefineProperty.prototype;
|
|
1326
|
-
var declared = new WeakSet;
|
|
1327
|
-
function declarePipeline(prototype) {
|
|
1328
|
-
declared.add(prototype);
|
|
1329
|
-
}
|
|
1330
|
-
function parserOf(definition) {
|
|
1331
|
-
const pipeline = definition;
|
|
1332
|
-
if (pipeline.parse !== AbstractDefineProperty.prototype.parse) {
|
|
1333
|
-
return;
|
|
1334
|
-
}
|
|
1335
|
-
if (!declared.has(Object.getPrototypeOf(definition)) || pipeline.handle !== PASS.handle || Object.hasOwn(definition, "preHandle") || Object.hasOwn(definition, "afterHandle")) {
|
|
1336
|
-
return (value) => pipeline.attemptWithoutThrowing(value);
|
|
1337
|
-
}
|
|
1338
|
-
const { name, optional, schema } = pipeline.type;
|
|
1339
|
-
const { match, matchShape } = checksOfSchema(schema);
|
|
1340
|
-
const preHandle = pipeline.preHandle === PASS.preHandle ? undefined : pipeline.preHandle;
|
|
1341
|
-
const afterHandle = pipeline.afterHandle === PASS.afterHandle ? undefined : pipeline.afterHandle;
|
|
1342
|
-
return (value) => {
|
|
1343
|
-
if (value === undefined) {
|
|
1344
|
-
return optional ? value : reject(new Failure(name, undefined, undefined));
|
|
1345
|
-
}
|
|
1346
|
-
try {
|
|
1347
|
-
if (preHandle !== undefined) {
|
|
1348
|
-
if (!matchShape(value))
|
|
1349
|
-
return pipeline.mismatch(value);
|
|
1350
|
-
value = preHandle.call(pipeline, value);
|
|
1351
|
-
}
|
|
1352
|
-
if (!match(value))
|
|
1353
|
-
return pipeline.mismatch(value);
|
|
1354
|
-
return afterHandle === undefined ? value : afterHandle.call(pipeline, value);
|
|
1355
|
-
} catch (error) {
|
|
1356
|
-
return pipeline.raise(error instanceof Exception2 ? error : pipeline.invalidValue(error));
|
|
1357
|
-
}
|
|
1358
|
-
};
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
// src/core/record/name.ts
|
|
1362
|
-
var RECORD_NAME = /^[A-Za-z_$][\w$]*$/;
|
|
1363
|
-
function isRecordName(name) {
|
|
1364
|
-
return typeof name === "string" && RECORD_NAME.test(name);
|
|
1365
|
-
}
|
|
1366
|
-
function recordNameOf2(Class) {
|
|
1367
|
-
const { recordName, name } = Class;
|
|
1368
|
-
return typeof recordName === "string" ? recordName : String(name);
|
|
1369
|
-
}
|
|
1370
|
-
var declaredNames = new WeakMap;
|
|
1371
|
-
function declareRecordName(Class, name) {
|
|
1372
|
-
declaredNames.set(Class, name);
|
|
1373
|
-
}
|
|
1374
|
-
function declaredRecordNameOf(Class) {
|
|
1375
|
-
for (let current = Class;typeof current === "function"; current = Object.getPrototypeOf(current)) {
|
|
1376
|
-
const own = Object.getOwnPropertyDescriptor(current, "recordName")?.value;
|
|
1377
|
-
if (typeof own === "string")
|
|
1378
|
-
return own;
|
|
1379
|
-
const declared = declaredNames.get(current);
|
|
1380
|
-
if (declared !== undefined)
|
|
1381
|
-
return declared;
|
|
1382
|
-
}
|
|
1383
|
-
return;
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
// src/core/parse/parse.ts
|
|
1387
|
-
var entriesOf = new WeakMap;
|
|
1388
|
-
function fieldsOf(properties) {
|
|
1389
|
-
let entries = entriesOf.get(properties);
|
|
1390
|
-
if (!entries) {
|
|
1391
|
-
entries = Object.entries(properties);
|
|
1392
|
-
entriesOf.set(properties, entries);
|
|
1393
|
-
}
|
|
1394
|
-
return entries;
|
|
1395
|
-
}
|
|
1396
|
-
function isPlainObject(value) {
|
|
1397
|
-
if (typeof value !== "object" || value === null)
|
|
1398
|
-
return false;
|
|
1399
|
-
const prototype = Object.getPrototypeOf(value);
|
|
1400
|
-
return prototype === Object.prototype || prototype === null;
|
|
1401
|
-
}
|
|
1402
|
-
var PROPERTY = 0;
|
|
1403
|
-
var LIST = 1;
|
|
1404
|
-
var BLUEPRINT = 2;
|
|
1405
|
-
var RECORD = 3;
|
|
1406
|
-
var UNDECLARED_FIELD = 4;
|
|
1407
|
-
var VARIANT = 5;
|
|
1408
|
-
function stepOf(field) {
|
|
1409
|
-
const record = recordFieldOf(field);
|
|
1410
|
-
const kind = isBlueprintList(field) ? LIST : isBlueprint(field) ? BLUEPRINT : isBlueprintVariant(field) ? VARIANT : record ? RECORD : isProperty(field) ? PROPERTY : UNDECLARED_FIELD;
|
|
1411
|
-
return {
|
|
1412
|
-
kind,
|
|
1413
|
-
property: kind === PROPERTY ? field : undefined,
|
|
1414
|
-
parser: undefined,
|
|
1415
|
-
list: kind === LIST ? field : undefined,
|
|
1416
|
-
item: undefined,
|
|
1417
|
-
blueprint: kind === BLUEPRINT ? field : undefined,
|
|
1418
|
-
collection: undefined,
|
|
1419
|
-
record: kind === RECORD ? record?.record : undefined,
|
|
1420
|
-
optionalRecord: kind === RECORD && record?.optional === true,
|
|
1421
|
-
variant: kind === VARIANT ? field : undefined,
|
|
1422
|
-
variants: undefined
|
|
1423
|
-
};
|
|
1424
|
-
}
|
|
1425
|
-
var UNDECLARED = {
|
|
1426
|
-
kind: UNDECLARED_FIELD,
|
|
1427
|
-
property: undefined,
|
|
1428
|
-
parser: undefined,
|
|
1429
|
-
list: undefined,
|
|
1430
|
-
item: undefined,
|
|
1431
|
-
blueprint: undefined,
|
|
1432
|
-
collection: undefined,
|
|
1433
|
-
record: undefined,
|
|
1434
|
-
optionalRecord: false,
|
|
1435
|
-
variant: undefined,
|
|
1436
|
-
variants: undefined
|
|
1437
|
-
};
|
|
1438
|
-
var steps = new WeakMap;
|
|
1439
|
-
function keptStepOf(field) {
|
|
1440
|
-
if (typeof field !== "object" && typeof field !== "function" || field === null) {
|
|
1441
|
-
return UNDECLARED;
|
|
1442
|
-
}
|
|
1443
|
-
let step = steps.get(field);
|
|
1444
|
-
if (!step) {
|
|
1445
|
-
step = stepOf(field);
|
|
1446
|
-
steps.set(field, step);
|
|
1447
|
-
}
|
|
1448
|
-
return step;
|
|
1449
|
-
}
|
|
1450
|
-
var collections = new WeakMap;
|
|
1451
|
-
function collectionOf(properties) {
|
|
1452
|
-
let collection = collections.get(properties);
|
|
1453
|
-
if (!collection) {
|
|
1454
|
-
const fields = fieldsOf(properties);
|
|
1455
|
-
collection = {
|
|
1456
|
-
properties,
|
|
1457
|
-
names: fields.map(([name]) => name),
|
|
1458
|
-
steps: fields.map(([, field]) => keptStepOf(field))
|
|
1459
|
-
};
|
|
1460
|
-
collections.set(properties, collection);
|
|
1461
|
-
}
|
|
1462
|
-
return collection;
|
|
1463
|
-
}
|
|
1464
|
-
function runOf(base, source) {
|
|
1465
|
-
return { source, base, keys: [], issues: undefined };
|
|
1466
|
-
}
|
|
1467
|
-
function pathOf(run, depth) {
|
|
1468
|
-
const { base, keys } = run;
|
|
1469
|
-
const path = base.length === 0 ? [] : [...base];
|
|
1470
|
-
for (let index = 0;index < depth; index++) {
|
|
1471
|
-
path.push(keys[index]);
|
|
1472
|
-
}
|
|
1473
|
-
return path;
|
|
1474
|
-
}
|
|
1475
|
-
function reject2(run, code, message, path) {
|
|
1476
|
-
run.issues ??= [];
|
|
1477
|
-
run.issues.push({ code, message, path, source: run.source });
|
|
1478
|
-
return REJECTED;
|
|
1479
|
-
}
|
|
1480
|
-
function resultOf(run, handled) {
|
|
1481
|
-
return handled === REJECTED ? { issues: run.issues ?? [] } : { value: handled };
|
|
1482
|
-
}
|
|
1483
|
-
var ROOT = Object.freeze([]);
|
|
1484
|
-
function collectionParserOf(properties, source) {
|
|
1485
|
-
let collection;
|
|
1486
|
-
return (value, vouched) => {
|
|
1487
|
-
collection ??= collectionOf(properties);
|
|
1488
|
-
const run = runOf(ROOT, source);
|
|
1489
|
-
return resultOf(run, collectionAt(collection, value, run, 0, vouched));
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
|
-
function collectionAt(collection, value, run, depth, vouched, tag) {
|
|
1493
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1494
|
-
return reject2(run, "invalid_type", "must be an object", pathOf(run, depth));
|
|
1495
|
-
}
|
|
1496
|
-
const { properties, names, steps } = collection;
|
|
1497
|
-
let rejected = false;
|
|
1498
|
-
const keys = Object.keys(value);
|
|
1499
|
-
for (let index = 0;index < keys.length; index++) {
|
|
1500
|
-
const name = keys[index];
|
|
1501
|
-
if (name === names[index] || name === tag || Object.hasOwn(properties, name)) {
|
|
1502
|
-
continue;
|
|
1503
|
-
}
|
|
1504
|
-
rejected = true;
|
|
1505
|
-
reject2(run, "undeclared_key", "is not declared", [
|
|
1506
|
-
...pathOf(run, depth),
|
|
1507
|
-
name
|
|
1508
|
-
]);
|
|
1509
|
-
}
|
|
1510
|
-
const handled = tag === undefined ? {} : { [tag]: value[tag] };
|
|
1511
|
-
for (let index = 0;index < names.length; index++) {
|
|
1512
|
-
const name = names[index];
|
|
1513
|
-
if (vouched?.includes(name)) {
|
|
1514
|
-
handled[name] = value[name];
|
|
1515
|
-
continue;
|
|
1516
|
-
}
|
|
1517
|
-
run.keys[depth] = name;
|
|
1518
|
-
const item = fieldAt(steps[index], value[name], run, depth + 1);
|
|
1519
|
-
if (item === REJECTED)
|
|
1520
|
-
rejected = true;
|
|
1521
|
-
else if (item !== undefined)
|
|
1522
|
-
handled[name] = item;
|
|
1523
|
-
}
|
|
1524
|
-
return rejected ? REJECTED : Object.freeze(handled);
|
|
1525
|
-
}
|
|
1526
|
-
function parseField(field, value, path, source) {
|
|
1527
|
-
const run = runOf(path, source);
|
|
1528
|
-
return resultOf(run, fieldAt(keptStepOf(field), value, run, 0));
|
|
1529
|
-
}
|
|
1530
|
-
var DECLARED_SAFE_PARSE = AbstractProperty.safeParse;
|
|
1531
|
-
function fieldAt(step, value, run, depth) {
|
|
1532
|
-
switch (step.kind) {
|
|
1533
|
-
case PROPERTY:
|
|
1534
|
-
return propertyAt(step, value, run, depth);
|
|
1535
|
-
case LIST: {
|
|
1536
|
-
const list = step.list;
|
|
1537
|
-
if (value === undefined) {
|
|
1538
|
-
return list.optional ? value : required(run, depth);
|
|
1539
|
-
}
|
|
1540
|
-
if (!Array.isArray(value)) {
|
|
1541
|
-
return reject2(run, "invalid_type", "must be an array", pathOf(run, depth));
|
|
1542
|
-
}
|
|
1543
|
-
const { minItems, maxItems } = list;
|
|
1544
|
-
let rejected = false;
|
|
1545
|
-
if (minItems !== undefined && value.length < minItems || maxItems !== undefined && value.length > maxItems) {
|
|
1546
|
-
rejected = true;
|
|
1547
|
-
const path = pathOf(run, depth);
|
|
1548
|
-
if (minItems !== undefined && value.length < minItems) {
|
|
1549
|
-
reject2(run, "too_few_items", `must have at least ${minItems} items`, path);
|
|
1550
|
-
}
|
|
1551
|
-
if (maxItems !== undefined && value.length > maxItems) {
|
|
1552
|
-
reject2(run, "too_many_items", `must have at most ${maxItems} items`, path);
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
step.item ??= keptStepOf(list.item);
|
|
1556
|
-
const { item } = step;
|
|
1557
|
-
const items = [];
|
|
1558
|
-
for (let index = 0;index < value.length; index++) {
|
|
1559
|
-
run.keys[depth] = index;
|
|
1560
|
-
const handled = fieldAt(item, value[index], run, depth + 1);
|
|
1561
|
-
if (handled === REJECTED)
|
|
1562
|
-
rejected = true;
|
|
1563
|
-
else
|
|
1564
|
-
items.push(handled);
|
|
1565
|
-
}
|
|
1566
|
-
return rejected ? REJECTED : Object.freeze(items);
|
|
1567
|
-
}
|
|
1568
|
-
case BLUEPRINT: {
|
|
1569
|
-
const blueprint = step.blueprint;
|
|
1570
|
-
if (value === undefined) {
|
|
1571
|
-
return blueprint.optional ? value : required(run, depth);
|
|
1572
|
-
}
|
|
1573
|
-
step.collection ??= collectionOf(blueprint.properties);
|
|
1574
|
-
return collectionAt(step.collection, value, run, depth);
|
|
1575
|
-
}
|
|
1576
|
-
case VARIANT: {
|
|
1577
|
-
const variant = step.variant;
|
|
1578
|
-
if (value === undefined) {
|
|
1579
|
-
return variant.optional ? value : required(run, depth);
|
|
1580
|
-
}
|
|
1581
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1582
|
-
return reject2(run, "invalid_type", "must be an object", pathOf(run, depth));
|
|
1583
|
-
}
|
|
1584
|
-
let { variants } = step;
|
|
1585
|
-
if (variants === undefined) {
|
|
1586
|
-
variants = new Map;
|
|
1587
|
-
const declared = variant.variants;
|
|
1588
|
-
for (const tag of Object.keys(declared)) {
|
|
1589
|
-
const one = declared[tag];
|
|
1590
|
-
variants.set(tag, isBlueprint(one) ? collectionOf(one.properties) : one);
|
|
1591
|
-
}
|
|
1592
|
-
step.variants = variants;
|
|
1593
|
-
}
|
|
1594
|
-
if (!isPlainObject(value)) {
|
|
1595
|
-
for (const one of variants.values()) {
|
|
1596
|
-
if (typeof one === "function" && value instanceof one)
|
|
1597
|
-
return value;
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
const { key } = variant;
|
|
1601
|
-
const tag = value[key];
|
|
1602
|
-
const named = typeof tag === "string" ? variants.get(tag) : undefined;
|
|
1603
|
-
if (named === undefined) {
|
|
1604
|
-
return reject2(run, "invalid_value", "must be equal to one of the allowed values", [...pathOf(run, depth), key]);
|
|
1605
|
-
}
|
|
1606
|
-
if (typeof named !== "function") {
|
|
1607
|
-
return collectionAt(named, value, run, depth, undefined, key);
|
|
1608
|
-
}
|
|
1609
|
-
const { [key]: _name, ...input } = value;
|
|
1610
|
-
const result = named.safeParse(input);
|
|
1611
|
-
if (!result.issues)
|
|
1612
|
-
return result.value;
|
|
1613
|
-
const path = pathOf(run, depth);
|
|
1614
|
-
run.issues ??= [];
|
|
1615
|
-
for (const issue of result.issues) {
|
|
1616
|
-
run.issues.push(movedIssue(issue, [...path, ...issue.path]));
|
|
1617
|
-
}
|
|
1618
|
-
return REJECTED;
|
|
1619
|
-
}
|
|
1620
|
-
case RECORD: {
|
|
1621
|
-
const Record = step.record;
|
|
1622
|
-
if (value === undefined) {
|
|
1623
|
-
return step.optionalRecord ? value : required(run, depth);
|
|
1624
|
-
}
|
|
1625
|
-
if (value instanceof Record)
|
|
1626
|
-
return value;
|
|
1627
|
-
if (!isPlainObject(value)) {
|
|
1628
|
-
return reject2(run, "not_record", `must be an instance of record "${recordNameOf2(Record)}"`, pathOf(run, depth));
|
|
1629
|
-
}
|
|
1630
|
-
const result = Record.safeParse(value);
|
|
1631
|
-
if (!result.issues)
|
|
1632
|
-
return result.value;
|
|
1633
|
-
const path = pathOf(run, depth);
|
|
1634
|
-
run.issues ??= [];
|
|
1635
|
-
for (const issue of result.issues) {
|
|
1636
|
-
run.issues.push(movedIssue(issue, [...path, ...issue.path]));
|
|
1637
|
-
}
|
|
1638
|
-
return REJECTED;
|
|
1639
|
-
}
|
|
1640
|
-
default:
|
|
1641
|
-
return reject2(run, "undeclared_key", "is not declared", pathOf(run, depth));
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
function required(run, depth) {
|
|
1645
|
-
return reject2(run, "required", "is required", pathOf(run, depth));
|
|
1646
|
-
}
|
|
1647
|
-
function propertyAt(step, value, run, depth) {
|
|
1648
|
-
const property = step.property;
|
|
1649
|
-
if (property.safeParse === DECLARED_SAFE_PARSE) {
|
|
1650
|
-
let { parser } = step;
|
|
1651
|
-
if (parser === undefined) {
|
|
1652
|
-
parser = parserOf(parsingDefinitionOf(property)) ?? null;
|
|
1653
|
-
step.parser = parser;
|
|
1654
|
-
}
|
|
1655
|
-
if (parser !== null) {
|
|
1656
|
-
const handled = parser(value);
|
|
1657
|
-
if (handled !== REJECTED)
|
|
1658
|
-
return handled;
|
|
1659
|
-
run.issues ??= [];
|
|
1660
|
-
takeRejectionIssues(pathOf(run, depth), run.issues);
|
|
1661
|
-
return REJECTED;
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
const result = property.safeParse(value);
|
|
1665
|
-
if (!result.issues)
|
|
1666
|
-
return result.value;
|
|
1667
|
-
const path = pathOf(run, depth);
|
|
1668
|
-
run.issues ??= [];
|
|
1669
|
-
if (result.issues.some((issue) => Object.isFrozen(issue))) {
|
|
1670
|
-
for (const issue of result.issues) {
|
|
1671
|
-
run.issues.push(movedIssue(issue, [...path, ...issue.path]));
|
|
1672
|
-
}
|
|
1673
|
-
} else {
|
|
1674
|
-
for (const issue of result.issues) {
|
|
1675
|
-
issue.path = [...path, ...issue.path];
|
|
1676
|
-
run.issues.push(issue);
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
return REJECTED;
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
// src/core/blueprint/list.ts
|
|
1683
|
-
function listOf2(item, { minItems, maxItems } = {}) {
|
|
1684
|
-
return standardListOf({
|
|
1685
|
-
[Kind2]: "list",
|
|
1686
|
-
item: fieldOf(item),
|
|
1687
|
-
optional: false,
|
|
1688
|
-
minItems,
|
|
1689
|
-
maxItems
|
|
1690
|
-
});
|
|
1691
|
-
}
|
|
1692
|
-
function standardListOf(list) {
|
|
1693
|
-
return Object.freeze(withStandard(list, (value) => parseField(list, value, [], "list")));
|
|
1694
|
-
}
|
|
1695
|
-
function isBlueprintList(value) {
|
|
1696
|
-
return typeof value === "object" && value !== null && value[Kind2] === "list";
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
// src/core/environment/environment.ts
|
|
1700
|
-
var InvalidEnvironment2 = exceptionOf2({
|
|
1701
|
-
layer: "environment" /* Environment */,
|
|
1702
|
-
name: "InvalidEnvironment",
|
|
1703
|
-
message: ({ keys }) => `Invalid environment variables: ${keys.join(", ")}.`
|
|
1704
|
-
});
|
|
1705
|
-
var processEnv = () => globalThis.process?.env ?? {};
|
|
1706
|
-
function environmentOf2(blueprint, { source = processEnv } = {}) {
|
|
1707
|
-
if (!isBlueprint(blueprint) || blueprint.optional) {
|
|
1708
|
-
throw new TypeError("An environment requires a blueprint");
|
|
1709
|
-
}
|
|
1710
|
-
let value;
|
|
1711
|
-
return Object.freeze({
|
|
1712
|
-
[Kind2]: "environment",
|
|
1713
|
-
blueprint,
|
|
1714
|
-
load() {
|
|
1715
|
-
if (value !== undefined)
|
|
1716
|
-
return value;
|
|
1717
|
-
value = parseEnvironment(blueprint, source());
|
|
1718
|
-
return value;
|
|
1719
|
-
}
|
|
1720
|
-
});
|
|
1721
|
-
}
|
|
1722
|
-
function parseEnvironment(blueprint, variables) {
|
|
1723
|
-
const declared = {};
|
|
1724
|
-
for (const [key, field] of Object.entries(blueprint.properties)) {
|
|
1725
|
-
const variable = variables[key];
|
|
1726
|
-
if (variable !== undefined)
|
|
1727
|
-
declared[key] = convert(field, variable);
|
|
1728
|
-
}
|
|
1729
|
-
const parsed = blueprint.safeParse(declared);
|
|
1730
|
-
if (!parsed.issues)
|
|
1731
|
-
return Object.freeze(parsed.value);
|
|
1732
|
-
const issues = parsed.issues;
|
|
1733
|
-
throw new InvalidEnvironment2({
|
|
1734
|
-
source: "environment",
|
|
1735
|
-
details: {
|
|
1736
|
-
keys: [...new Set(issues.map((issue) => String(issue.path[0] ?? "")))]
|
|
1737
|
-
},
|
|
1738
|
-
cause: issues.find((issue) => issue.cause)?.cause
|
|
1739
|
-
});
|
|
1740
|
-
}
|
|
1741
|
-
function convert(field, variable) {
|
|
1742
|
-
if (!isProperty(field))
|
|
1743
|
-
return variable;
|
|
1744
|
-
const { schema } = field.type;
|
|
1745
|
-
if (schema.matchShape(variable))
|
|
1746
|
-
return variable;
|
|
1747
|
-
const text = variable.trim();
|
|
1748
|
-
if (text === "true" || text === "false") {
|
|
1749
|
-
if (schema.matchShape(text === "true"))
|
|
1750
|
-
return text === "true";
|
|
1751
|
-
}
|
|
1752
|
-
const number = text === "" ? Number.NaN : Number(text);
|
|
1753
|
-
if (Number.isFinite(number) && schema.matchShape(number))
|
|
1754
|
-
return number;
|
|
1755
|
-
return variable;
|
|
1756
|
-
}
|
|
1757
|
-
function loadEnvironments(dependencies) {
|
|
1758
|
-
if (dependencies === undefined)
|
|
1759
|
-
return Object.freeze({});
|
|
1760
|
-
const list = isEnvironment(dependencies) ? [dependencies] : dependencies;
|
|
1761
|
-
return Object.freeze(Object.assign({}, ...list.map((environment) => environment.load())));
|
|
1762
|
-
}
|
|
1763
|
-
function isEnvironment(value) {
|
|
1764
|
-
return typeof value === "object" && value !== null && value[Kind2] === "environment";
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
// src/core/application/exceptions.ts
|
|
1768
|
-
var InvalidApplicationDeclaration2 = exceptionOf2({
|
|
1769
|
-
layer: "application" /* Application */,
|
|
1770
|
-
name: "InvalidApplicationDeclaration",
|
|
1771
|
-
message: ({ reason }) => reason
|
|
1772
|
-
});
|
|
1773
|
-
var DuplicateApplicationDeclaration2 = exceptionOf2({
|
|
1774
|
-
layer: "application" /* Application */,
|
|
1775
|
-
name: "DuplicateApplicationDeclaration",
|
|
1776
|
-
message: ({
|
|
1777
|
-
first,
|
|
1778
|
-
second
|
|
1779
|
-
}) => `The same object is registered as ${first} and as ${second}.`
|
|
1780
|
-
});
|
|
1781
|
-
var ApplicationConflict2 = exceptionOf2({
|
|
1782
|
-
layer: "application" /* Application */,
|
|
1783
|
-
name: "ApplicationConflict",
|
|
1784
|
-
message: ({
|
|
1785
|
-
reason
|
|
1786
|
-
}) => reason
|
|
1787
|
-
});
|
|
1788
|
-
var UnregisteredApplicationReference2 = exceptionOf2({
|
|
1789
|
-
layer: "application" /* Application */,
|
|
1790
|
-
name: "UnregisteredApplicationReference",
|
|
1791
|
-
message: ({
|
|
1792
|
-
holder,
|
|
1793
|
-
reference
|
|
1794
|
-
}) => `${holder} holds ${reference}, which is not registered in the application.`
|
|
1795
|
-
});
|
|
1796
|
-
var UnregisteredRepositoryDependency2 = exceptionOf2({
|
|
1797
|
-
layer: "application" /* Application */,
|
|
1798
|
-
name: "UnregisteredRepositoryDependency",
|
|
1799
|
-
message: ({
|
|
1800
|
-
repository,
|
|
1801
|
-
dependency
|
|
1802
|
-
}) => `Repository ${repository} depends on ${dependency}, which is not registered in the application.`
|
|
1803
|
-
});
|
|
1804
|
-
var UnregisteredUseCaseDependency2 = exceptionOf2({
|
|
1805
|
-
layer: "application" /* Application */,
|
|
1806
|
-
name: "UnregisteredUseCaseDependency",
|
|
1807
|
-
message: ({
|
|
1808
|
-
useCase,
|
|
1809
|
-
dependency
|
|
1810
|
-
}) => `Use case ${useCase} depends on ${dependency}, which is not registered in the application.`
|
|
1811
|
-
});
|
|
1812
|
-
var ApplicationNotStarted2 = exceptionOf2({
|
|
1813
|
-
layer: "application" /* Application */,
|
|
1814
|
-
name: "ApplicationNotStarted",
|
|
1815
|
-
message: ({
|
|
1816
|
-
application
|
|
1817
|
-
}) => application === undefined ? "No application is started: call await app.start() first." : `The application "${application}" is not started: call await app.start() first.`
|
|
1818
|
-
});
|
|
1819
|
-
var ProviderNotBound2 = exceptionOf2({
|
|
1820
|
-
layer: "application" /* Application */,
|
|
1821
|
-
name: "ProviderNotBound",
|
|
1822
|
-
message: ({
|
|
1823
|
-
provider
|
|
1824
|
-
}) => `The provider "${provider}" is made by an application: register its storage in applicationOf({ providers }) and call the repository through the application.`
|
|
1825
|
-
});
|
|
1826
|
-
var ApplicationAlreadyStarted2 = exceptionOf2({
|
|
1827
|
-
layer: "application" /* Application */,
|
|
1828
|
-
name: "ApplicationAlreadyStarted",
|
|
1829
|
-
message: ({
|
|
1830
|
-
current,
|
|
1831
|
-
attempted
|
|
1832
|
-
}) => `The application "${current}" is already started, so "${attempted}" cannot be: stop it, or call start({ replace: true }).`
|
|
1833
|
-
});
|
|
1834
|
-
var SchemaLockMismatch2 = exceptionOf2({
|
|
1835
|
-
layer: "application" /* Application */,
|
|
1836
|
-
name: "SchemaLockMismatch",
|
|
1837
|
-
message: ({ problems }) => `The application does not match its schema lock: ${problems.join(" ")}`
|
|
1838
|
-
});
|
|
1839
|
-
var InvalidSchemaMigration2 = exceptionOf2({
|
|
1840
|
-
layer: "application" /* Application */,
|
|
1841
|
-
name: "InvalidSchemaMigration",
|
|
1842
|
-
message: ({ reason }) => reason
|
|
1843
|
-
});
|
|
1844
|
-
var InvalidApplicationEnvironment2 = exceptionOf2({
|
|
1845
|
-
layer: "environment" /* Environment */,
|
|
1846
|
-
name: "InvalidApplicationEnvironment",
|
|
1847
|
-
message: ({
|
|
1848
|
-
environments
|
|
1849
|
-
}) => `Invalid environment variables: ${Object.entries(environments).map(([name, keys]) => `${name} (${keys.join(", ")})`).join("; ")}.`
|
|
1850
|
-
});
|
|
1851
|
-
|
|
1852
|
-
// src/core/application/registry.ts
|
|
1853
|
-
var SLOT = Symbol.for("afora.application");
|
|
1854
|
-
function slot() {
|
|
1855
|
-
const global = globalThis;
|
|
1856
|
-
global[SLOT] ??= { current: undefined };
|
|
1857
|
-
return global[SLOT];
|
|
1858
|
-
}
|
|
1859
|
-
function useApplication2() {
|
|
1860
|
-
const { current } = slot();
|
|
1861
|
-
if (current === undefined) {
|
|
1862
|
-
throw new ApplicationNotStarted2({ source: "useApplication", details: {} });
|
|
1863
|
-
}
|
|
1864
|
-
return current;
|
|
1865
|
-
}
|
|
1866
|
-
function resetApplication2() {
|
|
1867
|
-
slot().current = undefined;
|
|
1868
|
-
}
|
|
1869
|
-
function startedApplication() {
|
|
1870
|
-
return slot().current;
|
|
1871
|
-
}
|
|
1872
|
-
function setStartedApplication(application) {
|
|
1873
|
-
slot().current = application;
|
|
1874
|
-
}
|
|
1875
|
-
|
|
1876
|
-
// src/core/logger/exceptions.ts
|
|
1877
|
-
var InvalidLogDeclaration2 = exceptionOf2({
|
|
1878
|
-
layer: "application" /* Application */,
|
|
1879
|
-
name: "InvalidLogDeclaration",
|
|
1880
|
-
message: ({ reason }) => reason
|
|
1881
|
-
});
|
|
1882
|
-
|
|
1883
|
-
// src/core/logger/logger.ts
|
|
1884
|
-
var LogLevels2 = Object.freeze([
|
|
1885
|
-
"debug",
|
|
1886
|
-
"info",
|
|
1887
|
-
"warn",
|
|
1888
|
-
"error"
|
|
1889
|
-
]);
|
|
1890
|
-
var names = new WeakMap;
|
|
1891
|
-
var invalid = (reason) => {
|
|
1892
|
-
throw new InvalidLogDeclaration2({ source: "log", details: { reason } });
|
|
1893
|
-
};
|
|
1894
|
-
function logProviderOf2(settings) {
|
|
1895
|
-
if (!settings || typeof settings.write !== "function") {
|
|
1896
|
-
invalid("Expected a log provider with a write function.");
|
|
1897
|
-
}
|
|
1898
|
-
if (settings.flush !== undefined && typeof settings.flush !== "function") {
|
|
1899
|
-
invalid("Expected flush to be a function.");
|
|
1900
|
-
}
|
|
1901
|
-
if (settings.name !== undefined && (typeof settings.name !== "string" || settings.name.trim() === "")) {
|
|
1902
|
-
invalid("Expected the name of a log provider to be a non-empty string.");
|
|
1903
|
-
}
|
|
1904
|
-
const provider = Object.freeze({
|
|
1905
|
-
write: settings.write,
|
|
1906
|
-
...settings.flush ? { flush: settings.flush } : {}
|
|
1907
|
-
});
|
|
1908
|
-
if (settings.name)
|
|
1909
|
-
names.set(provider, settings.name);
|
|
1910
|
-
return provider;
|
|
1911
|
-
}
|
|
1912
|
-
function logProviderNameOf(provider) {
|
|
1913
|
-
return names.get(provider);
|
|
1914
|
-
}
|
|
1915
|
-
var fieldsText = (fields) => Object.keys(fields).length > 0 ? ` ${JSON.stringify(fields)}` : "";
|
|
1916
|
-
function consoleLogProvider2() {
|
|
1917
|
-
return logProviderOf2({
|
|
1918
|
-
name: "console",
|
|
1919
|
-
write: ({ at, level, event, fields, application }) => {
|
|
1920
|
-
const line = `${at} ${level.toUpperCase()} [${application}] ${event}${fieldsText(fields)}`;
|
|
1921
|
-
(level === "debug" ? console.debug : level === "info" ? console.info : level === "warn" ? console.warn : console.error)(line);
|
|
1922
|
-
}
|
|
1923
|
-
});
|
|
1924
|
-
}
|
|
1925
|
-
function jsonLogProvider2() {
|
|
1926
|
-
return logProviderOf2({
|
|
1927
|
-
name: "json",
|
|
1928
|
-
write: (entry) => {
|
|
1929
|
-
console.log(JSON.stringify({
|
|
1930
|
-
at: entry.at,
|
|
1931
|
-
level: entry.level,
|
|
1932
|
-
application: entry.application,
|
|
1933
|
-
event: entry.event,
|
|
1934
|
-
...entry.fields
|
|
1935
|
-
}));
|
|
1936
|
-
}
|
|
1937
|
-
});
|
|
1938
|
-
}
|
|
1939
|
-
function memoryLogProvider2() {
|
|
1940
|
-
const entries = [];
|
|
1941
|
-
const provider = Object.freeze({
|
|
1942
|
-
write: (entry) => {
|
|
1943
|
-
entries.push(entry);
|
|
1944
|
-
},
|
|
1945
|
-
entries,
|
|
1946
|
-
clear: () => {
|
|
1947
|
-
entries.length = 0;
|
|
1948
|
-
}
|
|
1949
|
-
});
|
|
1950
|
-
names.set(provider, "memory");
|
|
1951
|
-
return provider;
|
|
1952
|
-
}
|
|
1953
|
-
function checkLogSettings(settings) {
|
|
1954
|
-
if (typeof settings !== "object" || settings === null) {
|
|
1955
|
-
return invalid("Expected `log` to be { level?, providers }.");
|
|
1956
|
-
}
|
|
1957
|
-
const { level = "info", providers } = settings;
|
|
1958
|
-
if (!LogLevels2.includes(level)) {
|
|
1959
|
-
invalid(`Expected the log level to be one of ${LogLevels2.join(", ")}.`);
|
|
1960
|
-
}
|
|
1961
|
-
if (!Array.isArray(providers) || providers.some((provider) => typeof provider !== "object" || provider === null || typeof provider.write !== "function")) {
|
|
1962
|
-
invalid("Expected `log.providers` to be a list of log providers.");
|
|
1963
|
-
}
|
|
1964
|
-
return Object.freeze({ level, providers: Object.freeze([...providers]) });
|
|
1965
|
-
}
|
|
1966
|
-
var silentLogger = Object.freeze({
|
|
1967
|
-
debug: () => {},
|
|
1968
|
-
info: () => {},
|
|
1969
|
-
warn: () => {},
|
|
1970
|
-
error: () => {}
|
|
1971
|
-
});
|
|
1972
|
-
var rank = (level) => LogLevels2.indexOf(level);
|
|
1973
|
-
function applicationLogger(application) {
|
|
1974
|
-
let current;
|
|
1975
|
-
const write = (level) => (event, fields = {}) => {
|
|
1976
|
-
if (!current || rank(level) < rank(current.level))
|
|
1977
|
-
return;
|
|
1978
|
-
const entry = Object.freeze({
|
|
1979
|
-
at: new Date().toISOString(),
|
|
1980
|
-
level,
|
|
1981
|
-
event,
|
|
1982
|
-
fields,
|
|
1983
|
-
application
|
|
1984
|
-
});
|
|
1985
|
-
for (const provider of current.providers) {
|
|
1986
|
-
try {
|
|
1987
|
-
const written = provider.write(entry);
|
|
1988
|
-
if (written && typeof written.catch === "function") {
|
|
1989
|
-
written.catch(() => {});
|
|
1990
|
-
}
|
|
1991
|
-
} catch {}
|
|
1992
|
-
}
|
|
1993
|
-
};
|
|
1994
|
-
const logger = Object.freeze({
|
|
1995
|
-
debug: write("debug"),
|
|
1996
|
-
info: write("info"),
|
|
1997
|
-
warn: write("warn"),
|
|
1998
|
-
error: write("error")
|
|
1999
|
-
});
|
|
2000
|
-
return {
|
|
2001
|
-
logger,
|
|
2002
|
-
get settings() {
|
|
2003
|
-
return current;
|
|
2004
|
-
},
|
|
2005
|
-
set(settings) {
|
|
2006
|
-
current = settings;
|
|
2007
|
-
},
|
|
2008
|
-
async flush() {
|
|
2009
|
-
await Promise.all((current?.providers ?? []).map((provider) => Promise.resolve().then(() => provider.flush?.()).catch(() => {})));
|
|
2010
|
-
}
|
|
2011
|
-
};
|
|
2012
|
-
}
|
|
2013
|
-
var Logger2 = Object.freeze({
|
|
2014
|
-
[Kind2]: "logger"
|
|
2015
|
-
});
|
|
2016
|
-
function isLoggerDeclaration(value) {
|
|
2017
|
-
return value === Logger2;
|
|
2018
|
-
}
|
|
2019
|
-
function isLogger(value) {
|
|
2020
|
-
return typeof value === "object" && value !== null && ["debug", "info", "warn", "error"].every((level) => typeof value[level] === "function");
|
|
2021
|
-
}
|
|
2022
|
-
var ApplicationLoggerKey = Symbol("afora.application.logger");
|
|
2023
|
-
function resolveLogger(scoped, owner) {
|
|
2024
|
-
return scoped ?? owner?.[ApplicationLoggerKey] ?? startedApplication()?.[ApplicationLoggerKey];
|
|
2025
|
-
}
|
|
2026
|
-
function clock() {
|
|
2027
|
-
return globalThis.performance?.now() ?? Date.now();
|
|
2028
|
-
}
|
|
2029
|
-
function elapsed(since) {
|
|
2030
|
-
return Math.round(clock() - since);
|
|
2031
|
-
}
|
|
2032
|
-
var logged = new WeakSet;
|
|
2033
|
-
function logFailure(logger, event, fields, error) {
|
|
2034
|
-
if (!logger)
|
|
2035
|
-
return;
|
|
2036
|
-
const exception = error instanceof Exception2 ? error : undefined;
|
|
2037
|
-
const key = exception?.origin ?? error;
|
|
2038
|
-
if (typeof key === "object" && key !== null) {
|
|
2039
|
-
if (logged.has(key))
|
|
2040
|
-
return;
|
|
2041
|
-
logged.add(key);
|
|
2042
|
-
}
|
|
2043
|
-
const unexpected = !exception || exception.origin.name === UNEXPECTED_ERROR;
|
|
2044
|
-
try {
|
|
2045
|
-
logger[unexpected ? "error" : "warn"](event, {
|
|
2046
|
-
...fields,
|
|
2047
|
-
exception: exception ? exception.toJSON() : { message: error instanceof Error ? error.message : String(error) }
|
|
2048
|
-
});
|
|
2049
|
-
} catch {}
|
|
2050
|
-
}
|
|
2051
|
-
function writeLog(logger, level, event, fields) {
|
|
2052
|
-
if (!logger)
|
|
2053
|
-
return;
|
|
2054
|
-
try {
|
|
2055
|
-
logger[level](event, fields);
|
|
2056
|
-
} catch {}
|
|
2057
|
-
}
|
|
2058
|
-
|
|
2059
|
-
// src/core/symbols/meta.ts
|
|
2060
|
-
var Meta2 = Symbol("meta");
|
|
2061
|
-
|
|
2062
|
-
// src/core/record/exceptions.ts
|
|
2063
|
-
var InvalidRecordValue2 = exceptionOf2({
|
|
2064
|
-
layer: "record" /* Record */,
|
|
2065
|
-
name: "InvalidRecordValue",
|
|
2066
|
-
message: ({
|
|
2067
|
-
key,
|
|
2068
|
-
errors
|
|
2069
|
-
}, source) => `Invalid value for ${key ? `"${key}" of ` : ""}record "${source}": ${errors.join("; ")}`
|
|
2070
|
-
});
|
|
2071
|
-
var InvalidRecordDeclaration2 = exceptionOf2({
|
|
2072
|
-
layer: "record" /* Record */,
|
|
2073
|
-
name: "InvalidRecordDeclaration",
|
|
2074
|
-
message: (reason, source) => `Invalid declaration of record "${source}": ${reason}`
|
|
2075
|
-
});
|
|
2076
|
-
var UndeclaredRecordProperty2 = exceptionOf2({
|
|
2077
|
-
layer: "record" /* Record */,
|
|
2078
|
-
name: "UndeclaredRecordProperty",
|
|
2079
|
-
message: ({ key }, source) => `Property "${key}" is not declared in record "${source}".`
|
|
2080
|
-
});
|
|
2081
|
-
var ReservedRecordKey2 = exceptionOf2({
|
|
2082
|
-
layer: "record" /* Record */,
|
|
2083
|
-
name: "ReservedRecordKey",
|
|
2084
|
-
message: ({ key }, source) => `"${key}" is a member of record "${source}" and cannot be a key of its blueprint.`
|
|
2085
|
-
});
|
|
2086
|
-
var InvalidRecordPlugin2 = exceptionOf2({
|
|
2087
|
-
layer: "record" /* Record */,
|
|
2088
|
-
name: "InvalidRecordPlugin",
|
|
2089
|
-
message: ({ reason }, source) => `Invalid record plugin "${source}": ${reason}.`
|
|
2090
|
-
});
|
|
2091
|
-
var RecordPluginConflict2 = exceptionOf2({
|
|
2092
|
-
layer: "record" /* Record */,
|
|
2093
|
-
name: "RecordPluginConflict",
|
|
2094
|
-
message: ({
|
|
2095
|
-
plugin,
|
|
2096
|
-
key,
|
|
2097
|
-
owner
|
|
2098
|
-
}, source) => `Plugin "${plugin}" of record "${source}" adds "${key}", which ${owner} already has.`
|
|
2099
|
-
});
|
|
2100
|
-
var UnknownRecordPlugin2 = exceptionOf2({
|
|
2101
|
-
layer: "record" /* Record */,
|
|
2102
|
-
name: "UnknownRecordPlugin",
|
|
2103
|
-
message: ({ name }) => `No record plugin named "${name}" in the catalog.`
|
|
2104
|
-
});
|
|
2105
|
-
var IncompatibleRecordPlugin2 = exceptionOf2({
|
|
2106
|
-
layer: "record" /* Record */,
|
|
2107
|
-
name: "IncompatibleRecordPlugin",
|
|
2108
|
-
message: ({ reason }, source) => `Record plugin "${source}" does not satisfy the reference: ${reason}.`
|
|
2109
|
-
});
|
|
2110
|
-
|
|
2111
|
-
// src/core/record/marks.ts
|
|
2112
|
-
function isMarked(field, mark, { lists = false } = {}) {
|
|
2113
|
-
if (lists && isBlueprintList(field))
|
|
2114
|
-
return isMarked(field.item, mark, { lists });
|
|
2115
|
-
return isProperty(field) && field.type[mark] === true;
|
|
2116
|
-
}
|
|
2117
|
-
|
|
2118
|
-
// src/core/record/mask.ts
|
|
2119
|
-
var MASK2 = "********";
|
|
2120
|
-
function maskAll(value) {
|
|
2121
|
-
if (value === undefined || value === null)
|
|
2122
|
-
return value;
|
|
2123
|
-
if (Array.isArray(value))
|
|
2124
|
-
return Object.freeze(value.map(maskAll));
|
|
2125
|
-
if (typeof value === "object" && isRecordClass(value.constructor)) {
|
|
2126
|
-
return maskAll(value.toJSON());
|
|
2127
|
-
}
|
|
2128
|
-
if (typeof value === "object") {
|
|
2129
|
-
return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, maskAll(item)])));
|
|
2130
|
-
}
|
|
2131
|
-
return MASK2;
|
|
2132
|
-
}
|
|
2133
|
-
function maskField(field, value, sensitive) {
|
|
2134
|
-
if (value === undefined)
|
|
2135
|
-
return value;
|
|
2136
|
-
if (isBlueprintVariant(field)) {
|
|
2137
|
-
const name = variantNameOf(field, value);
|
|
2138
|
-
if (name !== undefined) {
|
|
2139
|
-
const json = Object.freeze({
|
|
2140
|
-
[field.key]: name,
|
|
2141
|
-
...value.toJSON()
|
|
2142
|
-
});
|
|
2143
|
-
return sensitive ? maskAll(json) : json;
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
|
-
if (recordFieldOf(field)) {
|
|
2147
|
-
const json = value.toJSON();
|
|
2148
|
-
return sensitive ? maskAll(json) : json;
|
|
2149
|
-
}
|
|
2150
|
-
if (sensitive || isMarked(field, "sensitive"))
|
|
2151
|
-
return maskAll(value);
|
|
2152
|
-
if (isBlueprintList(field) && Array.isArray(value)) {
|
|
2153
|
-
return Object.freeze(value.map((item) => maskField(field.item, item, false)));
|
|
2154
|
-
}
|
|
2155
|
-
if (isBlueprint(field) && typeof value === "object" && value !== null) {
|
|
2156
|
-
return maskCollection(field.properties, value);
|
|
2157
|
-
}
|
|
2158
|
-
if (isBlueprintVariant(field)) {
|
|
2159
|
-
const variant = variantOfValue(field, value);
|
|
2160
|
-
return variant ? maskCollection(variant.properties, value) : value;
|
|
2161
|
-
}
|
|
2162
|
-
return value;
|
|
2163
|
-
}
|
|
2164
|
-
function maskCollection(properties, value, sensitive = []) {
|
|
2165
|
-
return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
2166
|
-
key,
|
|
2167
|
-
maskField(properties[key], item, sensitive.includes(key))
|
|
2168
|
-
])));
|
|
2169
|
-
}
|
|
2170
|
-
|
|
2171
|
-
// src/core/record/abstract-record.ts
|
|
2172
|
-
var values = new WeakMap;
|
|
2173
|
-
var metadata = new WeakMap;
|
|
2174
|
-
var RESERVED_RECORD_KEYS2 = Object.freeze([
|
|
2175
|
-
"onSet",
|
|
2176
|
-
"onSetAll",
|
|
2177
|
-
"set",
|
|
2178
|
-
"toJSON",
|
|
2179
|
-
"toString",
|
|
2180
|
-
"toLocaleString",
|
|
2181
|
-
"valueOf",
|
|
2182
|
-
"hasOwnProperty",
|
|
2183
|
-
"propertyIsEnumerable",
|
|
2184
|
-
"isPrototypeOf",
|
|
2185
|
-
"__defineGetter__",
|
|
2186
|
-
"__defineSetter__",
|
|
2187
|
-
"__lookupGetter__",
|
|
2188
|
-
"__lookupSetter__",
|
|
2189
|
-
"__proto__",
|
|
2190
|
-
"constructor"
|
|
2191
|
-
]);
|
|
2192
|
-
function exposeRecordKeys(prototype, keys) {
|
|
2193
|
-
for (const key of keys) {
|
|
2194
|
-
Object.defineProperty(prototype, key, {
|
|
2195
|
-
get() {
|
|
2196
|
-
return values.get(this)?.[key];
|
|
2197
|
-
},
|
|
2198
|
-
enumerable: true,
|
|
2199
|
-
configurable: true
|
|
2200
|
-
});
|
|
2201
|
-
}
|
|
2202
|
-
}
|
|
2203
|
-
var checked = new WeakSet;
|
|
2204
|
-
function checkMembers(record, properties) {
|
|
2205
|
-
const Class = record.constructor;
|
|
2206
|
-
if (checked.has(Class))
|
|
2207
|
-
return;
|
|
2208
|
-
const keys = Object.keys(properties);
|
|
2209
|
-
for (let prototype = Object.getPrototypeOf(record);prototype !== null && !Object.hasOwn(prototype.constructor, "blueprint"); prototype = Object.getPrototypeOf(prototype)) {
|
|
2210
|
-
const key = Object.getOwnPropertyNames(prototype).find((name) => keys.includes(name));
|
|
2211
|
-
if (key !== undefined) {
|
|
2212
|
-
throw new ReservedRecordKey2({
|
|
2213
|
-
source: recordNameOf2(Class),
|
|
2214
|
-
details: { key }
|
|
2215
|
-
});
|
|
2216
|
-
}
|
|
2217
|
-
}
|
|
2218
|
-
checked.add(Class);
|
|
2219
|
-
}
|
|
2220
|
-
var vouched;
|
|
2221
|
-
function vouchFor(keys) {
|
|
2222
|
-
vouched = keys;
|
|
2223
|
-
}
|
|
2224
|
-
var constructions = new WeakMap;
|
|
2225
|
-
function constructionOf(record) {
|
|
2226
|
-
const Class = record.constructor;
|
|
2227
|
-
let construction = constructions.get(Class);
|
|
2228
|
-
if (!construction) {
|
|
2229
|
-
const { properties } = record[Meta2].blueprint;
|
|
2230
|
-
checkMembers(record, properties);
|
|
2231
|
-
const source = recordNameOf2(Class);
|
|
2232
|
-
construction = { source, parse: collectionParserOf(properties, source) };
|
|
2233
|
-
constructions.set(Class, construction);
|
|
2234
|
-
}
|
|
2235
|
-
return construction;
|
|
2236
|
-
}
|
|
2237
|
-
function withIssues(details, issues) {
|
|
2238
|
-
return Object.defineProperty(details, "issues", {
|
|
2239
|
-
value: Object.freeze([...issues]),
|
|
2240
|
-
enumerable: false
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2243
|
-
function exceptionOfIssues(issues, source) {
|
|
2244
|
-
const [first] = issues;
|
|
2245
|
-
const key = first.path.join(".");
|
|
2246
|
-
if (first.cause) {
|
|
2247
|
-
return first.cause.propagate({
|
|
2248
|
-
layer: "record" /* Record */,
|
|
2249
|
-
source,
|
|
2250
|
-
details: withIssues({ key }, issues)
|
|
2251
|
-
});
|
|
2252
|
-
}
|
|
2253
|
-
if (first.code === "undeclared_key") {
|
|
2254
|
-
return new UndeclaredRecordProperty2({
|
|
2255
|
-
source,
|
|
2256
|
-
details: withIssues({ key }, issues)
|
|
2257
|
-
});
|
|
2258
|
-
}
|
|
2259
|
-
return new InvalidRecordValue2({
|
|
2260
|
-
source,
|
|
2261
|
-
details: withIssues({ key, errors: [first.message] }, issues)
|
|
2262
|
-
});
|
|
2263
|
-
}
|
|
2264
|
-
function issuesOfError(error, source) {
|
|
2265
|
-
const issues = error?.details?.issues;
|
|
2266
|
-
if (error instanceof Exception2 && issues)
|
|
2267
|
-
return issues;
|
|
2268
|
-
const cause = Exception2.from(error, {
|
|
2269
|
-
layer: "record" /* Record */,
|
|
2270
|
-
source
|
|
2271
|
-
});
|
|
2272
|
-
return [
|
|
2273
|
-
{
|
|
2274
|
-
code: "invalid_value",
|
|
2275
|
-
message: cause.message,
|
|
2276
|
-
path: [],
|
|
2277
|
-
source,
|
|
2278
|
-
cause
|
|
2279
|
-
}
|
|
2280
|
-
];
|
|
2281
|
-
}
|
|
2282
|
-
var request;
|
|
2283
|
-
function exceptionOfRejection(rejection) {
|
|
2284
|
-
rejection.exception ??= exceptionOfIssues(rejection.issues, rejection.source);
|
|
2285
|
-
return rejection.exception;
|
|
2286
|
-
}
|
|
2287
|
-
var REJECTION_HANDLER = {
|
|
2288
|
-
get: (rejection, key) => Reflect.get(exceptionOfRejection(rejection), key),
|
|
2289
|
-
set: (rejection, key, value) => Reflect.set(exceptionOfRejection(rejection), key, value),
|
|
2290
|
-
has: (rejection, key) => Reflect.has(exceptionOfRejection(rejection), key),
|
|
2291
|
-
getPrototypeOf: (rejection) => Reflect.getPrototypeOf(exceptionOfRejection(rejection)),
|
|
2292
|
-
ownKeys: (rejection) => Reflect.ownKeys(exceptionOfRejection(rejection)),
|
|
2293
|
-
getOwnPropertyDescriptor: (rejection, key) => {
|
|
2294
|
-
const descriptor = Reflect.getOwnPropertyDescriptor(exceptionOfRejection(rejection), key);
|
|
2295
|
-
return descriptor && { ...descriptor, configurable: true };
|
|
2296
|
-
}
|
|
2297
|
-
};
|
|
2298
|
-
function parseRecord(Class, value) {
|
|
2299
|
-
if (value instanceof Class)
|
|
2300
|
-
return { value };
|
|
2301
|
-
const outer = request;
|
|
2302
|
-
const own = { Class };
|
|
2303
|
-
request = own;
|
|
2304
|
-
try {
|
|
2305
|
-
return { value: new Class(value) };
|
|
2306
|
-
} catch (error) {
|
|
2307
|
-
if (own.issues !== undefined && own.rejection === error) {
|
|
2308
|
-
return { issues: own.issues };
|
|
2309
|
-
}
|
|
2310
|
-
return { issues: issuesOfError(error, recordNameOf2(Class)) };
|
|
2311
|
-
} finally {
|
|
2312
|
-
request = outer;
|
|
2313
|
-
}
|
|
2314
|
-
}
|
|
2315
|
-
function recordValue(record) {
|
|
2316
|
-
return values.get(record);
|
|
2317
|
-
}
|
|
2318
|
-
function recordDataOf(record, options) {
|
|
2319
|
-
const { properties } = record[Meta2].blueprint;
|
|
2320
|
-
return dataOfCollection(properties, values.get(record), options);
|
|
2321
|
-
}
|
|
2322
|
-
function dataOfCollection(properties, value, options) {
|
|
2323
|
-
return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
2324
|
-
key,
|
|
2325
|
-
recordFieldDataOf(properties[key], item, options)
|
|
2326
|
-
])));
|
|
2327
|
-
}
|
|
2328
|
-
function recordFieldDataOf(field, value, options) {
|
|
2329
|
-
if (value === undefined || value === null)
|
|
2330
|
-
return value;
|
|
2331
|
-
if (isBlueprintVariant(field) && value instanceof AbstractRecord) {
|
|
2332
|
-
const name = variantNameOf(field, value);
|
|
2333
|
-
if (name !== undefined) {
|
|
2334
|
-
const reference = options?.reference?.(value);
|
|
2335
|
-
return Object.freeze(reference === undefined ? { [field.key]: name, ...recordDataOf(value, options) } : { [field.key]: name, id: reference });
|
|
2336
|
-
}
|
|
2337
|
-
}
|
|
2338
|
-
if (value instanceof AbstractRecord) {
|
|
2339
|
-
return options?.reference?.(value) ?? recordDataOf(value, options);
|
|
2340
|
-
}
|
|
2341
|
-
if (isBlueprintList(field) && Array.isArray(value)) {
|
|
2342
|
-
return Object.freeze(value.map((item) => recordFieldDataOf(field.item, item, options)));
|
|
2343
|
-
}
|
|
2344
|
-
if (isBlueprint(field) && typeof value === "object") {
|
|
2345
|
-
return dataOfCollection(field.properties, value, options);
|
|
2346
|
-
}
|
|
2347
|
-
if (isBlueprintVariant(field)) {
|
|
2348
|
-
const variant = variantOfValue(field, value);
|
|
2349
|
-
return variant ? dataOfCollection(variant.properties, value, options) : value;
|
|
2350
|
-
}
|
|
2351
|
-
return value;
|
|
2352
|
-
}
|
|
2353
|
-
function storeRecordValue(record, key, value) {
|
|
2354
|
-
const source = recordNameOf2(record.constructor);
|
|
2355
|
-
const { properties } = record[Meta2].blueprint;
|
|
2356
|
-
if (!Object.hasOwn(properties, key)) {
|
|
2357
|
-
throw exceptionOfIssues([
|
|
2358
|
-
{
|
|
2359
|
-
code: "undeclared_key",
|
|
2360
|
-
message: "is not declared",
|
|
2361
|
-
path: [key],
|
|
2362
|
-
source
|
|
2363
|
-
}
|
|
2364
|
-
], source);
|
|
2365
|
-
}
|
|
2366
|
-
const current = values.get(record);
|
|
2367
|
-
const previous = current[key];
|
|
2368
|
-
const result = parseField(properties[key], value, [key], source);
|
|
2369
|
-
if (result.issues)
|
|
2370
|
-
throw exceptionOfIssues(result.issues, source);
|
|
2371
|
-
const next = result.value;
|
|
2372
|
-
const { [key]: _, ...rest } = current;
|
|
2373
|
-
values.set(record, Object.freeze(next === undefined ? rest : { ...rest, [key]: next }));
|
|
2374
|
-
return { next, previous };
|
|
2375
|
-
}
|
|
2376
|
-
var RecordPluginHooks = Symbol("recordPluginHooks");
|
|
2377
|
-
function runRecordEffects(record, key, next, previous) {
|
|
2378
|
-
const pluginHooks = record.constructor[RecordPluginHooks];
|
|
2379
|
-
if (pluginHooks !== undefined && pluginHooks.length > 0) {
|
|
2380
|
-
const name = String(key);
|
|
2381
|
-
for (const hook of pluginHooks) {
|
|
2382
|
-
if (!hook.keys.includes(name))
|
|
2383
|
-
continue;
|
|
2384
|
-
hook.onSetAll?.call(record, { key, value: next, previous });
|
|
2385
|
-
hook.onSet?.call(record)[name]?.call(record, next, previous);
|
|
2386
|
-
}
|
|
2387
|
-
}
|
|
2388
|
-
const hooks = record;
|
|
2389
|
-
hooks.onSetAll({ key, value: next, previous });
|
|
2390
|
-
hooks.onSet()[key]?.(next, previous);
|
|
2391
|
-
return record;
|
|
2392
|
-
}
|
|
2393
|
-
|
|
2394
|
-
class AbstractRecord {
|
|
2395
|
-
get [Meta2]() {
|
|
2396
|
-
const Class = this.constructor;
|
|
2397
|
-
let declaration = metadata.get(Class);
|
|
2398
|
-
if (!declaration) {
|
|
2399
|
-
const { blueprint, options } = Class;
|
|
2400
|
-
declaration = Object.freeze({ blueprint, options });
|
|
2401
|
-
metadata.set(Class, declaration);
|
|
2402
|
-
}
|
|
2403
|
-
return declaration;
|
|
2404
|
-
}
|
|
2405
|
-
constructor(value) {
|
|
2406
|
-
let asked;
|
|
2407
|
-
if (request !== undefined && request.Class === this.constructor) {
|
|
2408
|
-
asked = request;
|
|
2409
|
-
request = undefined;
|
|
2410
|
-
}
|
|
2411
|
-
const made = vouched;
|
|
2412
|
-
vouched = undefined;
|
|
2413
|
-
const { source, parse } = constructionOf(this);
|
|
2414
|
-
const result = parse(value, made);
|
|
2415
|
-
if (result.issues) {
|
|
2416
|
-
if (asked === undefined)
|
|
2417
|
-
throw exceptionOfIssues(result.issues, source);
|
|
2418
|
-
asked.issues = result.issues;
|
|
2419
|
-
asked.rejection = new Proxy({ issues: asked.issues, source }, REJECTION_HANDLER);
|
|
2420
|
-
throw asked.rejection;
|
|
2421
|
-
}
|
|
2422
|
-
values.set(this, result.value);
|
|
2423
|
-
}
|
|
2424
|
-
static safeParse(value) {
|
|
2425
|
-
return parseRecord(this, value);
|
|
2426
|
-
}
|
|
2427
|
-
static get "~standard"() {
|
|
2428
|
-
return standardOfClass(this);
|
|
2429
|
-
}
|
|
2430
|
-
toJSON() {
|
|
2431
|
-
return maskCollection(this[Meta2].blueprint.properties, recordValue(this), this[Meta2].options.sensitive);
|
|
2432
|
-
}
|
|
2433
|
-
set(key, value) {
|
|
2434
|
-
const { next, previous } = storeRecordValue(this, String(key), value);
|
|
2435
|
-
return runRecordEffects(this, key, next, previous);
|
|
2436
|
-
}
|
|
2437
|
-
onSetAll(_change) {}
|
|
2438
|
-
onSet() {
|
|
2439
|
-
return {};
|
|
2440
|
-
}
|
|
2441
|
-
}
|
|
2442
|
-
|
|
2443
|
-
// src/core/blueprint/blueprint.ts
|
|
2444
|
-
import { Type as Type3 } from "typebox";
|
|
2445
|
-
|
|
2446
|
-
// src/core/property/property.ts
|
|
2447
|
-
import { Type } from "typebox";
|
|
2448
|
-
function propertyOf2({
|
|
2449
|
-
name,
|
|
2450
|
-
schema,
|
|
2451
|
-
optional,
|
|
2452
|
-
sensitive = false,
|
|
2453
|
-
unique = false,
|
|
2454
|
-
default: _default,
|
|
2455
|
-
preHandle: onPreHandle,
|
|
2456
|
-
afterHandle: onAfterHandle
|
|
2457
|
-
}) {
|
|
2458
|
-
const valueSchema = optional ? Type.Optional(schema) : schema;
|
|
2459
|
-
const SchemaConstructor = schemaOf(name, valueSchema);
|
|
2460
|
-
const type = {
|
|
2461
|
-
[Demo2]: _default,
|
|
2462
|
-
name,
|
|
2463
|
-
schema: new SchemaConstructor,
|
|
2464
|
-
optional: optional ?? false,
|
|
2465
|
-
sensitive,
|
|
2466
|
-
unique
|
|
2467
|
-
};
|
|
2468
|
-
|
|
2469
|
-
class DefineProperty extends AbstractDefineProperty {
|
|
2470
|
-
get type() {
|
|
2471
|
-
return type;
|
|
2472
|
-
}
|
|
2473
|
-
}
|
|
2474
|
-
const steps = DefineProperty.prototype;
|
|
2475
|
-
if (onPreHandle)
|
|
2476
|
-
steps.preHandle = (value) => onPreHandle(value);
|
|
2477
|
-
if (onAfterHandle)
|
|
2478
|
-
steps.afterHandle = (value) => onAfterHandle(value);
|
|
2479
|
-
declarePipeline(DefineProperty.prototype);
|
|
2480
|
-
|
|
2481
|
-
class Property extends AbstractProperty {
|
|
2482
|
-
static type = type;
|
|
2483
|
-
createDefinition() {
|
|
2484
|
-
return new DefineProperty;
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
return Property;
|
|
2488
|
-
}
|
|
2489
|
-
|
|
2490
|
-
// src/core/blueprint/optional.ts
|
|
2491
|
-
import { Type as Type2 } from "typebox";
|
|
2492
|
-
var cache2 = new WeakMap;
|
|
2493
|
-
function optionalOf2(given) {
|
|
2494
|
-
const field = fieldOf(given);
|
|
2495
|
-
const cached = cache2.get(field);
|
|
2496
|
-
if (cached)
|
|
2497
|
-
return cached;
|
|
2498
|
-
if (isOptionalRecord(field))
|
|
2499
|
-
return field;
|
|
2500
|
-
if (isRecordClass(field)) {
|
|
2501
|
-
const optional = Object.freeze(withStandard({
|
|
2502
|
-
[Kind2]: "record",
|
|
2503
|
-
record: field,
|
|
2504
|
-
optional: true
|
|
2505
|
-
}, (value) => value === undefined ? { value } : field.safeParse(value)));
|
|
2506
|
-
cache2.set(field, optional);
|
|
2507
|
-
return optional;
|
|
2508
|
-
}
|
|
2509
|
-
if (isBlueprint(field)) {
|
|
2510
|
-
if (field.optional)
|
|
2511
|
-
return field;
|
|
2512
|
-
const optional = {
|
|
2513
|
-
...field,
|
|
2514
|
-
optional: true,
|
|
2515
|
-
safeParse: (value) => value === undefined ? { value } : field.safeParse(value)
|
|
2516
|
-
};
|
|
2517
|
-
Object.freeze(withStandard(optional, (value) => optional.safeParse(value)));
|
|
2518
|
-
cache2.set(field, optional);
|
|
2519
|
-
return optional;
|
|
2520
|
-
}
|
|
2521
|
-
if (isBlueprintList(field)) {
|
|
2522
|
-
if (field.optional)
|
|
2523
|
-
return field;
|
|
2524
|
-
const optional = standardListOf({ ...field, optional: true });
|
|
2525
|
-
cache2.set(field, optional);
|
|
2526
|
-
return optional;
|
|
2527
|
-
}
|
|
2528
|
-
if (isBlueprintVariant(field)) {
|
|
2529
|
-
if (field.optional)
|
|
2530
|
-
return field;
|
|
2531
|
-
const optional = standardVariantOf({ ...field, optional: true });
|
|
2532
|
-
cache2.set(field, optional);
|
|
2533
|
-
return optional;
|
|
2534
|
-
}
|
|
2535
|
-
const Property = field;
|
|
2536
|
-
if (Property.type.optional)
|
|
2537
|
-
return Property;
|
|
2538
|
-
const base = Property.type;
|
|
2539
|
-
const SchemaConstructor = schemaOf(base.name, Type2.Optional(base.schema.type.Type()));
|
|
2540
|
-
const type = {
|
|
2541
|
-
...base,
|
|
2542
|
-
schema: new SchemaConstructor,
|
|
2543
|
-
optional: true
|
|
2544
|
-
};
|
|
2545
|
-
const Optional = derivePropertyOf(Property, type);
|
|
2546
|
-
recordPropertyLineage(Optional, { kind: "optional", base: Property });
|
|
2547
|
-
cache2.set(Property, Optional);
|
|
2548
|
-
return Optional;
|
|
2549
|
-
}
|
|
2550
|
-
|
|
2551
|
-
// src/core/blueprint/blueprint.ts
|
|
2552
|
-
function blueprintBuilderOf2(...base) {
|
|
2553
|
-
return (sourcesOrDefine, maybeDefine) => {
|
|
2554
|
-
const [sources, define] = typeof sourcesOrDefine === "function" ? [[], sourcesOrDefine] : [
|
|
2555
|
-
sourcesOrDefine,
|
|
2556
|
-
maybeDefine
|
|
2557
|
-
];
|
|
2558
|
-
const all = [...base, ...sources];
|
|
2559
|
-
return create(all.flatMap((source) => isBlueprint(source) ? source.plugins : [source]), { ...define(contextOf2(all)) });
|
|
2560
|
-
};
|
|
2561
|
-
}
|
|
2562
|
-
function blueprintFromProperties(plugins, properties) {
|
|
2563
|
-
return create(plugins, { ...properties });
|
|
2564
|
-
}
|
|
2565
|
-
function create(plugins, properties) {
|
|
2566
|
-
const shape = {};
|
|
2567
|
-
for (const [key, field] of Object.entries(properties)) {
|
|
2568
|
-
properties[key] = fieldOf(field);
|
|
2569
|
-
shape[key] = schemaOfField(key, properties[key]);
|
|
2570
|
-
}
|
|
2571
|
-
const SchemaConstructor = schemaOf("blueprint", Type3.Object(shape));
|
|
2572
|
-
const safeParse = collectionParserOf(properties, "blueprint");
|
|
2573
|
-
const blueprint = {
|
|
2574
|
-
[Kind2]: "blueprint",
|
|
2575
|
-
plugins: Object.freeze([...new Set(plugins)]),
|
|
2576
|
-
properties: Object.freeze(properties),
|
|
2577
|
-
schema: new SchemaConstructor,
|
|
2578
|
-
optional: false,
|
|
2579
|
-
safeParse,
|
|
2580
|
-
join: (...others) => create([blueprint, ...others].flatMap((source) => source.plugins), Object.assign({}, ...[blueprint, ...others].map((source) => source.properties)))
|
|
2581
|
-
};
|
|
2582
|
-
return Object.freeze(withStandard(blueprint, safeParse));
|
|
2583
|
-
}
|
|
2584
|
-
var HELPERS = { listOf: listOf2, optionalOf: optionalOf2, propertyOf: propertyOf2, variantOf: variantOf2 };
|
|
2585
|
-
var RESERVED_KEYS = ["optional", "list", ...Object.keys(HELPERS)];
|
|
2586
|
-
function contextOf2(sources) {
|
|
2587
|
-
for (const key of RESERVED_KEYS) {
|
|
2588
|
-
const reserving = sources.find((source) => Object.hasOwn(source.properties, key));
|
|
2589
|
-
if (reserving) {
|
|
2590
|
-
throw new ReservedBlueprintKey2({
|
|
2591
|
-
source: isBlueprint(reserving) ? "blueprint" : reserving.name,
|
|
2592
|
-
details: { key }
|
|
2593
|
-
});
|
|
2594
|
-
}
|
|
2595
|
-
}
|
|
2596
|
-
const factories = Object.assign({}, ...sources.map((source) => isBlueprint(source) ? {} : source.factories ?? {}));
|
|
2597
|
-
for (const key of RESERVED_KEYS) {
|
|
2598
|
-
if (Object.hasOwn(factories, key)) {
|
|
2599
|
-
const reserving = sources.find((source) => !isBlueprint(source) && Object.hasOwn(source.factories ?? {}, key));
|
|
2600
|
-
throw new ReservedBlueprintKey2({
|
|
2601
|
-
source: reserving.name,
|
|
2602
|
-
details: { key }
|
|
2603
|
-
});
|
|
2604
|
-
}
|
|
2605
|
-
}
|
|
2606
|
-
const available = Object.assign({}, ...sources.map((source) => source.properties));
|
|
2607
|
-
for (const key of Object.keys(factories))
|
|
2608
|
-
delete available[key];
|
|
2609
|
-
const mirror = (fields, map) => Object.fromEntries(Object.entries(fields).map(([key, field]) => [key, map(field)]));
|
|
2610
|
-
const list = mirror(available, (field) => listOf2(field));
|
|
2611
|
-
const callable = (field) => isProperty(field) ? callableOf(field) : field;
|
|
2612
|
-
return Object.freeze({
|
|
2613
|
-
...mirror(available, callable),
|
|
2614
|
-
...factories,
|
|
2615
|
-
...HELPERS,
|
|
2616
|
-
optional: Object.freeze(mirror(available, (field) => callable(optionalOf2(field)))),
|
|
2617
|
-
list: Object.freeze({
|
|
2618
|
-
...list,
|
|
2619
|
-
optional: Object.freeze(mirror(list, optionalOf2))
|
|
2620
|
-
})
|
|
2621
|
-
});
|
|
2622
|
-
}
|
|
2623
|
-
function schemaOfField(key, field) {
|
|
2624
|
-
if (isBlueprintList(field)) {
|
|
2625
|
-
const { item, minItems, maxItems } = field;
|
|
2626
|
-
const schema = Type3.Array(schemaOfField(key, item), {
|
|
2627
|
-
...minItems === undefined ? {} : { minItems },
|
|
2628
|
-
...maxItems === undefined ? {} : { maxItems }
|
|
2629
|
-
});
|
|
2630
|
-
return field.optional ? Type3.Optional(schema) : schema;
|
|
2631
|
-
}
|
|
2632
|
-
if (isBlueprint(field)) {
|
|
2633
|
-
const schema = field.schema.type.Type();
|
|
2634
|
-
return field.optional ? Type3.Optional(schema) : schema;
|
|
2635
|
-
}
|
|
2636
|
-
if (isBlueprintVariant(field)) {
|
|
2637
|
-
const schema = Type3.Union(Object.entries(field.variants).map(([tag, variant]) => {
|
|
2638
|
-
const object = blueprintOfVariant(variant).schema.type.Type();
|
|
2639
|
-
return {
|
|
2640
|
-
...object,
|
|
2641
|
-
properties: {
|
|
2642
|
-
[field.key]: Type3.Literal(tag),
|
|
2643
|
-
...object.properties
|
|
2644
|
-
},
|
|
2645
|
-
required: [field.key, ...object.required ?? []]
|
|
2646
|
-
};
|
|
2647
|
-
}));
|
|
2648
|
-
return field.optional ? Type3.Optional(schema) : schema;
|
|
2649
|
-
}
|
|
2650
|
-
const record = recordFieldOf(field);
|
|
2651
|
-
if (record) {
|
|
2652
|
-
const schema = record.record.blueprint.schema.type.Type();
|
|
2653
|
-
return record.optional ? Type3.Optional(schema) : schema;
|
|
2654
|
-
}
|
|
2655
|
-
if (isProperty(field)) {
|
|
2656
|
-
return field.type.schema.type.Type();
|
|
2657
|
-
}
|
|
2658
|
-
throw new UndeclaredBlueprintProperty2({
|
|
2659
|
-
source: "blueprint",
|
|
2660
|
-
details: { key }
|
|
2661
|
-
});
|
|
2662
|
-
}
|
|
2663
|
-
|
|
2664
|
-
// src/core/record/plugin.ts
|
|
2665
|
-
var RecordPlugins = Symbol("recordPlugins");
|
|
2666
|
-
var IdentifiedRecord = Symbol("identifiedRecord");
|
|
2667
|
-
var SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
2668
|
-
function isVersion(version) {
|
|
2669
|
-
return typeof version === "string" && SEMVER.test(version);
|
|
2670
|
-
}
|
|
2671
|
-
function versionParts(version) {
|
|
2672
|
-
const [, major, minor, patch] = SEMVER.exec(version);
|
|
2673
|
-
return [Number(major), Number(minor), Number(patch)];
|
|
2674
|
-
}
|
|
2675
|
-
function satisfies(available, requested) {
|
|
2676
|
-
const [major, minor, patch] = versionParts(available);
|
|
2677
|
-
const [wantedMajor, wantedMinor, wantedPatch] = versionParts(requested);
|
|
2678
|
-
if (major !== wantedMajor)
|
|
2679
|
-
return false;
|
|
2680
|
-
if (major === 0 && minor !== wantedMinor)
|
|
2681
|
-
return false;
|
|
2682
|
-
if (minor !== wantedMinor)
|
|
2683
|
-
return minor > wantedMinor;
|
|
2684
|
-
return patch >= wantedPatch;
|
|
2685
|
-
}
|
|
2686
|
-
var HOOKS = ["onSet", "onSetAll"];
|
|
2687
|
-
var internals = new WeakMap;
|
|
2688
|
-
function pluginsOf2(value) {
|
|
2689
|
-
const Class = typeof value === "function" ? value : typeof value === "object" && value !== null ? value.constructor : undefined;
|
|
2690
|
-
return Class?.[RecordPlugins] ?? [];
|
|
2691
|
-
}
|
|
2692
|
-
function isRecordPlugin(value) {
|
|
2693
|
-
return typeof value === "object" && value !== null && value[Kind2] === "record-plugin";
|
|
2694
|
-
}
|
|
2695
|
-
function hasPlugin2(value, plugin) {
|
|
2696
|
-
const plugins = pluginsOf2(value);
|
|
2697
|
-
if (typeof plugin === "string") {
|
|
2698
|
-
return plugins.some((applied) => applied.name === plugin);
|
|
2699
|
-
}
|
|
2700
|
-
if (plugins.includes(plugin))
|
|
2701
|
-
return true;
|
|
2702
|
-
return typeof value === "function" ? value === plugin.record || value.prototype instanceof plugin.record : value instanceof plugin.record;
|
|
2703
|
-
}
|
|
2704
|
-
function membersOf(Record, name) {
|
|
2705
|
-
const descriptors = {};
|
|
2706
|
-
const hooks = {};
|
|
2707
|
-
for (let prototype = Record.prototype;prototype !== null && !Object.hasOwn(prototype.constructor, "blueprint"); prototype = Object.getPrototypeOf(prototype)) {
|
|
2708
|
-
for (const member of Object.getOwnPropertyNames(prototype)) {
|
|
2709
|
-
if (member === "constructor")
|
|
2710
|
-
continue;
|
|
2711
|
-
const descriptor = Object.getOwnPropertyDescriptor(prototype, member);
|
|
2712
|
-
if (HOOKS.includes(member)) {
|
|
2713
|
-
hooks[member] ??= descriptor.value;
|
|
2714
|
-
continue;
|
|
2715
|
-
}
|
|
2716
|
-
if (RESERVED_RECORD_KEYS2.includes(member)) {
|
|
2717
|
-
throw new InvalidRecordPlugin2({
|
|
2718
|
-
source: name,
|
|
2719
|
-
details: {
|
|
2720
|
-
reason: `"${member}" is a member of every record and cannot be replaced`
|
|
2721
|
-
}
|
|
2722
|
-
});
|
|
2723
|
-
}
|
|
2724
|
-
descriptors[member] ??= descriptor;
|
|
2725
|
-
}
|
|
2726
|
-
}
|
|
2727
|
-
return { descriptors: Object.freeze(descriptors), hooks };
|
|
2728
|
-
}
|
|
2729
|
-
function recordPluginOf2(name, Record, { version = "1.0.0", description } = {}) {
|
|
2730
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
2731
|
-
throw new InvalidRecordPlugin2({
|
|
2732
|
-
source: String(name),
|
|
2733
|
-
details: { reason: "its name must be a non-empty string" }
|
|
2734
|
-
});
|
|
2735
|
-
}
|
|
2736
|
-
if (!isRecordClass(Record)) {
|
|
2737
|
-
throw new InvalidRecordPlugin2({
|
|
2738
|
-
source: name,
|
|
2739
|
-
details: { reason: "it must be made from a class of `recordOf`" }
|
|
2740
|
-
});
|
|
2741
|
-
}
|
|
2742
|
-
if (Record[IdentifiedRecord]) {
|
|
2743
|
-
throw new InvalidRecordPlugin2({
|
|
2744
|
-
source: name,
|
|
2745
|
-
details: {
|
|
2746
|
-
reason: "it must be made from a record, not an entity: plugins have no identity"
|
|
2747
|
-
}
|
|
2748
|
-
});
|
|
2749
|
-
}
|
|
2750
|
-
if (!isVersion(version)) {
|
|
2751
|
-
throw new InvalidRecordPlugin2({
|
|
2752
|
-
source: name,
|
|
2753
|
-
details: { reason: `"${version}" is not a semantic version` }
|
|
2754
|
-
});
|
|
2755
|
-
}
|
|
2756
|
-
const requires = pluginsOf2(Record);
|
|
2757
|
-
const inherited = new Set(requires.flatMap((required) => required.keys));
|
|
2758
|
-
const declaration = Record;
|
|
2759
|
-
const keys = Object.freeze(Object.keys(declaration.blueprint.properties).filter((key) => !inherited.has(key)));
|
|
2760
|
-
const own = membersOf(Record, name);
|
|
2761
|
-
const plugin = Object.freeze({
|
|
2762
|
-
[Kind2]: "record-plugin",
|
|
2763
|
-
name,
|
|
2764
|
-
version,
|
|
2765
|
-
...description === undefined ? {} : { description },
|
|
2766
|
-
record: Record,
|
|
2767
|
-
keys,
|
|
2768
|
-
members: Object.freeze(Object.keys(own.descriptors)),
|
|
2769
|
-
options: declaration.options,
|
|
2770
|
-
requires,
|
|
2771
|
-
is: (value) => hasPlugin2(value, plugin),
|
|
2772
|
-
toJSON: () => descriptorOf(plugin)
|
|
2773
|
-
});
|
|
2774
|
-
internals.set(plugin, own);
|
|
2775
|
-
return plugin;
|
|
2776
|
-
}
|
|
2777
|
-
function descriptorOf(plugin) {
|
|
2778
|
-
return Object.freeze({
|
|
2779
|
-
kind: "record-plugin",
|
|
2780
|
-
name: plugin.name,
|
|
2781
|
-
version: plugin.version,
|
|
2782
|
-
...plugin.description === undefined ? {} : { description: plugin.description },
|
|
2783
|
-
keys: plugin.keys,
|
|
2784
|
-
sensitive: plugin.options.sensitive,
|
|
2785
|
-
unique: plugin.options.unique,
|
|
2786
|
-
change: plugin.options.change,
|
|
2787
|
-
members: plugin.members,
|
|
2788
|
-
requires: Object.freeze(plugin.requires.map(({ name, version }) => Object.freeze({ name, version })))
|
|
2789
|
-
});
|
|
2790
|
-
}
|
|
2791
|
-
function applyPlugins(blueprint, plugins, name, reserved) {
|
|
2792
|
-
const flat = [];
|
|
2793
|
-
for (const plugin of plugins) {
|
|
2794
|
-
if (!isRecordPlugin(plugin)) {
|
|
2795
|
-
throw new InvalidRecordPlugin2({
|
|
2796
|
-
source: name,
|
|
2797
|
-
details: {
|
|
2798
|
-
reason: "`options.plugins` takes plugins made by `recordPluginOf`"
|
|
2799
|
-
}
|
|
2800
|
-
});
|
|
2801
|
-
}
|
|
2802
|
-
for (const applied of [...plugin.requires, plugin]) {
|
|
2803
|
-
if (flat.includes(applied))
|
|
2804
|
-
continue;
|
|
2805
|
-
if (flat.some((other) => other.name === applied.name)) {
|
|
2806
|
-
throw new RecordPluginConflict2({
|
|
2807
|
-
source: name,
|
|
2808
|
-
details: {
|
|
2809
|
-
plugin: applied.name,
|
|
2810
|
-
key: applied.name,
|
|
2811
|
-
owner: "another plugin"
|
|
2812
|
-
}
|
|
2813
|
-
});
|
|
2814
|
-
}
|
|
2815
|
-
flat.push(applied);
|
|
2816
|
-
}
|
|
2817
|
-
}
|
|
2818
|
-
const owners = new Map(Object.keys(blueprint.properties).map((key) => [key, `record "${name}"`]));
|
|
2819
|
-
for (const member of reserved)
|
|
2820
|
-
owners.set(member, `record "${name}"`);
|
|
2821
|
-
const claim = (plugin, key) => {
|
|
2822
|
-
const owner = owners.get(key);
|
|
2823
|
-
if (owner !== undefined) {
|
|
2824
|
-
throw new RecordPluginConflict2({
|
|
2825
|
-
source: name,
|
|
2826
|
-
details: { plugin: plugin.name, key, owner }
|
|
2827
|
-
});
|
|
2828
|
-
}
|
|
2829
|
-
owners.set(key, `plugin "${plugin.name}"`);
|
|
2830
|
-
};
|
|
2831
|
-
const descriptors = {};
|
|
2832
|
-
const hooks = [];
|
|
2833
|
-
for (const plugin of flat) {
|
|
2834
|
-
for (const key of plugin.keys)
|
|
2835
|
-
claim(plugin, key);
|
|
2836
|
-
const own = internals.get(plugin);
|
|
2837
|
-
for (const member of plugin.members) {
|
|
2838
|
-
claim(plugin, member);
|
|
2839
|
-
descriptors[member] = own.descriptors[member];
|
|
2840
|
-
}
|
|
2841
|
-
if (own.hooks.onSet || own.hooks.onSetAll) {
|
|
2842
|
-
hooks.push(Object.freeze({
|
|
2843
|
-
plugin,
|
|
2844
|
-
keys: Object.freeze(Object.keys(plugin.record.blueprint.properties)),
|
|
2845
|
-
...own.hooks
|
|
2846
|
-
}));
|
|
2847
|
-
}
|
|
2848
|
-
}
|
|
2849
|
-
return {
|
|
2850
|
-
blueprint: flat.length === 0 ? blueprint : blueprint.join(...flat.map((plugin) => plugin.record.blueprint)),
|
|
2851
|
-
plugins: Object.freeze(flat),
|
|
2852
|
-
sensitive: flat.flatMap((plugin) => plugin.options.sensitive),
|
|
2853
|
-
unique: flat.flatMap((plugin) => plugin.options.unique),
|
|
2854
|
-
change: flat.flatMap((plugin) => plugin.options.change),
|
|
2855
|
-
descriptors,
|
|
2856
|
-
hooks: Object.freeze(hooks)
|
|
2857
|
-
};
|
|
2858
|
-
}
|
|
2859
|
-
|
|
2860
|
-
// src/core/record/record.ts
|
|
2861
|
-
function recordBuilderOf2(...catalogs) {
|
|
2862
|
-
const context = pluginContextOf(catalogs);
|
|
2863
|
-
return (blueprint, options = {}) => declareRecord(AbstractRecord, blueprint, options, "record", [], context);
|
|
2864
|
-
}
|
|
2865
|
-
function pluginContextOf(catalogs) {
|
|
2866
|
-
return Object.freeze(Object.assign({}, ...catalogs.map((catalog) => catalog.plugins)));
|
|
2867
|
-
}
|
|
2868
|
-
var recordOf3 = recordBuilderOf2();
|
|
2869
|
-
function declareRecord(Base, declared, { plugins = [], name: declaredName, ...declaredOptions }, fallback, reserved = [], context = {}) {
|
|
2870
|
-
if (declaredName !== undefined && !isRecordName(declaredName)) {
|
|
2871
|
-
throw new InvalidRecordDeclaration2({
|
|
2872
|
-
source: fallback,
|
|
2873
|
-
details: `"name" must be an identifier, got ${JSON.stringify(declaredName)}.`
|
|
2874
|
-
});
|
|
2875
|
-
}
|
|
2876
|
-
const name = declaredName ?? fallback;
|
|
2877
|
-
const applied = applyPlugins(declared, typeof plugins === "function" ? plugins(context) : plugins, name, reserved);
|
|
2878
|
-
const blueprint = applied.blueprint;
|
|
2879
|
-
const sensitive = [
|
|
2880
|
-
...declaredOptions.sensitive ?? [],
|
|
2881
|
-
...applied.sensitive
|
|
2882
|
-
];
|
|
2883
|
-
const unique = [...declaredOptions.unique ?? [], ...applied.unique];
|
|
2884
|
-
const declaredChange = declaredOptions.change ?? [];
|
|
2885
|
-
const keys = Object.keys(blueprint.properties);
|
|
2886
|
-
const change = keys.filter((key) => declaredChange.includes(key) || applied.change.includes(key));
|
|
2887
|
-
for (const key of [...sensitive, ...unique, ...declaredChange]) {
|
|
2888
|
-
if (!keys.includes(key)) {
|
|
2889
|
-
throw new UndeclaredRecordProperty2({
|
|
2890
|
-
source: name,
|
|
2891
|
-
details: { key }
|
|
2892
|
-
});
|
|
2893
|
-
}
|
|
2894
|
-
}
|
|
2895
|
-
const methods = change.length > 0 ? [CHANGE_MEMBER] : [];
|
|
2896
|
-
for (const member of Object.keys(applied.descriptors)) {
|
|
2897
|
-
if (methods.includes(member)) {
|
|
2898
|
-
const plugin = applied.plugins.find((plugin) => plugin.members.includes(member));
|
|
2899
|
-
throw new RecordPluginConflict2({
|
|
2900
|
-
source: name,
|
|
2901
|
-
details: {
|
|
2902
|
-
plugin: plugin.name,
|
|
2903
|
-
key: member,
|
|
2904
|
-
owner: `record "${name}" (the \`change\` namespace)`
|
|
2905
|
-
}
|
|
2906
|
-
});
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
for (const key of keys) {
|
|
2910
|
-
if (RESERVED_RECORD_KEYS2.includes(key) || reserved.includes(key) || methods.includes(key)) {
|
|
2911
|
-
throw new ReservedRecordKey2({ source: name, details: { key } });
|
|
2912
|
-
}
|
|
2913
|
-
}
|
|
2914
|
-
const options = Object.freeze({
|
|
2915
|
-
sensitive: Object.freeze(keys.filter((key) => sensitive.includes(key) || isMarked(blueprint.properties[key], "sensitive", { lists: true }))),
|
|
2916
|
-
unique: Object.freeze(keys.filter((key) => unique.includes(key) || isMarked(blueprint.properties[key], "unique"))),
|
|
2917
|
-
change: Object.freeze([...change])
|
|
2918
|
-
});
|
|
2919
|
-
|
|
2920
|
-
class DeclaredRecord extends Base {
|
|
2921
|
-
static [Kind2] = "record";
|
|
2922
|
-
static blueprint = blueprint;
|
|
2923
|
-
static options = options;
|
|
2924
|
-
static plugins = applied.plugins;
|
|
2925
|
-
static [RecordPlugins] = applied.plugins;
|
|
2926
|
-
static [RecordPluginHooks] = applied.hooks;
|
|
2927
|
-
}
|
|
2928
|
-
if (declaredName !== undefined) {
|
|
2929
|
-
declareRecordName(DeclaredRecord, declaredName);
|
|
2930
|
-
}
|
|
2931
|
-
Object.defineProperty(DeclaredRecord, "recordName", {
|
|
2932
|
-
get() {
|
|
2933
|
-
return declaredName ?? this.name;
|
|
2934
|
-
},
|
|
2935
|
-
configurable: true
|
|
2936
|
-
});
|
|
2937
|
-
exposeRecordKeys(DeclaredRecord.prototype, keys);
|
|
2938
|
-
for (const [member, descriptor] of Object.entries(applied.descriptors)) {
|
|
2939
|
-
Object.defineProperty(DeclaredRecord.prototype, member, descriptor);
|
|
2940
|
-
}
|
|
2941
|
-
if (change.length > 0) {
|
|
2942
|
-
Object.defineProperty(DeclaredRecord.prototype, CHANGE_MEMBER, {
|
|
2943
|
-
get() {
|
|
2944
|
-
let namespace = changeNamespaces.get(this);
|
|
2945
|
-
if (namespace === undefined) {
|
|
2946
|
-
namespace = Object.freeze(Object.fromEntries(change.map((key) => [
|
|
2947
|
-
key,
|
|
2948
|
-
(value) => this.set(key, value)
|
|
2949
|
-
])));
|
|
2950
|
-
changeNamespaces.set(this, namespace);
|
|
2951
|
-
}
|
|
2952
|
-
return namespace;
|
|
2953
|
-
},
|
|
2954
|
-
configurable: true
|
|
2955
|
-
});
|
|
2956
|
-
}
|
|
2957
|
-
Object.defineProperty(DeclaredRecord, "name", { value: name });
|
|
2958
|
-
return DeclaredRecord;
|
|
2959
|
-
}
|
|
2960
|
-
var CHANGE_MEMBER = "change";
|
|
2961
|
-
var changeNamespaces = new WeakMap;
|
|
2962
|
-
|
|
2963
|
-
// src/core/entity/exceptions.ts
|
|
2964
|
-
var ReservedEntityKey2 = exceptionOf2({
|
|
2965
|
-
layer: "entity" /* Entity */,
|
|
2966
|
-
name: "ReservedEntityKey",
|
|
2967
|
-
message: ({ key }, source) => `"${key}" is a key or a member of every entity and cannot be a key of the blueprint of "${source}".`
|
|
2968
|
-
});
|
|
2969
|
-
var ImmutableEntityKey2 = exceptionOf2({
|
|
2970
|
-
layer: "entity" /* Entity */,
|
|
2971
|
-
name: "ImmutableEntityKey",
|
|
2972
|
-
message: ({ key }, source) => `"${key}" of entity "${source}" cannot be changed.`
|
|
2973
|
-
});
|
|
2974
|
-
var DeletedEntity2 = exceptionOf2({
|
|
2975
|
-
layer: "entity" /* Entity */,
|
|
2976
|
-
name: "DeletedEntity",
|
|
2977
|
-
message: ({ id }, source) => `Entity "${source}" of id "${id}" was destroyed and cannot change.`
|
|
2978
|
-
});
|
|
2979
|
-
var InvalidEntityExpiry2 = exceptionOf2({
|
|
2980
|
-
layer: "entity" /* Entity */,
|
|
2981
|
-
name: "InvalidEntityExpiry",
|
|
2982
|
-
message: ({ reason }, source) => `Invalid expires of entity "${source}": ${reason}`
|
|
2983
|
-
});
|
|
2984
|
-
var InvalidEntitySchemaVersion2 = exceptionOf2({
|
|
2985
|
-
layer: "entity" /* Entity */,
|
|
2986
|
-
name: "InvalidEntitySchemaVersion",
|
|
2987
|
-
message: ({ reason }, source) => `Invalid schema evolution options of entity "${source}": ${reason}`
|
|
2988
|
-
});
|
|
2989
|
-
|
|
2990
|
-
// src/core/entity/trust.ts
|
|
2991
|
-
var MakesValid = Symbol("makesValid");
|
|
2992
|
-
function vouching(settings, makers) {
|
|
2993
|
-
return Object.defineProperty({ ...settings }, MakesValid, { value: makers });
|
|
2994
|
-
}
|
|
2995
|
-
function validMakersOf(settings) {
|
|
2996
|
-
return settings[MakesValid];
|
|
2997
|
-
}
|
|
2998
|
-
|
|
2999
|
-
// src/core/entity/version.ts
|
|
3000
|
-
import { Type as Type4 } from "typebox";
|
|
3001
|
-
class EntityVersion2 extends propertyOf2({
|
|
3002
|
-
name: "version",
|
|
3003
|
-
schema: Type4.Integer({ minimum: 1 }),
|
|
3004
|
-
default: 1
|
|
3005
|
-
}) {
|
|
3006
|
-
}
|
|
3007
|
-
var VersionIdentity = blueprintBuilderOf2()(() => ({
|
|
3008
|
-
version: EntityVersion2
|
|
3009
|
-
}));
|
|
3010
|
-
|
|
3011
|
-
// src/core/entity/entity.ts
|
|
3012
|
-
function entityBuilderOf2(settings) {
|
|
3013
|
-
const { identity, generateId, now, expiresAt, plugins: catalogs } = settings;
|
|
3014
|
-
const clock = Object.freeze({
|
|
3015
|
-
generateId,
|
|
3016
|
-
now,
|
|
3017
|
-
makesValid: validMakersOf(settings)
|
|
3018
|
-
});
|
|
3019
|
-
const context = pluginContextOf(catalogs ?? []);
|
|
3020
|
-
return (blueprint, options = {}) => {
|
|
3021
|
-
const lifetime = lifetimeOf(blueprint, options);
|
|
3022
|
-
const expiring = lifetime !== undefined;
|
|
3023
|
-
const versioned = options.versioned === true;
|
|
3024
|
-
const added = [
|
|
3025
|
-
...versioned ? [ENTITY_VERSION_KEY] : [],
|
|
3026
|
-
...expiring ? [EXPIRES_AT] : []
|
|
3027
|
-
];
|
|
3028
|
-
if (expiring && expiresAt === undefined) {
|
|
3029
|
-
throw new InvalidEntityExpiry2({
|
|
3030
|
-
source: options.name ?? "entity",
|
|
3031
|
-
details: {
|
|
3032
|
-
reason: "the entity builder has no expiresAt field, which expires: { after } needs."
|
|
3033
|
-
}
|
|
3034
|
-
});
|
|
3035
|
-
}
|
|
3036
|
-
const schemaVersioned = options.schemaVersion !== undefined;
|
|
3037
|
-
checkSchemaOptions(options);
|
|
3038
|
-
if (schemaVersioned)
|
|
3039
|
-
added.push(SCHEMA_VERSION_KEY2);
|
|
3040
|
-
for (const key of Object.keys(blueprint.properties)) {
|
|
3041
|
-
if (RESERVED_ENTITY_KEYS2.includes(key) || added.includes(key)) {
|
|
3042
|
-
throw new ReservedEntityKey2({ source: "entity", details: { key } });
|
|
3043
|
-
}
|
|
3044
|
-
}
|
|
3045
|
-
for (const key of options.change ?? []) {
|
|
3046
|
-
if (ENTITY_IDENTITY_KEYS2.includes(key) || added.includes(key)) {
|
|
3047
|
-
throw new ImmutableEntityKey2({ source: "entity", details: { key } });
|
|
3048
|
-
}
|
|
3049
|
-
}
|
|
3050
|
-
const DeclaredEntity = declareRecord(AbstractEntity, identity.join(...versioned ? [VersionIdentity] : [], ...expiring ? [
|
|
3051
|
-
blueprintFromProperties([], {
|
|
3052
|
-
[EXPIRES_AT]: expiresAt
|
|
3053
|
-
})
|
|
3054
|
-
] : [], blueprint), {
|
|
3055
|
-
...withoutStorage(options),
|
|
3056
|
-
unique: ["id", ...options.unique ?? []]
|
|
3057
|
-
}, "entity", ENTITY_MEMBERS, context);
|
|
3058
|
-
Object.defineProperty(DeclaredEntity, IdentifiedRecord, { value: true });
|
|
3059
|
-
Object.defineProperty(DeclaredEntity, EntityClock, { value: clock });
|
|
3060
|
-
Object.defineProperty(DeclaredEntity, EntityClassBrand, { value: true });
|
|
3061
|
-
Object.defineProperty(DeclaredEntity, EntityUniqueKeys2, {
|
|
3062
|
-
value: DeclaredEntity.options.unique
|
|
3063
|
-
});
|
|
3064
|
-
Object.defineProperty(DeclaredEntity, EntityLifetime, { value: lifetime });
|
|
3065
|
-
Object.defineProperty(DeclaredEntity, EntitySettings2, {
|
|
3066
|
-
value: Object.freeze({
|
|
3067
|
-
versioned,
|
|
3068
|
-
expires: options.expires,
|
|
3069
|
-
schemaVersioned,
|
|
3070
|
-
schemaVersion: options.schemaVersion ?? 1,
|
|
3071
|
-
upgrade: Object.freeze({ ...options.upgrade }),
|
|
3072
|
-
previousNames: Object.freeze([...options.previousNames ?? []])
|
|
3073
|
-
})
|
|
3074
|
-
});
|
|
3075
|
-
Object.defineProperty(DeclaredEntity, EntityEventSettings, {
|
|
3076
|
-
value: Object.freeze({
|
|
3077
|
-
onCreate: options.onCreate,
|
|
3078
|
-
onUpdate: options.onUpdate,
|
|
3079
|
-
onDelete: options.onDelete
|
|
3080
|
-
})
|
|
3081
|
-
});
|
|
3082
|
-
return DeclaredEntity;
|
|
3083
|
-
};
|
|
3084
|
-
}
|
|
3085
|
-
function isEntityClass2(value) {
|
|
3086
|
-
return isRecordClass(value) && value.prototype instanceof AbstractEntity;
|
|
3087
|
-
}
|
|
3088
|
-
function isEntity2(value) {
|
|
3089
|
-
return value instanceof AbstractEntity;
|
|
3090
|
-
}
|
|
3091
|
-
function checkSchemaOptions(options) {
|
|
3092
|
-
const source = options.name ?? "entity";
|
|
3093
|
-
const fail = (reason) => {
|
|
3094
|
-
throw new InvalidEntitySchemaVersion2({ source, details: { reason } });
|
|
3095
|
-
};
|
|
3096
|
-
const { schemaVersion = 1, upgrade, previousNames } = options;
|
|
3097
|
-
if (!Number.isSafeInteger(schemaVersion) || schemaVersion < 1) {
|
|
3098
|
-
fail("expected schemaVersion to be a positive integer.");
|
|
3099
|
-
}
|
|
3100
|
-
if (upgrade !== undefined) {
|
|
3101
|
-
if (typeof upgrade !== "object" || upgrade === null) {
|
|
3102
|
-
fail("expected upgrade to be an object of steps by version.");
|
|
3103
|
-
}
|
|
3104
|
-
for (const [key, step] of Object.entries(upgrade)) {
|
|
3105
|
-
const version = Number(key);
|
|
3106
|
-
if (!Number.isSafeInteger(version) || version < 2 || version > schemaVersion) {
|
|
3107
|
-
fail(`the upgrade step "${key}" must reach a version from 2 to the schemaVersion (${schemaVersion}).`);
|
|
3108
|
-
}
|
|
3109
|
-
if (typeof step !== "function") {
|
|
3110
|
-
fail(`the upgrade step ${key} is not a function.`);
|
|
3111
|
-
}
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
if (previousNames !== undefined) {
|
|
3115
|
-
if (!Array.isArray(previousNames)) {
|
|
3116
|
-
fail("expected previousNames to be a list of names.");
|
|
3117
|
-
}
|
|
3118
|
-
for (const previous of previousNames) {
|
|
3119
|
-
if (!isRecordName(previous) || previous === options.name) {
|
|
3120
|
-
fail(`"${String(previous)}" cannot be a previous name: expected an identifier other than the name of the entity.`);
|
|
3121
|
-
}
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
|
-
}
|
|
3125
|
-
function withoutStorage(options) {
|
|
3126
|
-
const {
|
|
3127
|
-
versioned: _versioned,
|
|
3128
|
-
expires: _expires,
|
|
3129
|
-
schemaVersion: _schemaVersion,
|
|
3130
|
-
upgrade: _upgrade,
|
|
3131
|
-
previousNames: _previousNames,
|
|
3132
|
-
...rest
|
|
3133
|
-
} = options;
|
|
3134
|
-
return rest;
|
|
3135
|
-
}
|
|
3136
|
-
var DURATION_UNITS = {
|
|
3137
|
-
days: 86400000,
|
|
3138
|
-
hours: 3600000,
|
|
3139
|
-
minutes: 60000,
|
|
3140
|
-
seconds: 1000
|
|
3141
|
-
};
|
|
3142
|
-
function isDateField(field) {
|
|
3143
|
-
if (!isProperty(field))
|
|
3144
|
-
return false;
|
|
3145
|
-
const schema = field.type.schema.type.Type();
|
|
3146
|
-
return schema.type === "string" && (schema.format === "date-time" || schema.format === "date");
|
|
3147
|
-
}
|
|
3148
|
-
function lifetimeOf(blueprint, options) {
|
|
3149
|
-
const { expires } = options;
|
|
3150
|
-
if (expires === undefined)
|
|
3151
|
-
return;
|
|
3152
|
-
const fail = (reason) => {
|
|
3153
|
-
throw new InvalidEntityExpiry2({
|
|
3154
|
-
source: options.name ?? "entity",
|
|
3155
|
-
details: { reason }
|
|
3156
|
-
});
|
|
3157
|
-
};
|
|
3158
|
-
const plain = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3159
|
-
if (!plain(expires) || Object.keys(expires).length !== 1)
|
|
3160
|
-
return fail("expected { after: duration } or { at: key }.");
|
|
3161
|
-
if ("at" in expires) {
|
|
3162
|
-
const { at } = expires;
|
|
3163
|
-
if (typeof at !== "string" || !Object.hasOwn(blueprint.properties, at))
|
|
3164
|
-
return fail(`"${String(at)}" is not a key of the blueprint.`);
|
|
3165
|
-
if (!isDateField(blueprint.properties[at]))
|
|
3166
|
-
return fail(`"${at}" does not hold a date.`);
|
|
3167
|
-
return;
|
|
3168
|
-
}
|
|
3169
|
-
if (!("after" in expires)) {
|
|
3170
|
-
return fail("expected { after: duration } or { at: key }.");
|
|
3171
|
-
}
|
|
3172
|
-
const { after } = expires;
|
|
3173
|
-
if (!plain(after) || Object.keys(after).length === 0)
|
|
3174
|
-
return fail("after must be a non-empty duration, e.g. { days: 400 }.");
|
|
3175
|
-
let total = 0;
|
|
3176
|
-
for (const [unit, amount] of Object.entries(after)) {
|
|
3177
|
-
if (!Object.hasOwn(DURATION_UNITS, unit))
|
|
3178
|
-
return fail(`"${unit}" is not a unit of a duration (days, hours, minutes, seconds).`);
|
|
3179
|
-
if (typeof amount !== "number" || !Number.isFinite(amount) || amount <= 0)
|
|
3180
|
-
return fail(`${unit} must be a positive finite number.`);
|
|
3181
|
-
total += amount * DURATION_UNITS[unit];
|
|
3182
|
-
}
|
|
3183
|
-
return total;
|
|
3184
|
-
}
|
|
3185
|
-
|
|
3186
|
-
// src/core/entity/event.ts
|
|
3187
|
-
var EntityClassBrand = Symbol("entityClass");
|
|
3188
|
-
var EventBrand = Symbol("event");
|
|
3189
|
-
var EntityEventSettings = Symbol("entityEvents");
|
|
3190
|
-
var definitions = new WeakMap;
|
|
3191
|
-
var queues = new WeakMap;
|
|
3192
|
-
var withHandler = new WeakSet;
|
|
3193
|
-
function eventOf2(name, entityClass, handler) {
|
|
3194
|
-
if (!isEntityClass2(entityClass)) {
|
|
3195
|
-
throw new TypeError("An event requires an entity class");
|
|
3196
|
-
}
|
|
3197
|
-
if (handler !== undefined && typeof handler !== "function") {
|
|
3198
|
-
throw new TypeError(`The handler of event ${name} must be a function`);
|
|
3199
|
-
}
|
|
3200
|
-
const event = Object.freeze({
|
|
3201
|
-
name,
|
|
3202
|
-
[EventBrand]: true
|
|
3203
|
-
});
|
|
3204
|
-
if (handler)
|
|
3205
|
-
withHandler.add(event);
|
|
3206
|
-
definitions.set(event, (entity) => {
|
|
3207
|
-
if (!(entity instanceof entityClass)) {
|
|
3208
|
-
throw new TypeError(`Incompatible entity for event ${name}`);
|
|
3209
|
-
}
|
|
3210
|
-
return Object.freeze({
|
|
3211
|
-
name,
|
|
3212
|
-
entity,
|
|
3213
|
-
async handle(context) {
|
|
3214
|
-
if (!handler)
|
|
3215
|
-
return;
|
|
3216
|
-
await handler(entity, {
|
|
3217
|
-
logger: context?.logger ?? resolveLogger(undefined, undefined) ?? silentLogger
|
|
3218
|
-
});
|
|
3219
|
-
}
|
|
3220
|
-
});
|
|
3221
|
-
});
|
|
3222
|
-
return event;
|
|
3223
|
-
}
|
|
3224
|
-
function eventHasHandler(event) {
|
|
3225
|
-
return withHandler.has(event);
|
|
3226
|
-
}
|
|
3227
|
-
function lifecycleEventsOf(entityClass) {
|
|
3228
|
-
const settings = entityClass[EntityEventSettings];
|
|
3229
|
-
const found = {};
|
|
3230
|
-
for (const cycle of ["onCreate", "onUpdate", "onDelete"]) {
|
|
3231
|
-
const reference = settings?.[cycle];
|
|
3232
|
-
if (reference === undefined)
|
|
3233
|
-
continue;
|
|
3234
|
-
const events = typeof reference === "function" ? reference() : reference;
|
|
3235
|
-
const list = Array.isArray(events) ? events : [events];
|
|
3236
|
-
if (list.length > 0)
|
|
3237
|
-
found[cycle] = list;
|
|
3238
|
-
}
|
|
3239
|
-
return found;
|
|
3240
|
-
}
|
|
3241
|
-
function enqueueEvent(entity, event) {
|
|
3242
|
-
const bind = definitions.get(event);
|
|
3243
|
-
if (!bind)
|
|
3244
|
-
throw new TypeError("Expected an eventOf definition");
|
|
3245
|
-
const occurrence = bind(entity);
|
|
3246
|
-
const queue = queues.get(entity) ?? [];
|
|
3247
|
-
queue.push(occurrence);
|
|
3248
|
-
queues.set(entity, queue);
|
|
3249
|
-
}
|
|
3250
|
-
function pullEntityEvents(entity) {
|
|
3251
|
-
const queue = queues.get(entity) ?? [];
|
|
3252
|
-
queues.delete(entity);
|
|
3253
|
-
return queue;
|
|
3254
|
-
}
|
|
3255
|
-
function enqueueLifecycle(entity, cycle) {
|
|
3256
|
-
const settings = entity.constructor[EntityEventSettings];
|
|
3257
|
-
const reference = settings?.[cycle];
|
|
3258
|
-
if (reference === undefined)
|
|
3259
|
-
return;
|
|
3260
|
-
const events = typeof reference === "function" ? reference() : reference;
|
|
3261
|
-
for (const event of Array.isArray(events) ? events : [events]) {
|
|
3262
|
-
enqueueEvent(entity, event);
|
|
3263
|
-
}
|
|
3264
|
-
}
|
|
3265
|
-
|
|
3266
|
-
// src/core/entity/abstract-entity.ts
|
|
3267
|
-
var ENTITY_IDENTITY_KEYS2 = Object.freeze(["id", "createdAt", "updatedAt", "deletedAt"]);
|
|
3268
|
-
var ENTITY_MEMBERS = Object.freeze([
|
|
3269
|
-
"destroy",
|
|
3270
|
-
"isDeleted",
|
|
3271
|
-
"equals",
|
|
3272
|
-
"onDestroy",
|
|
3273
|
-
"emit",
|
|
3274
|
-
"pullEvents"
|
|
3275
|
-
]);
|
|
3276
|
-
var RESERVED_ENTITY_KEYS2 = Object.freeze([
|
|
3277
|
-
...ENTITY_IDENTITY_KEYS2,
|
|
3278
|
-
...ENTITY_MEMBERS
|
|
3279
|
-
]);
|
|
3280
|
-
var EntityClock = Symbol("entityClock");
|
|
3281
|
-
var EntityUniqueKeys2 = Symbol("entityUniqueKeys");
|
|
3282
|
-
var EntitySettings2 = Symbol("entitySettings");
|
|
3283
|
-
var EntityLifetime = Symbol("entityLifetime");
|
|
3284
|
-
var EXPIRES_AT = "expiresAt";
|
|
3285
|
-
var ENTITY_VERSION_KEY = "version";
|
|
3286
|
-
var SCHEMA_VERSION_KEY2 = "$v";
|
|
3287
|
-
function isVersionedEntityClass(entityClass) {
|
|
3288
|
-
if (typeof entityClass !== "function")
|
|
3289
|
-
return false;
|
|
3290
|
-
return entityClass[EntitySettings2]?.versioned === true;
|
|
3291
|
-
}
|
|
3292
|
-
function identityKeysOf(entityClass) {
|
|
3293
|
-
const keys = [...ENTITY_IDENTITY_KEYS2];
|
|
3294
|
-
if (isVersionedEntityClass(entityClass))
|
|
3295
|
-
keys.push(ENTITY_VERSION_KEY);
|
|
3296
|
-
if (typeof entityClass === "function" && entityClass[EntityLifetime] !== undefined) {
|
|
3297
|
-
keys.push(EXPIRES_AT);
|
|
3298
|
-
}
|
|
3299
|
-
return keys;
|
|
3300
|
-
}
|
|
3301
|
-
function isIdentityKey(Entity, key) {
|
|
3302
|
-
return identityKeysOf(Entity).includes(key);
|
|
3303
|
-
}
|
|
3304
|
-
function storeEntityVersion(entity, version) {
|
|
3305
|
-
storeRecordValue(entity, ENTITY_VERSION_KEY, version);
|
|
3306
|
-
}
|
|
3307
|
-
var ID_MADE = Object.freeze(["id"]);
|
|
3308
|
-
var CREATED_AT_MADE = Object.freeze(["createdAt"]);
|
|
3309
|
-
var BOTH_MADE = Object.freeze(["id", "createdAt"]);
|
|
3310
|
-
function identityOf(entity) {
|
|
3311
|
-
return entity;
|
|
3312
|
-
}
|
|
3313
|
-
function clockOf(entity) {
|
|
3314
|
-
return entity.constructor[EntityClock];
|
|
3315
|
-
}
|
|
3316
|
-
function assertAlive(entity) {
|
|
3317
|
-
if (entity.isDeleted) {
|
|
3318
|
-
throw new DeletedEntity2({
|
|
3319
|
-
source: recordNameOf2(entity.constructor),
|
|
3320
|
-
details: { id: identityOf(entity).id }
|
|
3321
|
-
});
|
|
3322
|
-
}
|
|
3323
|
-
}
|
|
3324
|
-
function withIdentity(value, clock, lifetime, versioned) {
|
|
3325
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3326
|
-
return value;
|
|
3327
|
-
}
|
|
3328
|
-
const { id, createdAt, expiresAt, version } = value;
|
|
3329
|
-
const expiring = lifetime !== undefined && expiresAt === undefined;
|
|
3330
|
-
const unversioned = versioned && version === undefined;
|
|
3331
|
-
if (id !== undefined && createdAt !== undefined && !expiring && !unversioned)
|
|
3332
|
-
return value;
|
|
3333
|
-
const created = createdAt === undefined ? clock.now() : createdAt;
|
|
3334
|
-
const identity = {
|
|
3335
|
-
id: undefined,
|
|
3336
|
-
createdAt: undefined,
|
|
3337
|
-
...value
|
|
3338
|
-
};
|
|
3339
|
-
identity.id = id === undefined ? clock.generateId() : id;
|
|
3340
|
-
identity.createdAt = created;
|
|
3341
|
-
const { makesValid } = clock;
|
|
3342
|
-
if (makesValid !== undefined) {
|
|
3343
|
-
const idMade = id === undefined && makesValid.id();
|
|
3344
|
-
const createdAtMade = createdAt === undefined && makesValid.createdAt();
|
|
3345
|
-
if (idMade && createdAtMade)
|
|
3346
|
-
vouchFor(BOTH_MADE);
|
|
3347
|
-
else if (idMade)
|
|
3348
|
-
vouchFor(ID_MADE);
|
|
3349
|
-
else if (createdAtMade)
|
|
3350
|
-
vouchFor(CREATED_AT_MADE);
|
|
3351
|
-
}
|
|
3352
|
-
if (unversioned)
|
|
3353
|
-
identity[ENTITY_VERSION_KEY] = 1;
|
|
3354
|
-
if (expiring) {
|
|
3355
|
-
const start = typeof created === "string" ? Date.parse(created) : NaN;
|
|
3356
|
-
if (!Number.isNaN(start)) {
|
|
3357
|
-
identity[EXPIRES_AT] = new Date(start + lifetime).toISOString();
|
|
3358
|
-
}
|
|
3359
|
-
}
|
|
3360
|
-
return identity;
|
|
3361
|
-
}
|
|
3362
|
-
|
|
3363
|
-
class AbstractEntity extends AbstractRecord {
|
|
3364
|
-
constructor(value) {
|
|
3365
|
-
super(withIdentity(value, new.target[EntityClock], new.target[EntityLifetime], isVersionedEntityClass(new.target)));
|
|
3366
|
-
const input = value;
|
|
3367
|
-
if (input.id === undefined && input.createdAt === undefined) {
|
|
3368
|
-
enqueueLifecycle(this, "onCreate");
|
|
3369
|
-
}
|
|
3370
|
-
}
|
|
3371
|
-
emit(event) {
|
|
3372
|
-
enqueueEvent(this, event);
|
|
3373
|
-
}
|
|
3374
|
-
pullEvents() {
|
|
3375
|
-
return pullEntityEvents(this);
|
|
3376
|
-
}
|
|
3377
|
-
get isDeleted() {
|
|
3378
|
-
return identityOf(this).deletedAt !== undefined;
|
|
3379
|
-
}
|
|
3380
|
-
equals(other) {
|
|
3381
|
-
return other instanceof AbstractEntity && other[Meta2].blueprint === this[Meta2].blueprint && identityOf(other).id === identityOf(this).id;
|
|
3382
|
-
}
|
|
3383
|
-
destroy() {
|
|
3384
|
-
assertAlive(this);
|
|
3385
|
-
storeRecordValue(this, "deletedAt", clockOf(this).now());
|
|
3386
|
-
enqueueLifecycle(this, "onDelete");
|
|
3387
|
-
this.onDestroy();
|
|
3388
|
-
return this;
|
|
3389
|
-
}
|
|
3390
|
-
set(key, value) {
|
|
3391
|
-
const name = String(key);
|
|
3392
|
-
if (isIdentityKey(this.constructor, name)) {
|
|
3393
|
-
throw new ImmutableEntityKey2({
|
|
3394
|
-
source: recordNameOf2(this.constructor),
|
|
3395
|
-
details: { key: name }
|
|
3396
|
-
});
|
|
3397
|
-
}
|
|
3398
|
-
assertAlive(this);
|
|
3399
|
-
const { next, previous } = storeRecordValue(this, name, value);
|
|
3400
|
-
storeRecordValue(this, "updatedAt", clockOf(this).now());
|
|
3401
|
-
enqueueLifecycle(this, "onUpdate");
|
|
3402
|
-
return runRecordEffects(this, key, next, previous);
|
|
3403
|
-
}
|
|
3404
|
-
onDestroy() {}
|
|
3405
|
-
}
|
|
3406
|
-
|
|
3407
|
-
// src/core/repository/exceptions.ts
|
|
3408
|
-
var InvalidRepositoryQuery2 = exceptionOf2({
|
|
3409
|
-
layer: "repository" /* Repository */,
|
|
3410
|
-
name: "InvalidRepositoryQuery",
|
|
3411
|
-
message: ({ reason }) => reason
|
|
3412
|
-
});
|
|
3413
|
-
var InvalidRepositoryCursor2 = exceptionOf2({
|
|
3414
|
-
layer: "repository" /* Repository */,
|
|
3415
|
-
name: "InvalidRepositoryCursor",
|
|
3416
|
-
message: ({
|
|
3417
|
-
reason
|
|
3418
|
-
}) => reason
|
|
3419
|
-
});
|
|
3420
|
-
var InvalidRepositoryDeclaration2 = exceptionOf2({
|
|
3421
|
-
layer: "repository" /* Repository */,
|
|
3422
|
-
name: "InvalidRepositoryDeclaration",
|
|
3423
|
-
message: ({ reason }) => reason
|
|
3424
|
-
});
|
|
3425
|
-
var InvalidRepositoryEntity2 = exceptionOf2({
|
|
3426
|
-
layer: "repository" /* Repository */,
|
|
3427
|
-
name: "InvalidRepositoryEntity",
|
|
3428
|
-
message: (_details, source) => `"${source}" expected an entity of its own class.`
|
|
3429
|
-
});
|
|
3430
|
-
var InvalidStoredSchemaVersion2 = exceptionOf2({
|
|
3431
|
-
layer: "repository" /* Repository */,
|
|
3432
|
-
name: "InvalidStoredSchemaVersion",
|
|
3433
|
-
message: ({
|
|
3434
|
-
id,
|
|
3435
|
-
stored,
|
|
3436
|
-
current,
|
|
3437
|
-
reason
|
|
3438
|
-
}, source) => reason ?? `"${source}" read the row "${id}" stored at schema version ${JSON.stringify(stored)}, and its entity is at version ${current}.`
|
|
3439
|
-
});
|
|
3440
|
-
var InvalidRepositoryData2 = exceptionOf2({
|
|
3441
|
-
layer: "repository" /* Repository */,
|
|
3442
|
-
name: "InvalidRepositoryData",
|
|
3443
|
-
message: (_details, source) => `"${source}" read a value that its entity rejects.`
|
|
3444
|
-
});
|
|
3445
|
-
var RepositoryUniqueViolation2 = exceptionOf2({
|
|
3446
|
-
layer: "repository" /* Repository */,
|
|
3447
|
-
name: "RepositoryUniqueViolation",
|
|
3448
|
-
message: ({ key }, source) => `"${source}" already holds an entity with this "${key}".`
|
|
3449
|
-
});
|
|
3450
|
-
var RepositoryUsedOutsideApplication2 = exceptionOf2({
|
|
3451
|
-
layer: "repository" /* Repository */,
|
|
3452
|
-
name: "RepositoryUsedOutsideApplication",
|
|
3453
|
-
message: ({
|
|
3454
|
-
application,
|
|
3455
|
-
repository
|
|
3456
|
-
}, source) => `"${source}" is bound to the application "${application}", and its declaration no longer reads or writes: use app.repositories.${repository}, run its use cases with app.run, or give the repository of the application to execute.`
|
|
3457
|
-
});
|
|
3458
|
-
var RepositoryEntityNotFound2 = exceptionOf2({
|
|
3459
|
-
layer: "repository" /* Repository */,
|
|
3460
|
-
name: "RepositoryEntityNotFound",
|
|
3461
|
-
message: ({ id }, source) => `"${source}" holds no entity of id "${id}".`
|
|
3462
|
-
});
|
|
3463
|
-
var RepositoryConcurrencyConflict2 = exceptionOf2({
|
|
3464
|
-
layer: "repository" /* Repository */,
|
|
3465
|
-
name: "RepositoryConcurrencyConflict",
|
|
3466
|
-
message: ({
|
|
3467
|
-
id,
|
|
3468
|
-
expected
|
|
3469
|
-
}, source) => `"${source}" holds another version of "${id}" than ${expected}: it changed since it was read.`
|
|
3470
|
-
});
|
|
3471
|
-
var InvalidRepositoryIncrement2 = exceptionOf2({
|
|
3472
|
-
layer: "repository" /* Repository */,
|
|
3473
|
-
name: "InvalidRepositoryIncrement",
|
|
3474
|
-
message: ({
|
|
3475
|
-
reason
|
|
3476
|
-
}) => reason
|
|
3477
|
-
});
|
|
3478
|
-
|
|
3479
|
-
// src/core/json.ts
|
|
3480
|
-
function frozenJson(value, subject, fail, seen = new Set) {
|
|
3481
|
-
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
3482
|
-
return value;
|
|
3483
|
-
if (typeof value === "number" && Number.isFinite(value))
|
|
3484
|
-
return value;
|
|
3485
|
-
if (typeof value !== "object" || value === null || seen.has(value))
|
|
3486
|
-
return fail(`${subject} must be finite, acyclic JSON values.`);
|
|
3487
|
-
if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
|
|
3488
|
-
return fail(`${subject} must contain only plain objects and arrays.`);
|
|
3489
|
-
if (Object.getOwnPropertySymbols(value).length > 0)
|
|
3490
|
-
return fail(`${subject} cannot contain symbol keys.`);
|
|
3491
|
-
seen.add(value);
|
|
3492
|
-
const result = Array.isArray(value) ? value.map((item) => frozenJson(item, subject, fail, seen)) : Object.fromEntries(Object.entries(value).map(([key, item]) => [
|
|
3493
|
-
key,
|
|
3494
|
-
frozenJson(item, subject, fail, seen)
|
|
3495
|
-
]));
|
|
3496
|
-
seen.delete(value);
|
|
3497
|
-
return Object.freeze(result);
|
|
3498
|
-
}
|
|
3499
|
-
|
|
3500
|
-
// src/core/repository/state.ts
|
|
3501
|
-
var states = new WeakMap;
|
|
3502
|
-
function findState(repository) {
|
|
3503
|
-
if (typeof repository !== "object" || repository === null)
|
|
3504
|
-
return;
|
|
3505
|
-
for (let Class = repository.constructor;typeof Class === "function"; Class = Object.getPrototypeOf(Class)) {
|
|
3506
|
-
const state = states.get(Class);
|
|
3507
|
-
if (state)
|
|
3508
|
-
return state;
|
|
3509
|
-
}
|
|
3510
|
-
return;
|
|
3511
|
-
}
|
|
3512
|
-
function stateOf(repository) {
|
|
3513
|
-
const state = findState(repository);
|
|
3514
|
-
if (!state)
|
|
3515
|
-
throw new TypeError("Expected a repository made by repositoryOf");
|
|
3516
|
-
return state;
|
|
3517
|
-
}
|
|
3518
|
-
function expiryKeyOf(entity) {
|
|
3519
|
-
const expires = entity[EntitySettings2]?.expires;
|
|
3520
|
-
if (expires === undefined)
|
|
3521
|
-
return;
|
|
3522
|
-
return "at" in expires ? expires.at : EXPIRES_AT;
|
|
3523
|
-
}
|
|
3524
|
-
function schemaOf2(entity) {
|
|
3525
|
-
const settings = entity[EntitySettings2];
|
|
3526
|
-
if (!settings?.schemaVersioned)
|
|
3527
|
-
return;
|
|
3528
|
-
return Object.freeze({
|
|
3529
|
-
version: settings.schemaVersion,
|
|
3530
|
-
key: SCHEMA_VERSION_KEY2,
|
|
3531
|
-
previousNames: settings.previousNames
|
|
3532
|
-
});
|
|
3533
|
-
}
|
|
3534
|
-
function contextOf(state) {
|
|
3535
|
-
if (state.context)
|
|
3536
|
-
return state.context;
|
|
3537
|
-
const key = expiryKeyOf(state.entity);
|
|
3538
|
-
const schema = schemaOf2(state.entity);
|
|
3539
|
-
state.context = Object.freeze({
|
|
3540
|
-
entity: state.entity,
|
|
3541
|
-
name: state.name,
|
|
3542
|
-
unique: state.entity[EntityUniqueKeys2],
|
|
3543
|
-
indexes: state.indexes,
|
|
3544
|
-
...key === undefined ? {} : { expiry: Object.freeze({ key }) },
|
|
3545
|
-
...schema === undefined ? {} : { schema },
|
|
3546
|
-
env: loadEnvironments(state.environment)
|
|
3547
|
-
});
|
|
3548
|
-
return state.context;
|
|
3549
|
-
}
|
|
3550
|
-
function inspectRepository(repository) {
|
|
3551
|
-
const state = findState(repository);
|
|
3552
|
-
if (!state)
|
|
3553
|
-
return;
|
|
3554
|
-
const { environment } = state;
|
|
3555
|
-
return {
|
|
3556
|
-
entity: state.entity,
|
|
3557
|
-
actions: state.actions,
|
|
3558
|
-
deletion: state.deletion,
|
|
3559
|
-
indexes: state.indexes,
|
|
3560
|
-
scans: state.scans,
|
|
3561
|
-
explicitProvider: state.explicitProvider,
|
|
3562
|
-
provider: state.explicitProvider ? state.provider : undefined,
|
|
3563
|
-
environments: environment === undefined ? [] : Array.isArray(environment) ? environment : [environment],
|
|
3564
|
-
relations: [...state.relations.values()].map(declarationOf),
|
|
3565
|
-
state: declarationOf(state)
|
|
3566
|
-
};
|
|
3567
|
-
}
|
|
3568
|
-
var origins = new WeakMap;
|
|
3569
|
-
function declarationOf(state) {
|
|
3570
|
-
return origins.get(state) ?? state;
|
|
3571
|
-
}
|
|
3572
|
-
var declared2 = new WeakMap;
|
|
3573
|
-
function declareRepository(state, repository) {
|
|
3574
|
-
declared2.set(state, repository);
|
|
3575
|
-
}
|
|
3576
|
-
function relatedRepositoryOf(repository, Entity) {
|
|
3577
|
-
const related = findState(repository)?.relations.get(Entity);
|
|
3578
|
-
return related ? declared2.get(declarationOf(related)) : undefined;
|
|
3579
|
-
}
|
|
3580
|
-
function bindState(state, provider, instances, logger, bound = new Map) {
|
|
3581
|
-
const done = bound.get(state);
|
|
3582
|
-
if (done)
|
|
3583
|
-
return done;
|
|
3584
|
-
const copy = {
|
|
3585
|
-
...state,
|
|
3586
|
-
logger,
|
|
3587
|
-
provider: state.explicitProvider ? instances?.get(state.provider) ?? state.provider : provider ?? state.provider,
|
|
3588
|
-
context: undefined,
|
|
3589
|
-
relations: new Map([...state.relations].map(([target, related]) => [
|
|
3590
|
-
target,
|
|
3591
|
-
bindState(related, provider, instances, logger, bound)
|
|
3592
|
-
]))
|
|
3593
|
-
};
|
|
3594
|
-
origins.set(copy, declarationOf(state));
|
|
3595
|
-
bound.set(state, copy);
|
|
3596
|
-
return copy;
|
|
3597
|
-
}
|
|
3598
|
-
var owners = new WeakMap;
|
|
3599
|
-
function assertUnbound(state) {
|
|
3600
|
-
const owner = owners.get(state);
|
|
3601
|
-
if (owner) {
|
|
3602
|
-
throw new RepositoryUsedOutsideApplication2({
|
|
3603
|
-
source: state.name,
|
|
3604
|
-
details: owner
|
|
3605
|
-
});
|
|
3606
|
-
}
|
|
3607
|
-
}
|
|
3608
|
-
function bindRepository(repository, provider, instances, binding) {
|
|
3609
|
-
const state = stateOf(repository);
|
|
3610
|
-
const Declared = repository.constructor;
|
|
3611
|
-
|
|
3612
|
-
class Bound extends Declared {
|
|
3613
|
-
}
|
|
3614
|
-
Object.defineProperty(Bound, "name", { value: Declared.name });
|
|
3615
|
-
states.set(Bound, bindState(state, provider, instances, binding?.logger));
|
|
3616
|
-
if (binding) {
|
|
3617
|
-
owners.set(declarationOf(state), {
|
|
3618
|
-
application: binding.application,
|
|
3619
|
-
repository: binding.key
|
|
3620
|
-
});
|
|
3621
|
-
}
|
|
3622
|
-
return Object.freeze(new Bound);
|
|
3623
|
-
}
|
|
3624
|
-
function providerOfRepository(repository) {
|
|
3625
|
-
return findState(repository)?.provider;
|
|
3626
|
-
}
|
|
3627
|
-
|
|
3628
|
-
// src/core/openapi/exceptions.ts
|
|
3629
|
-
var InvalidOpenAPIModel2 = exceptionOf2({
|
|
3630
|
-
layer: "output" /* Output */,
|
|
3631
|
-
name: "InvalidOpenAPIModel",
|
|
3632
|
-
message: ({ name }) => `"${name}" is not a property, blueprint, list, record or entity.`
|
|
3633
|
-
});
|
|
3634
|
-
|
|
3635
|
-
// src/core/openapi/openapi.ts
|
|
3636
|
-
var NO_MARKS = { writeOnly: [], readOnly: [] };
|
|
3637
|
-
function isField(value) {
|
|
3638
|
-
return isProperty(value) || isBlueprint(value) || isBlueprintList(value) || isBlueprintVariant(value) || recordFieldOf(value) !== undefined;
|
|
3639
|
-
}
|
|
3640
|
-
function isOptional(field) {
|
|
3641
|
-
if (isProperty(field))
|
|
3642
|
-
return field.type.optional === true;
|
|
3643
|
-
if (isBlueprint(field) || isBlueprintList(field) || isBlueprintVariant(field)) {
|
|
3644
|
-
return field.optional;
|
|
3645
|
-
}
|
|
3646
|
-
return recordFieldOf(field)?.optional ?? false;
|
|
3647
|
-
}
|
|
3648
|
-
function plainOf(value, nested = false) {
|
|
3649
|
-
if (Array.isArray(value))
|
|
3650
|
-
return value.map((item) => plainOf(item, true));
|
|
3651
|
-
if (typeof value !== "object" || value === null)
|
|
3652
|
-
return value;
|
|
3653
|
-
const id = value.$id;
|
|
3654
|
-
if (nested && typeof id === "string")
|
|
3655
|
-
return { $ref: id };
|
|
3656
|
-
const plain = {};
|
|
3657
|
-
for (const [key, item] of Object.entries(value)) {
|
|
3658
|
-
if (!key.startsWith("~"))
|
|
3659
|
-
plain[key] = plainOf(item, true);
|
|
3660
|
-
}
|
|
3661
|
-
return plain;
|
|
3662
|
-
}
|
|
3663
|
-
function objectOf(properties, scope, marks) {
|
|
3664
|
-
const shape = {};
|
|
3665
|
-
const required = [];
|
|
3666
|
-
for (const [key, field] of Object.entries(properties)) {
|
|
3667
|
-
const schema = schemaOf3(field, scope);
|
|
3668
|
-
if (marks.readOnly.includes(key))
|
|
3669
|
-
schema.readOnly = true;
|
|
3670
|
-
if (marks.writeOnly.includes(key))
|
|
3671
|
-
schema.writeOnly = true;
|
|
3672
|
-
shape[key] = schema;
|
|
3673
|
-
if (!isOptional(field))
|
|
3674
|
-
required.push(key);
|
|
3675
|
-
}
|
|
3676
|
-
return {
|
|
3677
|
-
type: "object",
|
|
3678
|
-
properties: shape,
|
|
3679
|
-
...required.length > 0 ? { required } : {},
|
|
3680
|
-
additionalProperties: false
|
|
3681
|
-
};
|
|
3682
|
-
}
|
|
3683
|
-
function recordSchemaOf(record, scope) {
|
|
3684
|
-
const { sensitive = [] } = record.options ?? {};
|
|
3685
|
-
return objectOf(record.blueprint.properties, scope, {
|
|
3686
|
-
writeOnly: sensitive,
|
|
3687
|
-
readOnly: isEntityClass2(record) ? identityKeysOf(record) : []
|
|
3688
|
-
});
|
|
3689
|
-
}
|
|
3690
|
-
function schemaOf3(field, scope) {
|
|
3691
|
-
if (isBlueprintList(field)) {
|
|
3692
|
-
const { item, minItems, maxItems } = field;
|
|
3693
|
-
return {
|
|
3694
|
-
type: "array",
|
|
3695
|
-
items: schemaOf3(item, scope),
|
|
3696
|
-
...minItems === undefined ? {} : { minItems },
|
|
3697
|
-
...maxItems === undefined ? {} : { maxItems }
|
|
3698
|
-
};
|
|
3699
|
-
}
|
|
3700
|
-
if (isBlueprint(field))
|
|
3701
|
-
return objectOf(field.properties, scope, NO_MARKS);
|
|
3702
|
-
if (isBlueprintVariant(field)) {
|
|
3703
|
-
const variants = field.variants;
|
|
3704
|
-
return {
|
|
3705
|
-
oneOf: Object.entries(variants).map(([tag, variant]) => {
|
|
3706
|
-
const object = isRecordClass(variant) ? recordSchemaOf(variant, scope) : objectOf(variant.properties, scope, NO_MARKS);
|
|
3707
|
-
return {
|
|
3708
|
-
...object,
|
|
3709
|
-
properties: { [field.key]: { const: tag }, ...object.properties },
|
|
3710
|
-
required: [field.key, ...object.required ?? []]
|
|
3711
|
-
};
|
|
3712
|
-
}),
|
|
3713
|
-
discriminator: { propertyName: field.key }
|
|
3714
|
-
};
|
|
3715
|
-
}
|
|
3716
|
-
const record = recordFieldOf(field);
|
|
3717
|
-
if (record) {
|
|
3718
|
-
const name = scope.names.get(record.record);
|
|
3719
|
-
return name === undefined ? recordSchemaOf(record.record, scope) : { $ref: `${scope.prefix}${name}` };
|
|
3720
|
-
}
|
|
3721
|
-
if (!isProperty(field)) {
|
|
3722
|
-
throw new InvalidOpenAPIModel2({
|
|
3723
|
-
source: "openapi",
|
|
3724
|
-
details: { name: String(field) }
|
|
3725
|
-
});
|
|
3726
|
-
}
|
|
3727
|
-
const schema = plainOf(field.type.schema.type.Type());
|
|
3728
|
-
if (field.type.sensitive)
|
|
3729
|
-
schema.writeOnly = true;
|
|
3730
|
-
return schema;
|
|
3731
|
-
}
|
|
3732
|
-
function toOpenAPI2(modelOrModels, { refPrefix = "#/components/schemas/" } = {}) {
|
|
3733
|
-
if (isField(modelOrModels)) {
|
|
3734
|
-
return schemaOf3(modelOrModels, { names: new Map, prefix: refPrefix });
|
|
3735
|
-
}
|
|
3736
|
-
if (typeof modelOrModels !== "object" || modelOrModels === null) {
|
|
3737
|
-
throw new InvalidOpenAPIModel2({
|
|
3738
|
-
source: "openapi",
|
|
3739
|
-
details: { name: String(modelOrModels) }
|
|
3740
|
-
});
|
|
3741
|
-
}
|
|
3742
|
-
const names = new Map;
|
|
3743
|
-
for (const [name, model] of Object.entries(modelOrModels)) {
|
|
3744
|
-
if (!isField(model)) {
|
|
3745
|
-
throw new InvalidOpenAPIModel2({ source: "openapi", details: { name } });
|
|
3746
|
-
}
|
|
3747
|
-
const record = recordFieldOf(model);
|
|
3748
|
-
if (record && !names.has(record.record))
|
|
3749
|
-
names.set(record.record, name);
|
|
3750
|
-
}
|
|
3751
|
-
const scope = { names, prefix: refPrefix };
|
|
3752
|
-
const schemas = {};
|
|
3753
|
-
for (const [name, model] of Object.entries(modelOrModels)) {
|
|
3754
|
-
const record = recordFieldOf(model);
|
|
3755
|
-
schemas[name] = record && names.get(record.record) === name ? recordSchemaOf(record.record, scope) : schemaOf3(model, scope);
|
|
3756
|
-
}
|
|
3757
|
-
return { schemas };
|
|
3758
|
-
}
|
|
3759
|
-
|
|
3760
|
-
// src/core/use-case/route.ts
|
|
3761
|
-
var ROUTE_METHODS = [
|
|
3762
|
-
"get",
|
|
3763
|
-
"post",
|
|
3764
|
-
"put",
|
|
3765
|
-
"patch",
|
|
3766
|
-
"delete"
|
|
3767
|
-
];
|
|
3768
|
-
var ROUTE_SUCCESS_STATUSES = [
|
|
3769
|
-
200,
|
|
3770
|
-
201,
|
|
3771
|
-
202,
|
|
3772
|
-
204
|
|
3773
|
-
];
|
|
3774
|
-
var PARAMETER = /^\{([A-Za-z_][A-Za-z0-9_]*)\}$/;
|
|
3775
|
-
var HEADER_NAME = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
|
|
3776
|
-
function isRoutePath(value, parameters = true) {
|
|
3777
|
-
if (typeof value !== "string" || !value.startsWith("/"))
|
|
3778
|
-
return false;
|
|
3779
|
-
return value.split("/").every((segment) => parameters && PARAMETER.test(segment) || !/[{}?#\s:*]/.test(segment));
|
|
3780
|
-
}
|
|
3781
|
-
function parametersOfPath(path) {
|
|
3782
|
-
const names = [];
|
|
3783
|
-
for (const segment of path.split("/")) {
|
|
3784
|
-
const name = PARAMETER.exec(segment)?.[1];
|
|
3785
|
-
if (name)
|
|
3786
|
-
names.push(name);
|
|
3787
|
-
}
|
|
3788
|
-
return names;
|
|
3789
|
-
}
|
|
3790
|
-
function isScalarSchema(schema) {
|
|
3791
|
-
const types = [schema.type ?? []].flat();
|
|
3792
|
-
return !types.some((type) => type === "object" || type === "array");
|
|
3793
|
-
}
|
|
3794
|
-
function isScalarKey(blueprint, name) {
|
|
3795
|
-
if (!Object.hasOwn(blueprint.properties, name))
|
|
3796
|
-
return false;
|
|
3797
|
-
const field = blueprint.properties[name];
|
|
3798
|
-
return isProperty(field) && isScalarSchema(toOpenAPI2(field));
|
|
3799
|
-
}
|
|
3800
|
-
function isObject(value) {
|
|
3801
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3802
|
-
}
|
|
3803
|
-
var ROUTE_KEYS = [
|
|
3804
|
-
"method",
|
|
3805
|
-
"path",
|
|
3806
|
-
"status",
|
|
3807
|
-
"query",
|
|
3808
|
-
"headers",
|
|
3809
|
-
"cookie",
|
|
3810
|
-
"setCookie"
|
|
3811
|
-
];
|
|
3812
|
-
var COOKIE_KEYS = [
|
|
3813
|
-
"name",
|
|
3814
|
-
"httpOnly",
|
|
3815
|
-
"secure",
|
|
3816
|
-
"sameSite",
|
|
3817
|
-
"path",
|
|
3818
|
-
"domain",
|
|
3819
|
-
"maxAge"
|
|
3820
|
-
];
|
|
3821
|
-
function cookieIssue(cookie, where) {
|
|
3822
|
-
if (!isObject(cookie) || typeof cookie.name !== "string") {
|
|
3823
|
-
return `Expected ${where} to be { name, httpOnly?, secure?, sameSite?, path?, domain?, maxAge? }.`;
|
|
3824
|
-
}
|
|
3825
|
-
for (const key of Object.keys(cookie)) {
|
|
3826
|
-
if (!COOKIE_KEYS.includes(key))
|
|
3827
|
-
return `${where} has no option "${key}".`;
|
|
3828
|
-
}
|
|
3829
|
-
if (!HEADER_NAME.test(cookie.name)) {
|
|
3830
|
-
return `Expected ${where}.name to be the name of a cookie.`;
|
|
3831
|
-
}
|
|
3832
|
-
for (const key of ["httpOnly", "secure"]) {
|
|
3833
|
-
if (cookie[key] !== undefined && typeof cookie[key] !== "boolean") {
|
|
3834
|
-
return `Expected ${where}.${key} to be a boolean.`;
|
|
3835
|
-
}
|
|
3836
|
-
}
|
|
3837
|
-
if (cookie.sameSite !== undefined && !["strict", "lax", "none"].includes(cookie.sameSite)) {
|
|
3838
|
-
return `Expected ${where}.sameSite to be "strict", "lax" or "none".`;
|
|
3839
|
-
}
|
|
3840
|
-
if (cookie.sameSite === "none" && cookie.secure === false) {
|
|
3841
|
-
return `${where}.sameSite "none" needs a secure cookie.`;
|
|
3842
|
-
}
|
|
3843
|
-
for (const key of ["path", "domain"]) {
|
|
3844
|
-
const value = cookie[key];
|
|
3845
|
-
if (value !== undefined && (typeof value !== "string" || value === "" || /[;\s]/.test(value))) {
|
|
3846
|
-
return `Expected ${where}.${key} to be text without ";" or spaces.`;
|
|
3847
|
-
}
|
|
3848
|
-
}
|
|
3849
|
-
if (cookie.maxAge !== undefined && (!Number.isInteger(cookie.maxAge) || cookie.maxAge < 0)) {
|
|
3850
|
-
return `Expected ${where}.maxAge to be a whole number of seconds, 0 or more.`;
|
|
3851
|
-
}
|
|
3852
|
-
return;
|
|
3853
|
-
}
|
|
3854
|
-
function routeDeclarationOf(route, blueprint, response) {
|
|
3855
|
-
if (!isObject(route)) {
|
|
3856
|
-
return "Expected route to be { method, path?, status?, query?, headers?, cookie?, setCookie? }.";
|
|
3857
|
-
}
|
|
3858
|
-
for (const key of Object.keys(route)) {
|
|
3859
|
-
if (!ROUTE_KEYS.includes(key))
|
|
3860
|
-
return `route has no option "${key}".`;
|
|
3861
|
-
}
|
|
3862
|
-
const method = typeof route.method === "string" ? route.method.toLowerCase() : undefined;
|
|
3863
|
-
if (!ROUTE_METHODS.includes(method)) {
|
|
3864
|
-
return `Expected route.method to be one of ${ROUTE_METHODS.join(", ")}.`;
|
|
3865
|
-
}
|
|
3866
|
-
const { path, status, query, headers, cookie, setCookie } = route;
|
|
3867
|
-
const places = new Map;
|
|
3868
|
-
const place = (key, where) => {
|
|
3869
|
-
const taken = places.get(key);
|
|
3870
|
-
if (taken !== undefined) {
|
|
3871
|
-
return `route reads the input key "${key}" from two places: ${taken} and ${where}.`;
|
|
3872
|
-
}
|
|
3873
|
-
if (!isScalarKey(blueprint, key)) {
|
|
3874
|
-
return `route reads "${key}" from ${where}, but it is not a scalar key of the input.`;
|
|
3875
|
-
}
|
|
3876
|
-
places.set(key, where);
|
|
3877
|
-
return;
|
|
3878
|
-
};
|
|
3879
|
-
if (path !== undefined) {
|
|
3880
|
-
if (!isRoutePath(path)) {
|
|
3881
|
-
return 'Expected route.path to start with "/", with parameters only as whole "{name}" segments and no query.';
|
|
3882
|
-
}
|
|
3883
|
-
for (const name of parametersOfPath(path)) {
|
|
3884
|
-
const bad = place(name, "the path");
|
|
3885
|
-
if (bad)
|
|
3886
|
-
return bad;
|
|
3887
|
-
}
|
|
3888
|
-
}
|
|
3889
|
-
if (status !== undefined && !ROUTE_SUCCESS_STATUSES.includes(status)) {
|
|
3890
|
-
return `Expected route.status to be one of ${ROUTE_SUCCESS_STATUSES.join(", ")}.`;
|
|
3891
|
-
}
|
|
3892
|
-
if (query !== undefined) {
|
|
3893
|
-
if (!Array.isArray(query) || query.some((key) => typeof key !== "string")) {
|
|
3894
|
-
return "Expected route.query to be a list of input keys.";
|
|
3895
|
-
}
|
|
3896
|
-
for (const key of query) {
|
|
3897
|
-
const bad = place(key, "the query");
|
|
3898
|
-
if (bad)
|
|
3899
|
-
return bad;
|
|
3900
|
-
}
|
|
3901
|
-
}
|
|
3902
|
-
for (const [option, value, where] of [
|
|
3903
|
-
["headers", headers, "a header"],
|
|
3904
|
-
["cookie", cookie, "a cookie"]
|
|
3905
|
-
]) {
|
|
3906
|
-
if (value === undefined)
|
|
3907
|
-
continue;
|
|
3908
|
-
if (!isObject(value)) {
|
|
3909
|
-
return `Expected route.${option} to map input keys to names.`;
|
|
3910
|
-
}
|
|
3911
|
-
const names = new Set;
|
|
3912
|
-
for (const [key, name] of Object.entries(value)) {
|
|
3913
|
-
if (typeof name !== "string" || !HEADER_NAME.test(name)) {
|
|
3914
|
-
return `Expected route.${option}["${key}"] to be the name of ${where}.`;
|
|
3915
|
-
}
|
|
3916
|
-
const bad = place(key, where);
|
|
3917
|
-
if (bad)
|
|
3918
|
-
return bad;
|
|
3919
|
-
const folded = option === "headers" ? name.toLowerCase() : name;
|
|
3920
|
-
if (names.has(folded)) {
|
|
3921
|
-
return `route.${option} reads "${name}" into two input keys.`;
|
|
3922
|
-
}
|
|
3923
|
-
names.add(folded);
|
|
3924
|
-
}
|
|
3925
|
-
}
|
|
3926
|
-
if (setCookie !== undefined) {
|
|
3927
|
-
if (!isObject(setCookie)) {
|
|
3928
|
-
return "Expected route.setCookie to map response keys to cookies.";
|
|
3929
|
-
}
|
|
3930
|
-
const names = new Set;
|
|
3931
|
-
for (const [key, settings] of Object.entries(setCookie)) {
|
|
3932
|
-
if (!isScalarKey(response, key)) {
|
|
3933
|
-
return `route.setCookie sends "${key}", which is not a scalar key of the response.`;
|
|
3934
|
-
}
|
|
3935
|
-
const bad = cookieIssue(settings, `route.setCookie["${key}"]`);
|
|
3936
|
-
if (bad)
|
|
3937
|
-
return bad;
|
|
3938
|
-
const { name } = settings;
|
|
3939
|
-
if (names.has(name)) {
|
|
3940
|
-
return `route.setCookie sets the cookie "${name}" from two response keys.`;
|
|
3941
|
-
}
|
|
3942
|
-
names.add(name);
|
|
3943
|
-
}
|
|
3944
|
-
}
|
|
3945
|
-
return Object.freeze({
|
|
3946
|
-
method,
|
|
3947
|
-
...path === undefined ? {} : { path },
|
|
3948
|
-
...status === undefined ? {} : { status },
|
|
3949
|
-
...query === undefined ? {} : { query: Object.freeze([...query]) },
|
|
3950
|
-
...headers === undefined ? {} : {
|
|
3951
|
-
headers: Object.freeze(Object.fromEntries(Object.entries(headers).map(([key, name]) => [key, name.toLowerCase()])))
|
|
3952
|
-
},
|
|
3953
|
-
...cookie === undefined ? {} : { cookie: Object.freeze({ ...cookie }) },
|
|
3954
|
-
...setCookie === undefined ? {} : {
|
|
3955
|
-
setCookie: Object.freeze(Object.fromEntries(Object.entries(setCookie).map(([key, settings]) => [key, Object.freeze({ ...settings })])))
|
|
3956
|
-
}
|
|
3957
|
-
});
|
|
3958
|
-
}
|
|
3959
|
-
|
|
3960
|
-
// src/core/output/exceptions.ts
|
|
3961
|
-
var InvalidOutputStage2 = exceptionOf2({
|
|
3962
|
-
layer: "output" /* Output */,
|
|
3963
|
-
name: "InvalidOutputStage",
|
|
3964
|
-
message: ({ reason }) => reason
|
|
3965
|
-
});
|
|
3966
|
-
var DuplicateOperation2 = exceptionOf2({
|
|
3967
|
-
layer: "output" /* Output */,
|
|
3968
|
-
name: "DuplicateOperation",
|
|
3969
|
-
message: ({ id }) => `The operation "${id}" is declared twice.`
|
|
3970
|
-
});
|
|
3971
|
-
var Unauthenticated2 = exceptionOf2({
|
|
3972
|
-
layer: "output" /* Output */,
|
|
3973
|
-
name: "Unauthenticated",
|
|
3974
|
-
message: "Authentication is required."
|
|
3975
|
-
});
|
|
3976
|
-
var Forbidden2 = exceptionOf2({
|
|
3977
|
-
layer: "output" /* Output */,
|
|
3978
|
-
name: "Forbidden",
|
|
3979
|
-
message: (_details) => "The caller may not do this."
|
|
3980
|
-
});
|
|
3981
|
-
|
|
3982
|
-
// src/core/output/stage.ts
|
|
3983
|
-
var descriptions = new WeakMap;
|
|
3984
|
-
var factories = new WeakMap;
|
|
3985
|
-
var opaque = Object.freeze({ kind: "opaque" });
|
|
3986
|
-
function invalid2(source, reason) {
|
|
3987
|
-
throw new InvalidOutputStage2({ source, details: { reason } });
|
|
3988
|
-
}
|
|
3989
|
-
function optionsOf(name, given, validate) {
|
|
3990
|
-
const options = frozenJson(given ?? {}, "Stage options", (reason) => invalid2(name, reason));
|
|
3991
|
-
if (options === null || typeof options !== "object" || Array.isArray(options)) {
|
|
3992
|
-
invalid2(name, "Stage options must be an object.");
|
|
3993
|
-
}
|
|
3994
|
-
const reason = validate?.(options);
|
|
3995
|
-
if (reason !== undefined)
|
|
3996
|
-
invalid2(name, reason);
|
|
3997
|
-
return options;
|
|
3998
|
-
}
|
|
3999
|
-
function checkName(source, name) {
|
|
4000
|
-
if (typeof name !== "string" || !name.trim()) {
|
|
4001
|
-
invalid2(source, "Expected the stage name to be a non-empty string.");
|
|
4002
|
-
}
|
|
4003
|
-
}
|
|
4004
|
-
function transformOf2(settings) {
|
|
4005
|
-
checkName("transformOf", settings?.name);
|
|
4006
|
-
if (typeof settings.apply !== "function") {
|
|
4007
|
-
invalid2(settings.name, "Expected apply to be a function.");
|
|
4008
|
-
}
|
|
4009
|
-
const { name, apply, validate } = settings;
|
|
4010
|
-
const factory = (given) => {
|
|
4011
|
-
const options = optionsOf(name, given, validate);
|
|
4012
|
-
const stage = Object.freeze({
|
|
4013
|
-
kind: "transform",
|
|
4014
|
-
name,
|
|
4015
|
-
options,
|
|
4016
|
-
apply: (operation, context) => apply(operation, options, context)
|
|
4017
|
-
});
|
|
4018
|
-
descriptions.set(stage, Object.freeze({
|
|
4019
|
-
kind: "transform",
|
|
4020
|
-
name,
|
|
4021
|
-
options
|
|
4022
|
-
}));
|
|
4023
|
-
return stage;
|
|
4024
|
-
};
|
|
4025
|
-
factories.set(factory, { kind: "transform", name });
|
|
4026
|
-
return factory;
|
|
4027
|
-
}
|
|
4028
|
-
function sinkOf2(settings) {
|
|
4029
|
-
checkName("sinkOf", settings?.name);
|
|
4030
|
-
if (typeof settings.build !== "function") {
|
|
4031
|
-
invalid2(settings.name, "Expected build to be a function.");
|
|
4032
|
-
}
|
|
4033
|
-
const { name, build, validate } = settings;
|
|
4034
|
-
const factory = (given, hooks) => {
|
|
4035
|
-
const options = optionsOf(name, given, validate);
|
|
4036
|
-
if (hooks !== undefined && (typeof hooks !== "object" || hooks === null || Array.isArray(hooks))) {
|
|
4037
|
-
invalid2(name, "Stage hooks must be an object.");
|
|
4038
|
-
}
|
|
4039
|
-
const stage = Object.freeze({
|
|
4040
|
-
kind: "sink",
|
|
4041
|
-
name,
|
|
4042
|
-
options,
|
|
4043
|
-
build: (operations, context) => build(operations, options, context, hooks)
|
|
4044
|
-
});
|
|
4045
|
-
descriptions.set(stage, Object.freeze({
|
|
4046
|
-
kind: "sink",
|
|
4047
|
-
name,
|
|
4048
|
-
options
|
|
4049
|
-
}));
|
|
4050
|
-
return stage;
|
|
4051
|
-
};
|
|
4052
|
-
factories.set(factory, { kind: "sink", name });
|
|
4053
|
-
return factory;
|
|
4054
|
-
}
|
|
4055
|
-
function stageDescriptionOf2(stage) {
|
|
4056
|
-
return descriptions.get(stage) ?? opaque;
|
|
4057
|
-
}
|
|
4058
|
-
function stageKindOf2(factory) {
|
|
4059
|
-
return factories.get(factory)?.kind;
|
|
4060
|
-
}
|
|
4061
|
-
function isStage(value) {
|
|
4062
|
-
if (typeof value !== "object" || value === null)
|
|
4063
|
-
return false;
|
|
4064
|
-
const { kind, apply, build } = value;
|
|
4065
|
-
return kind === "transform" && typeof apply === "function" || kind === "sink" && typeof build === "function";
|
|
4066
|
-
}
|
|
4067
|
-
function stageCatalogOf2(...stages) {
|
|
4068
|
-
const byName = {};
|
|
4069
|
-
for (const factory of stages) {
|
|
4070
|
-
const known = factories.get(factory);
|
|
4071
|
-
if (!known) {
|
|
4072
|
-
invalid2("catalog", "A catalog takes factories made by `transformOf` or `sinkOf`.");
|
|
4073
|
-
}
|
|
4074
|
-
if (Object.hasOwn(byName, known.name)) {
|
|
4075
|
-
invalid2(known.name, "The catalog has another stage with its name.");
|
|
4076
|
-
}
|
|
4077
|
-
byName[known.name] = factory;
|
|
4078
|
-
}
|
|
4079
|
-
return Object.freeze({
|
|
4080
|
-
[Kind2]: "stage-catalog",
|
|
4081
|
-
stages: Object.freeze(byName),
|
|
4082
|
-
list: Object.freeze([...stages]),
|
|
4083
|
-
resolve(name, options) {
|
|
4084
|
-
const factory = Object.hasOwn(byName, name) ? byName[name] : undefined;
|
|
4085
|
-
if (!factory)
|
|
4086
|
-
invalid2("catalog", `Unknown stage "${name}".`);
|
|
4087
|
-
return factory(options);
|
|
4088
|
-
}
|
|
4089
|
-
});
|
|
4090
|
-
}
|
|
4091
|
-
|
|
4092
|
-
// src/core/auth/jwt.ts
|
|
4093
|
-
var InvalidJwtOptions2 = exceptionOf2({
|
|
4094
|
-
layer: "output" /* Output */,
|
|
4095
|
-
name: "InvalidJwtOptions",
|
|
4096
|
-
message: ({ reason }) => reason
|
|
4097
|
-
});
|
|
4098
|
-
var HASHES = {
|
|
4099
|
-
HS256: "SHA-256",
|
|
4100
|
-
HS384: "SHA-384",
|
|
4101
|
-
HS512: "SHA-512"
|
|
4102
|
-
};
|
|
4103
|
-
var MIN_SECRET = 32;
|
|
4104
|
-
var DEFAULT_EXPIRES_IN = 900;
|
|
4105
|
-
var REGISTERED = new Set([
|
|
4106
|
-
"sub",
|
|
4107
|
-
"scope",
|
|
4108
|
-
"iat",
|
|
4109
|
-
"exp",
|
|
4110
|
-
"nbf",
|
|
4111
|
-
"iss",
|
|
4112
|
-
"aud",
|
|
4113
|
-
"use"
|
|
4114
|
-
]);
|
|
4115
|
-
var encoder = new TextEncoder;
|
|
4116
|
-
var decoder = new TextDecoder;
|
|
4117
|
-
function base64url(bytes) {
|
|
4118
|
-
let binary = "";
|
|
4119
|
-
for (const byte of bytes)
|
|
4120
|
-
binary += String.fromCharCode(byte);
|
|
4121
|
-
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
|
|
4122
|
-
}
|
|
4123
|
-
function bytesOf(text) {
|
|
4124
|
-
if (!/^[A-Za-z0-9_-]*$/.test(text))
|
|
4125
|
-
return;
|
|
4126
|
-
try {
|
|
4127
|
-
const binary = atob(text.replaceAll("-", "+").replaceAll("_", "/"));
|
|
4128
|
-
const bytes = new Uint8Array(binary.length);
|
|
4129
|
-
for (let i = 0;i < binary.length; i++)
|
|
4130
|
-
bytes[i] = binary.charCodeAt(i);
|
|
4131
|
-
return bytes;
|
|
4132
|
-
} catch {
|
|
4133
|
-
return;
|
|
4134
|
-
}
|
|
4135
|
-
}
|
|
4136
|
-
function jsonOf(part) {
|
|
4137
|
-
const bytes = bytesOf(part);
|
|
4138
|
-
if (!bytes)
|
|
4139
|
-
return;
|
|
4140
|
-
try {
|
|
4141
|
-
const value = JSON.parse(decoder.decode(bytes));
|
|
4142
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
4143
|
-
} catch {
|
|
4144
|
-
return;
|
|
4145
|
-
}
|
|
4146
|
-
}
|
|
4147
|
-
function jwtOptionsIssue(options, where, extra = [], described = false) {
|
|
4148
|
-
if (typeof options !== "object" || options === null || Array.isArray(options)) {
|
|
4149
|
-
return `Expected ${where} to be { secret, issuer?, audience?, expiresIn?, algorithm? }.`;
|
|
4150
|
-
}
|
|
4151
|
-
const given = options;
|
|
4152
|
-
const known = [
|
|
4153
|
-
"secret",
|
|
4154
|
-
"issuer",
|
|
4155
|
-
"audience",
|
|
4156
|
-
"expiresIn",
|
|
4157
|
-
"algorithm",
|
|
4158
|
-
...extra
|
|
4159
|
-
];
|
|
4160
|
-
for (const key of Object.keys(given)) {
|
|
4161
|
-
if (!known.includes(key))
|
|
4162
|
-
return `${where} has no option "${key}".`;
|
|
4163
|
-
}
|
|
4164
|
-
const { secret, issuer, audience, expiresIn, algorithm } = given;
|
|
4165
|
-
const named = typeof secret === "object" && secret !== null && !Array.isArray(secret) ? secret : undefined;
|
|
4166
|
-
if (named ? Object.keys(named).join() !== "env" || typeof named.env !== "string" || named.env === "" : typeof secret !== "string") {
|
|
4167
|
-
return `Expected ${where}.secret to be the secret or { "env": "NAME" }.`;
|
|
4168
|
-
}
|
|
4169
|
-
if (described && !named) {
|
|
4170
|
-
return `Expected ${where}.secret to be { "env": "NAME" }: these options are described, so the secret is named, not written.`;
|
|
4171
|
-
}
|
|
4172
|
-
if (typeof secret === "string" && secret.length < MIN_SECRET) {
|
|
4173
|
-
return `Expected ${where}.secret to have at least ${MIN_SECRET} characters.`;
|
|
4174
|
-
}
|
|
4175
|
-
for (const [key, value] of [
|
|
4176
|
-
["issuer", issuer],
|
|
4177
|
-
["audience", audience]
|
|
4178
|
-
]) {
|
|
4179
|
-
if (value !== undefined && (typeof value !== "string" || value === "")) {
|
|
4180
|
-
return `Expected ${where}.${key} to be a non-empty string.`;
|
|
4181
|
-
}
|
|
4182
|
-
}
|
|
4183
|
-
if (expiresIn !== undefined && (!Number.isInteger(expiresIn) || expiresIn <= 0)) {
|
|
4184
|
-
return `Expected ${where}.expiresIn to be a whole number of seconds above 0.`;
|
|
4185
|
-
}
|
|
4186
|
-
if (algorithm !== undefined && !Object.hasOwn(HASHES, algorithm)) {
|
|
4187
|
-
return `Expected ${where}.algorithm to be one of ${Object.keys(HASHES).join(", ")}.`;
|
|
4188
|
-
}
|
|
4189
|
-
return;
|
|
4190
|
-
}
|
|
4191
|
-
function jwtOf2(options) {
|
|
4192
|
-
const issue = jwtOptionsIssue(options, "jwtOf");
|
|
4193
|
-
if (issue) {
|
|
4194
|
-
throw new InvalidJwtOptions2({
|
|
4195
|
-
source: "jwtOf",
|
|
4196
|
-
details: { reason: issue }
|
|
4197
|
-
});
|
|
4198
|
-
}
|
|
4199
|
-
const algorithm = options.algorithm ?? "HS256";
|
|
4200
|
-
const lifetime = options.expiresIn ?? DEFAULT_EXPIRES_IN;
|
|
4201
|
-
const header = base64url(encoder.encode(JSON.stringify({ alg: algorithm, typ: "JWT" })));
|
|
4202
|
-
let imported;
|
|
4203
|
-
const keyOf = () => {
|
|
4204
|
-
if (imported)
|
|
4205
|
-
return imported;
|
|
4206
|
-
let secret;
|
|
4207
|
-
if (typeof options.secret === "string")
|
|
4208
|
-
secret = options.secret;
|
|
4209
|
-
else {
|
|
4210
|
-
const name = options.secret.env;
|
|
4211
|
-
secret = globalThis.process?.env?.[name];
|
|
4212
|
-
if (typeof secret !== "string" || secret.length < MIN_SECRET) {
|
|
4213
|
-
throw new InvalidJwtOptions2({
|
|
4214
|
-
source: "jwtOf",
|
|
4215
|
-
details: {
|
|
4216
|
-
reason: `The environment variable ${name} must hold a secret of at least ${MIN_SECRET} characters.`
|
|
4217
|
-
}
|
|
4218
|
-
});
|
|
4219
|
-
}
|
|
4220
|
-
}
|
|
4221
|
-
imported = crypto.subtle.importKey("raw", encoder.encode(secret), { name: "HMAC", hash: HASHES[algorithm] }, false, ["sign", "verify"]);
|
|
4222
|
-
return imported;
|
|
4223
|
-
};
|
|
4224
|
-
const refused = () => {
|
|
4225
|
-
throw new Unauthenticated2({ source: "jwt" });
|
|
4226
|
-
};
|
|
4227
|
-
const jwt = {
|
|
4228
|
-
async sign(subject, token = {}) {
|
|
4229
|
-
const now = Math.floor(Date.now() / 1000);
|
|
4230
|
-
const payload = {
|
|
4231
|
-
...subject.claims ?? {},
|
|
4232
|
-
sub: subject.subject,
|
|
4233
|
-
scope: (subject.scopes ?? []).join(" "),
|
|
4234
|
-
iat: now,
|
|
4235
|
-
exp: now + (token.expiresIn ?? lifetime),
|
|
4236
|
-
...options.issuer === undefined ? {} : { iss: options.issuer },
|
|
4237
|
-
...options.audience === undefined ? {} : { aud: options.audience },
|
|
4238
|
-
...token.use === undefined ? {} : { use: token.use }
|
|
4239
|
-
};
|
|
4240
|
-
const signing = `${header}.${base64url(encoder.encode(JSON.stringify(payload)))}`;
|
|
4241
|
-
const signature = await crypto.subtle.sign("HMAC", await keyOf(), encoder.encode(signing));
|
|
4242
|
-
return `${signing}.${base64url(new Uint8Array(signature))}`;
|
|
4243
|
-
},
|
|
4244
|
-
async verify(token, expected = {}) {
|
|
4245
|
-
if (typeof token !== "string")
|
|
4246
|
-
return refused();
|
|
4247
|
-
const parts = token.split(".");
|
|
4248
|
-
if (parts.length !== 3)
|
|
4249
|
-
return refused();
|
|
4250
|
-
const [head, body, sign] = parts;
|
|
4251
|
-
if (jsonOf(head)?.alg !== algorithm)
|
|
4252
|
-
return refused();
|
|
4253
|
-
const signature = bytesOf(sign);
|
|
4254
|
-
if (!signature)
|
|
4255
|
-
return refused();
|
|
4256
|
-
const valid = await crypto.subtle.verify("HMAC", await keyOf(), signature, encoder.encode(`${head}.${body}`));
|
|
4257
|
-
const payload = valid ? jsonOf(body) : undefined;
|
|
4258
|
-
if (!payload)
|
|
4259
|
-
return refused();
|
|
4260
|
-
const now = Math.floor(Date.now() / 1000);
|
|
4261
|
-
const { sub, scope, exp, nbf, iss, aud, use } = payload;
|
|
4262
|
-
if (typeof sub !== "string" || sub === "" || typeof exp !== "number" || exp <= now || nbf !== undefined && (typeof nbf !== "number" || nbf > now) || options.issuer !== undefined && iss !== options.issuer || options.audience !== undefined && aud !== options.audience && !(Array.isArray(aud) && aud.includes(options.audience)) || use !== expected.use) {
|
|
4263
|
-
return refused();
|
|
4264
|
-
}
|
|
4265
|
-
const claims = {};
|
|
4266
|
-
for (const [key, value] of Object.entries(payload)) {
|
|
4267
|
-
if (!REGISTERED.has(key))
|
|
4268
|
-
claims[key] = value;
|
|
4269
|
-
}
|
|
4270
|
-
return {
|
|
4271
|
-
subject: sub,
|
|
4272
|
-
scopes: typeof scope === "string" && scope !== "" ? scope.split(" ") : [],
|
|
4273
|
-
...Object.keys(claims).length > 0 ? { claims } : {}
|
|
4274
|
-
};
|
|
4275
|
-
},
|
|
4276
|
-
authenticator(reading = {}) {
|
|
4277
|
-
const header = (reading.header ?? "authorization").toLowerCase();
|
|
4278
|
-
const { cookie } = reading;
|
|
4279
|
-
return async (request) => {
|
|
4280
|
-
const sent = request.header(header);
|
|
4281
|
-
const token = sent !== undefined ? sent.replace(/^Bearer +/i, "").trim() : cookie !== undefined ? request.cookie(cookie) : undefined;
|
|
4282
|
-
if (token === undefined || token === "")
|
|
4283
|
-
return null;
|
|
4284
|
-
return jwt.verify(token);
|
|
4285
|
-
};
|
|
4286
|
-
}
|
|
4287
|
-
};
|
|
4288
|
-
return Object.freeze(jwt);
|
|
4289
|
-
}
|
|
4290
|
-
|
|
4291
|
-
export { __export, isProperty, schemaOf, Demo2, recordPropertyLineage, propertyLineageOf2, fieldOf, Kind2, isBlueprint, isRecordClass, recordFieldOf, ExceptionLayers2, Exception2, isDeclaredException, declaredMessageOf, exceptionOf2, ReservedBlueprintKey2, InvalidBlueprintVariant2, UndeclaredBlueprintProperty2, exports_exceptions3, variantOf2, blueprintOfVariant, namedVariantOf, variantOfValue, isBlueprintVariant, State2, PropertyRequired2, InvalidPropertyValue2, exports_exceptions4, recordNameOf2, declaredRecordNameOf, fieldsOf, isPlainObject, listOf2, isBlueprintList, InvalidEnvironment2, environmentOf2, loadEnvironments, isEnvironment, exports_environment, InvalidApplicationDeclaration2, DuplicateApplicationDeclaration2, ApplicationConflict2, UnregisteredApplicationReference2, UnregisteredRepositoryDependency2, UnregisteredUseCaseDependency2, ApplicationNotStarted2, ProviderNotBound2, ApplicationAlreadyStarted2, SchemaLockMismatch2, InvalidSchemaMigration2, InvalidApplicationEnvironment2, exports_exceptions5, useApplication2, resetApplication2, startedApplication, setStartedApplication, InvalidLogDeclaration2, exports_exceptions6, LogLevels2, logProviderOf2, logProviderNameOf, consoleLogProvider2, jsonLogProvider2, memoryLogProvider2, checkLogSettings, silentLogger, applicationLogger, Logger2, isLoggerDeclaration, isLogger, ApplicationLoggerKey, resolveLogger, clock, elapsed, logFailure, writeLog, Meta2, InvalidRecordValue2, InvalidRecordDeclaration2, UndeclaredRecordProperty2, ReservedRecordKey2, InvalidRecordPlugin2, RecordPluginConflict2, UnknownRecordPlugin2, IncompatibleRecordPlugin2, exports_exceptions7, MASK2, RESERVED_RECORD_KEYS2, recordDataOf, recordFieldDataOf, AbstractRecord, propertyOf2, optionalOf2, blueprintBuilderOf2, blueprintFromProperties, isVersion, satisfies, pluginsOf2, isRecordPlugin, hasPlugin2, recordPluginOf2, recordBuilderOf2, recordOf3, declareRecord, ReservedEntityKey2, ImmutableEntityKey2, DeletedEntity2, InvalidEntityExpiry2, InvalidEntitySchemaVersion2, exports_exceptions8, vouching, EntityVersion2, entityBuilderOf2, isEntityClass2, isEntity2, eventOf2, eventHasHandler, lifecycleEventsOf, enqueueLifecycle, ENTITY_IDENTITY_KEYS2, RESERVED_ENTITY_KEYS2, EntityClock, EntityUniqueKeys2, EntitySettings2, SCHEMA_VERSION_KEY2, isVersionedEntityClass, identityKeysOf, storeEntityVersion, InvalidRepositoryQuery2, InvalidRepositoryCursor2, InvalidRepositoryDeclaration2, InvalidRepositoryEntity2, InvalidStoredSchemaVersion2, InvalidRepositoryData2, RepositoryUniqueViolation2, RepositoryUsedOutsideApplication2, RepositoryEntityNotFound2, RepositoryConcurrencyConflict2, InvalidRepositoryIncrement2, exports_exceptions9, frozenJson, states, findState, stateOf, contextOf, inspectRepository, declareRepository, relatedRepositoryOf, assertUnbound, bindRepository, providerOfRepository, InvalidOpenAPIModel2, exports_exceptions10, plainOf, toOpenAPI2, HEADER_NAME, isRoutePath, parametersOfPath, isScalarSchema, isScalarKey, routeDeclarationOf, InvalidOutputStage2, DuplicateOperation2, Unauthenticated2, Forbidden2, exports_exceptions11, transformOf2, sinkOf2, stageDescriptionOf2, stageKindOf2, isStage, stageCatalogOf2, InvalidJwtOptions2, jwtOptionsIssue, jwtOf2 };
|