adaptive-extender 0.10.5 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 0.11.0 (21.06.2026)
2
+ - Added `Array.Of(type)` portable adapter for typed arrays, alongside the existing `Array.import`/`Array.export`.
3
+ - Added `Set.Of(type)` portable adapter for typed sets.
4
+ - Added `Map.AsRecord(type)` and `Map.AsTuples(typeKey, typeValue)` portable adapters (moved from a separate module into [map](./src/core/map.ts)).
5
+ - Added `Date.AsTimestamp` and `Date.AsUnixSeconds` portable adapters converting `Date` to millisecond and Unix-second numbers respectively.
6
+ - Added `Number.prototype.snap(step)` — snaps a number to the nearest multiple of the given step.
7
+ - **Breaking:** Removed `Reflect.mapNull`, `Reflect.mapUndefined`, and `Reflect.mapNullable`. Use `Nullable.map`, `Optional.map` from the portable module instead.
8
+ - **Breaking:** Renamed `Archive`/`ArchiveManager`/`ArchiveRepository` to `Cell`/`PortableCell`/`BufferedCell`. Construction is now done via `Storage` factory methods (`localStorage.openCell`, `localStorage.openPortableCell`, `localStorage.openBufferedCell`) — the storage backend is no longer hardcoded to `localStorage`.
9
+ - **Breaking:** `@Field` decorator no longer accepts a positional string as the second argument. Use `{ name: "..." }` options object: `@Field(String, { name: "fieldName" })`.
10
+ - `PortableCell.save()` returns `Promise<boolean>` — resolves `true` when persisted, `false` if cancelled (superseded or aborted); rejects only on serialization failure.
11
+ - Internal: `portable.ts` de-anemia refactor — `FieldDescriptor`, `DescendantDescriptor`, and `ModelSchema` are now rich objects with their own behavior (`importInto`, `exportFrom`, `accepts`, `owns`); `SchemaResolver` absorbed into `ModelSchema.resolve()`; `Model.import`/`Model.export` are thin facades.
12
+
1
13
  ## 0.10.5 (13.06.2026)
2
14
  - Bugfix at [portable](./src/core/portable.ts).
3
15
 
@@ -16,7 +28,7 @@
16
28
  ## 0.9.13 (06.04.2026)
17
29
  - Added `Version` class for semantic versioning with `parse()`, `tryParse()` support.
18
30
  - Added `BigInt` portable support via `BigInt.import()` and `BigInt.export()`.
19
- - `ArchiveRepository.save()` is now `async` and returns `Promise<void>`. The promise resolves when the save completes and rejects on failure. A pending save is cancelled (with an `AbortError`) when superseded by a new call.
31
+ - `ArchiveRepository.save()` is now `async` and returns `Promise<boolean>`. The promise resolves `true` when the save completes, `false` if cancelled (superseded by a subsequent call or aborted via `abort()`), and rejects only on serialization failure.
20
32
  - `Promise.withSignal` now has a default type parameter `T = void`.
21
33
  - Renamed `EnumFrom` adapter to `EnumAs`.
22
34
 
package/README.md CHANGED
@@ -412,10 +412,10 @@ const repository = new ArchiveRepository("settings", Settings, new Settings());
412
412
  const settings = repository.content;
413
413
  settings.volume = 0.5;
414
414
 
415
- // save() is async resolves when the write completes, rejects on failure
416
- await repository.save(); // save immediately
415
+ // save() resolves true when persisted, false if cancelled (superseded or aborted), rejects only on serialization failure
416
+ const saved = await repository.save(); // save immediately
417
417
  await repository.save(3000); // debounced — save after 3 seconds
418
- // A pending save is cancelled (AbortError) when superseded by a new call
418
+ // A pending save resolves false when superseded by a new call or cancelled by abort()
419
419
  repository.reset(); // abort pending save and revert to initial state
420
420
  ```
421
421
 
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  import "./global.js";
3
3
  import {} from "./promise.js";
4
+ import {} from "./portable.js";
4
5
  const { trunc } = Math;
5
6
  Array.import = function (source, name) {
6
7
  if (!Array.isArray(source))
@@ -10,6 +11,22 @@ Array.import = function (source, name) {
10
11
  Array.export = function (source) {
11
12
  return source;
12
13
  };
14
+ Array.Of = function (type) {
15
+ return {
16
+ [Symbol.hasInstance](instance) {
17
+ return Array[Symbol.hasInstance](instance);
18
+ },
19
+ get name() {
20
+ return `${type.name}[]`;
21
+ },
22
+ import(source, name) {
23
+ return Array.import(source, name).map((item, index) => type.import(item, `${name}[${index}]`));
24
+ },
25
+ export(source) {
26
+ return source.map(item => type.export(item));
27
+ },
28
+ };
29
+ };
13
30
  Array.range = function (min, max) {
14
31
  min = trunc(min);
15
32
  max = trunc(max);
package/dist/core/date.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  import "./global.js";
3
+ import {} from "./portable.js";
3
4
  Date.import = function (source, name) {
4
5
  if (typeof (source) !== "string")
5
6
  throw new TypeError(`Unable to import date from ${name} due its ${typename(source)} type`);
@@ -13,6 +14,38 @@ Date.isInvalid = function (date) {
13
14
  return false;
14
15
  return Number.isNaN(date.getTime());
15
16
  };
17
+ Date.AsTimestamp = {
18
+ [Symbol.hasInstance](instance) {
19
+ return Date[Symbol.hasInstance](instance);
20
+ },
21
+ get name() {
22
+ return "Timestamp";
23
+ },
24
+ import(source, name) {
25
+ if (typeof (source) !== "number")
26
+ throw new TypeError(`Unable to import date from ${name} due its ${typename(source)} type`);
27
+ return new Date(source);
28
+ },
29
+ export(source) {
30
+ return source.getTime();
31
+ },
32
+ };
33
+ Date.AsUnixSeconds = {
34
+ [Symbol.hasInstance](instance) {
35
+ return Date[Symbol.hasInstance](instance);
36
+ },
37
+ get name() {
38
+ return "UnixSeconds";
39
+ },
40
+ import(source, name) {
41
+ if (typeof (source) !== "number")
42
+ throw new TypeError(`Unable to import date from ${name} due its ${typename(source)} type`);
43
+ return new Date(source * 1000);
44
+ },
45
+ export(source) {
46
+ return Math.trunc(source.getTime() / 1000);
47
+ },
48
+ };
16
49
  Date.prototype.insteadInvalid = function (value) {
17
50
  if (Date.isInvalid(this))
18
51
  return value;
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- Reflect.set(Symbol, "metadata", Reflect.get(Symbol, "metadata") ?? Symbol.for("Symbol.metadata"));
3
2
  globalThis.constructor = function (value) {
4
3
  return value.constructor;
5
4
  };
package/dist/core/map.js CHANGED
@@ -1,8 +1,54 @@
1
1
  "use strict";
2
+ import {} from "./portable.js";
3
+ Map.AsRecord = function (type) {
4
+ return {
5
+ [Symbol.hasInstance](instance) {
6
+ return Map[Symbol.hasInstance](instance);
7
+ },
8
+ get name() {
9
+ return `Map<string, ${type.name}>`;
10
+ },
11
+ import(source, name) {
12
+ const record = Object.import(source, name);
13
+ const map = new Map();
14
+ for (const key of Object.keys(record)) {
15
+ map.set(key, type.import(Reflect.get(record, key), `${name}[${JSON.stringify(key)}]`));
16
+ }
17
+ return map;
18
+ },
19
+ export(source) {
20
+ const record = {};
21
+ for (const [key, value] of source) {
22
+ Reflect.set(record, key, type.export(value));
23
+ }
24
+ return record;
25
+ },
26
+ };
27
+ };
28
+ Map.AsTuples = function (typeKey, typeValue) {
29
+ return {
30
+ [Symbol.hasInstance](instance) {
31
+ return Map[Symbol.hasInstance](instance);
32
+ },
33
+ get name() {
34
+ return `Map<${typeKey.name}, ${typeValue.name}>`;
35
+ },
36
+ import(source, name) {
37
+ return new Map(Array.import(source, name).map((item, index) => {
38
+ const tuple = Array.import(item, `${name}[${index}]`);
39
+ const key = typeKey.import(tuple[0], `${name}[${index}][0]`);
40
+ const value = typeValue.import(tuple[1], `${name}[${index}][1]`);
41
+ return [key, value];
42
+ }));
43
+ },
44
+ export(source) {
45
+ return Array.from(source, ([key, value]) => [typeKey.export(key), typeValue.export(value)]);
46
+ },
47
+ };
48
+ };
2
49
  Map.prototype.add = function (key, value) {
3
50
  if (this.has(key))
4
51
  return false;
5
52
  this.set(key, value);
6
53
  return true;
7
54
  };
8
- export {};
package/dist/core/math.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const { PI, trunc, pow } = Math;
2
+ const { PI, trunc, pow, round } = Math;
3
3
  Number.prototype.clamp = function (min, max) {
4
4
  let result = this.valueOf();
5
5
  if (result < min)
@@ -8,6 +8,11 @@ Number.prototype.clamp = function (min, max) {
8
8
  return max;
9
9
  return result;
10
10
  };
11
+ function normalize(value, min, max) {
12
+ if (min === max)
13
+ throw new Error("Minimum and maximum of the original range cant be equal");
14
+ return (value - min) / (max - min);
15
+ }
11
16
  function lerp(value, min1, max1, min2, max2) {
12
17
  if (min1 === max1)
13
18
  throw new Error("Minimum and maximum of the original range cant be equal");
@@ -17,18 +22,24 @@ function lerp(value, min1, max1, min2, max2) {
17
22
  }
18
23
  Number.prototype.lerp = function (min1, max1, min2, max2) {
19
24
  if (min2 === undefined || max2 === undefined)
20
- return lerp(this.valueOf(), min1, max1, 0, 1);
25
+ return normalize(this.valueOf(), min1, max1);
21
26
  return lerp(this.valueOf(), min1, max1, min2, max2);
22
27
  };
23
- function mod(value, start, length) {
28
+ function repeat(value, length) {
24
29
  if (length === 0)
25
30
  throw new RangeError("Length must not be zero");
26
- return ((value - start) % length + length) % length + start;
31
+ return (value % length + length) % length;
32
+ }
33
+ function wrap(value, start, length) {
34
+ return repeat(value - start, length) + start;
27
35
  }
28
36
  Number.prototype.mod = function (arg1, arg2) {
29
37
  if (arg2 === undefined)
30
- return mod(this.valueOf(), 0, arg1);
31
- return mod(this.valueOf(), arg1, arg2);
38
+ return repeat(this.valueOf(), arg1);
39
+ return wrap(this.valueOf(), arg1, arg2);
40
+ };
41
+ Number.prototype.snap = function (step) {
42
+ return round(this.valueOf() / step) * step;
32
43
  };
33
44
  Math.split = function (x) {
34
45
  const integer = trunc(x);
@@ -9,28 +9,35 @@ import "./reflect.js";
9
9
  import "./error.js";
10
10
  import {} from "./global.js";
11
11
  //#endregion
12
- //#region Field descriptor
12
+ //#region Descriptors
13
+ Reflect.set(Symbol, "metadata", Reflect.get(Symbol, "metadata") ?? Symbol.for("Symbol.metadata"));
13
14
  class FieldDescriptor {
14
15
  #key;
15
16
  #association;
16
17
  #type;
17
- constructor(key, association, type) {
18
+ #hasFallback = false;
19
+ #fallback;
20
+ constructor(key, type, options = {}) {
18
21
  this.#key = key;
19
- this.#association = association;
22
+ this.#association = options.name ?? key;
20
23
  this.#type = type;
24
+ if (!("fallback" in options))
25
+ return;
26
+ this.#hasFallback = true;
27
+ this.#fallback = type.export(options.fallback);
21
28
  }
22
- get key() {
23
- return this.#key;
29
+ get key() { return this.#key; }
30
+ get association() { return this.#association; }
31
+ import(object, name) {
32
+ const association = this.#association;
33
+ const raw = Reflect.get(object, association);
34
+ const source = raw === undefined && this.#hasFallback ? this.#fallback : raw;
35
+ return this.#type.import(source, `${name}.${association}`);
24
36
  }
25
- get association() {
26
- return this.#association;
27
- }
28
- get type() {
29
- return this.#type;
37
+ export(source) {
38
+ return this.#type.export(Reflect.get(source, this.#key));
30
39
  }
31
40
  }
32
- //#endregion
33
- //#region Descendant descriptor
34
41
  class DescendantDescriptor {
35
42
  #type;
36
43
  #discriminator;
@@ -38,15 +45,99 @@ class DescendantDescriptor {
38
45
  this.#type = type;
39
46
  this.#discriminator = discriminator;
40
47
  }
41
- get type() {
42
- return this.#type;
48
+ get discriminator() { return this.#discriminator ?? this.#type.name; }
49
+ accepts(discriminator) {
50
+ return this.discriminator === discriminator;
51
+ }
52
+ owns(instance) {
53
+ return instance instanceof this.#type;
43
54
  }
44
- get discriminator() {
45
- return this.#discriminator ?? this.#type.name;
55
+ import(source, name) {
56
+ return this.#type.import(source, name);
57
+ }
58
+ export(source) {
59
+ return this.#type.export(source);
60
+ }
61
+ }
62
+ class ModelSchema {
63
+ static #schemas = new WeakMap();
64
+ static #collect(object) {
65
+ const fields = new Map();
66
+ let current = object;
67
+ while (current !== null) {
68
+ for (const [key, descriptor] of PortabilityMetadata.for(current).fields)
69
+ fields.add(key, descriptor);
70
+ current = Object.getPrototypeOf(current);
71
+ }
72
+ return fields;
73
+ }
74
+ static resolve(model) {
75
+ const schemas = ModelSchema.#schemas;
76
+ let schema = schemas.get(model);
77
+ if (schema !== undefined)
78
+ return schema;
79
+ const object = ReferenceError.suppress(model[Symbol.metadata], `Required an implementation of Symbol.metadata in '${model.name}' to use portability`);
80
+ const { discriminator, descendants } = Object.hasOwn(model, Symbol.metadata)
81
+ ? PortabilityMetadata.for(object)
82
+ : new PortabilityMetadata();
83
+ schema = descendants.length > 0
84
+ ? new PolymorphicSchema(discriminator, descendants)
85
+ : new ConcreteSchema(model, ModelSchema.#collect(object));
86
+ schemas.set(model, schema);
87
+ return schema;
88
+ }
89
+ }
90
+ class ConcreteSchema extends ModelSchema {
91
+ #model;
92
+ #fields;
93
+ constructor(model, fields) {
94
+ super();
95
+ this.#model = model;
96
+ this.#fields = fields;
97
+ }
98
+ import(source, name) {
99
+ const object = Object.import(source, name);
100
+ const instance = Reflect.construct(this.#model, []);
101
+ for (const descriptor of this.#fields.values())
102
+ Reflect.set(instance, descriptor.key, descriptor.import(object, name));
103
+ return instance;
104
+ }
105
+ export(source) {
106
+ const target = new Object();
107
+ for (const descriptor of this.#fields.values())
108
+ Reflect.set(target, descriptor.association, descriptor.export(source));
109
+ return target;
110
+ }
111
+ }
112
+ class PolymorphicSchema extends ModelSchema {
113
+ #discriminator;
114
+ #descendants;
115
+ constructor(discriminator, descendants) {
116
+ super();
117
+ this.#discriminator = discriminator;
118
+ this.#descendants = descendants;
119
+ }
120
+ import(source, name) {
121
+ const key = this.#discriminator;
122
+ const object = Object.import(source, name);
123
+ const value = Reflect.get(object, key);
124
+ if (value === undefined)
125
+ throw new TypeError(`Missing '${key}' discriminator in ${name}`);
126
+ const discriminator = String.import(value, `${name}.${key}`);
127
+ const descriptor = this.#descendants.find(descendant => descendant.accepts(discriminator));
128
+ if (descriptor === undefined)
129
+ throw new TypeError(`Unknown '${discriminator}' discriminator for ${name}`);
130
+ return descriptor.import(source, name);
131
+ }
132
+ export(source) {
133
+ const descriptor = this.#descendants.find(descendant => descendant.owns(source));
134
+ if (descriptor === undefined)
135
+ throw new TypeError(`Invalid '${typename(source)}' type for source`);
136
+ const exported = descriptor.export(source);
137
+ Reflect.set(exported, this.#discriminator, descriptor.discriminator);
138
+ return exported;
46
139
  }
47
140
  }
48
- //#endregion
49
- //#region Portability metadata
50
141
  class PortabilityMetadata {
51
142
  static #registry = new WeakMap();
52
143
  #fields = new Map();
@@ -61,40 +152,10 @@ class PortabilityMetadata {
61
152
  registry.set(metadata, entry);
62
153
  return entry;
63
154
  }
64
- static read(model) {
65
- const object = ReferenceError.suppress(model[Symbol.metadata], `Required an implementation of Symbol.metadata in '${model.name}' to use portability`);
66
- const metadata = PortabilityMetadata.for(object);
67
- const fields = metadata.#fields;
68
- let current = object;
69
- while (true) {
70
- if (current === null)
71
- break;
72
- for (const [key, descriptor] of PortabilityMetadata.for(current).#fields)
73
- fields.add(key, descriptor);
74
- current = Object.getPrototypeOf(current);
75
- }
76
- return metadata;
77
- }
78
- static descendantsOf(model) {
79
- if (!Object.hasOwn(model, Symbol.metadata))
80
- return [];
81
- const object = model[Symbol.metadata];
82
- if (object === null || object === undefined)
83
- return [];
84
- return PortabilityMetadata.for(object).#descendants;
85
- }
86
- get fields() {
87
- return this.#fields;
88
- }
89
- get descendants() {
90
- return this.#descendants;
91
- }
92
- get discriminator() {
93
- return this.#discriminator;
94
- }
95
- set discriminator(value) {
96
- this.#discriminator = value;
97
- }
155
+ get fields() { return this.#fields; }
156
+ get descendants() { return this.#descendants; }
157
+ get discriminator() { return this.#discriminator; }
158
+ set discriminator(value) { this.#discriminator = value; }
98
159
  }
99
160
  //#endregion
100
161
  //#region Model
@@ -110,89 +171,28 @@ export class Model {
110
171
  * @throws {TypeError} If validation fails or types do not match.
111
172
  */
112
173
  static import(source, name) {
113
- const model = this;
114
- const descendants = PortabilityMetadata.descendantsOf(model);
115
- if (descendants.length > 0) {
116
- const { discriminator: key } = PortabilityMetadata.read(model);
117
- const object = Object.import(source, name);
118
- const value = Reflect.get(object, key);
119
- if (value === undefined)
120
- throw new TypeError(`Missing '${key}' discriminator in ${name}`);
121
- const discriminator = String.import(value, `${name}.${key}`);
122
- const descriptor = descendants.find(descriptor => descriptor.discriminator === discriminator);
123
- if (descriptor === undefined)
124
- throw new TypeError(`Unknown '${discriminator}' discriminator for ${name}`);
125
- return descriptor.type.import(source, name);
126
- }
127
- const object = Object.import(source, name);
128
- const instance = Reflect.construct(this, []);
129
- const { fields } = PortabilityMetadata.read(model);
130
- for (const { key, association, type } of fields.values()) {
131
- const raw = Reflect.get(object, association);
132
- const value = type.import(raw, `${name}.${association}`);
133
- Reflect.set(instance, key, value);
134
- }
135
- return instance;
174
+ return ModelSchema.resolve(this).import(source, name);
136
175
  }
137
176
  /**
138
177
  * Serializes the model instance to a raw object.
139
178
  * @param source The model instance to export.
140
179
  */
141
180
  static export(source) {
142
- const model = this;
143
- const descendants = PortabilityMetadata.descendantsOf(model);
144
- if (descendants.length > 0) {
145
- const { discriminator: key } = PortabilityMetadata.read(model);
146
- const descriptor = descendants.find(descriptor => source instanceof descriptor.type);
147
- if (descriptor === undefined)
148
- throw new TypeError(`Invalid '${typename(source)}' type for source`);
149
- const descendant = descriptor.type;
150
- const exported = descendant.export(source);
151
- Reflect.set(exported, key, descriptor.discriminator);
152
- return exported;
153
- }
154
- const object = new Object();
155
- const { fields } = PortabilityMetadata.read(model);
156
- for (const { key, association, type } of fields.values()) {
157
- const value = Reflect.get(source, key);
158
- const raw = type.export(value);
159
- Reflect.set(object, association, raw);
160
- }
161
- return object;
181
+ return ModelSchema.resolve(this).export(source);
162
182
  }
163
183
  }
164
- export function Field(type, name) {
184
+ export function Field(type, options = {}) {
165
185
  return function (_, context) {
166
186
  if (context.static)
167
187
  throw new TypeError("Portable fields cannot be static");
168
188
  const key = context.name;
169
189
  if (typeof (key) === "symbol")
170
190
  throw new TypeError("Symbols are not supported as portable keys");
171
- const association = name ?? key;
172
191
  const { fields } = PortabilityMetadata.for(context.metadata);
173
192
  if (!fields.has(key))
174
- fields.set(key, new FieldDescriptor(key, association, type));
175
- };
176
- }
177
- export function Descendant(descendant, discriminator) {
178
- return function (model, context) {
179
- void model;
180
- const { descendants } = PortabilityMetadata.for(context.metadata);
181
- descendants.push(new DescendantDescriptor(descendant, discriminator));
182
- };
183
- }
184
- /**
185
- * Decorator to register a custom discriminator key for the polymorphic model.
186
- * @param key The property key to use for the discriminator.
187
- */
188
- export function DiscriminatorKey(key) {
189
- return function (model, context) {
190
- void model;
191
- PortabilityMetadata.for(context.metadata).discriminator = key;
193
+ fields.set(key, new FieldDescriptor(key, type, options));
192
194
  };
193
195
  }
194
- //#endregion
195
- //#region Adapters
196
196
  /**
197
197
  * Creates a wrapper for circular or deferred type references.
198
198
  * @param resolver Function that returns the actual type constructor.
@@ -213,224 +213,158 @@ export function Deferred(resolver) {
213
213
  },
214
214
  };
215
215
  }
216
- /**
217
- * Creates a portable wrapper for optional types.
218
- * @param type The inner portable type.
219
- */
220
- export function Optional(type) {
221
- return {
222
- [Symbol.hasInstance](instance) {
223
- return instance === undefined || type[Symbol.hasInstance](instance);
224
- },
225
- get name() {
226
- return `${type.name} | undefined`;
227
- },
228
- import(source, name) {
229
- return Reflect.mapUndefined(source, source => type.import(source, name));
230
- },
231
- export(source) {
232
- return Reflect.mapUndefined(source, source => type.export(source));
233
- },
234
- };
235
- }
236
- /**
237
- * Creates a portable wrapper for nullable types.
238
- * @param type The inner portable type.
239
- */
240
- export function Nullable(type) {
241
- return {
242
- [Symbol.hasInstance](instance) {
243
- return instance === null || type[Symbol.hasInstance](instance);
244
- },
245
- get name() {
246
- return `${type.name} | null`;
247
- },
248
- import(source, name) {
249
- return Reflect.mapNull(source, source => type.import(source, name));
250
- },
251
- export(source) {
252
- return Reflect.mapNull(source, source => type.export(source));
253
- },
254
- };
255
- }
256
- /**
257
- * Creates a portable wrapper for array types.
258
- * @param type The portable type of the array elements.
259
- */
260
- export function ArrayOf(type) {
261
- return {
262
- [Symbol.hasInstance](instance) {
263
- return Array[Symbol.hasInstance](instance);
264
- },
265
- get name() {
266
- return `${type.name}[]`;
267
- },
268
- import(source, name) {
269
- return Array.import(source, name).map((item, index) => type.import(item, `${name}[${index}]`));
270
- },
271
- export(source) {
272
- return source.map(item => type.export(item));
273
- },
216
+ export function Descendant(descendant, discriminator) {
217
+ return function (model, context) {
218
+ void model;
219
+ const { descendants } = PortabilityMetadata.for(context.metadata);
220
+ descendants.push(new DescendantDescriptor(descendant, discriminator));
274
221
  };
275
222
  }
276
223
  /**
277
- * Creates a portable wrapper for set types.
278
- * @param type The portable type of the set elements.
224
+ * Decorator to register a custom discriminator key for the polymorphic model.
225
+ * @param key The property key to use for the discriminator.
279
226
  */
280
- export function SetOf(type) {
281
- return {
282
- [Symbol.hasInstance](instance) {
283
- return Set[Symbol.hasInstance](instance);
284
- },
285
- get name() {
286
- return `Set<${type.name}>`;
287
- },
288
- import(source, name) {
289
- return new Set(Array.import(source, name).map((item, index) => type.import(item, `${name}[${index}]`)));
290
- },
291
- export(source) {
292
- return Array.from(source, item => type.export(item));
293
- },
227
+ export function DiscriminatorKey(key) {
228
+ return function (model, context) {
229
+ void model;
230
+ PortabilityMetadata.for(context.metadata).discriminator = key;
294
231
  };
295
232
  }
233
+ //#endregion
234
+ //#region Adapters
296
235
  /**
297
- * Creates a portable wrapper for maps with string keys, converting them to and from plain objects.
298
- * @param value The portable type of the map values.
236
+ * Portable adapter class for optional (possibly-undefined) types.
237
+ * Use `Optional.Of(type)` to wrap an adapter, and `Optional.map` for conditional mapping.
299
238
  */
300
- export function RecordOf(type) {
301
- return {
302
- [Symbol.hasInstance](instance) {
303
- return Map[Symbol.hasInstance](instance);
304
- },
305
- get name() {
306
- return `Map<string, ${type.name}>`;
307
- },
308
- import(source, name) {
309
- const record = Object.import(source, name);
310
- const map = new Map();
311
- for (const key of Object.keys(record)) {
312
- map.set(key, type.import(Reflect.get(record, key), `${name}[${JSON.stringify(key)}]`));
313
- }
314
- return map;
315
- },
316
- export(source) {
317
- const record = {};
318
- for (const [key, value] of source) {
319
- Reflect.set(record, key, type.export(value));
320
- }
321
- return record;
322
- },
323
- };
239
+ export class Optional {
240
+ constructor() {
241
+ throw new TypeError("Unable to create an instance of a static class");
242
+ }
243
+ /**
244
+ * Creates a portable wrapper for optional types.
245
+ * @param type The inner portable type.
246
+ */
247
+ static Of(type) {
248
+ return {
249
+ [Symbol.hasInstance](instance) {
250
+ return type[Symbol.hasInstance](instance);
251
+ },
252
+ get name() {
253
+ return `${type.name} | undefined`;
254
+ },
255
+ import(source, name) {
256
+ return Optional.map(source, source => type.import(source, name));
257
+ },
258
+ export(source) {
259
+ return Optional.map(source, source => type.export(source));
260
+ },
261
+ };
262
+ }
263
+ /**
264
+ * Applies a callback to a non-undefined value, or passes through `undefined` unchanged.
265
+ * @param value The value to map.
266
+ * @param callback The function to apply if the value is not undefined.
267
+ */
268
+ static map(value, callback) {
269
+ if (value === undefined)
270
+ return value;
271
+ return callback(value);
272
+ }
324
273
  }
325
274
  /**
326
- * Creates a portable wrapper for maps with arbitrary key and value types, converting them to and from arrays of `[key, value]` tuples.
327
- * @param key The portable type of the map keys.
328
- * @param value The portable type of the map values.
275
+ * Portable adapter class for nullable (possibly-null) types.
276
+ * Use `Nullable.Of(type)` to wrap an adapter, and `Nullable.map` for conditional mapping.
329
277
  */
330
- export function MapOf(typeKey, typeValue) {
331
- return {
332
- [Symbol.hasInstance](instance) {
333
- return Map[Symbol.hasInstance](instance);
334
- },
335
- get name() {
336
- return `Map<${typeKey.name}, ${typeValue.name}>`;
337
- },
338
- import(source, name) {
339
- return new Map(Array.import(source, name).map((item, index) => {
340
- const tuple = Array.import(item, `${name}[${index}]`);
341
- const key = typeKey.import(tuple[0], `${name}[${index}][0]`);
342
- const value = typeValue.import(tuple[1], `${name}[${index}][1]`);
343
- return [key, value];
344
- }));
345
- },
346
- export(source) {
347
- return Array.from(source, ([key, value]) => [typeKey.export(key), typeValue.export(value)]);
348
- },
349
- };
278
+ export class Nullable {
279
+ constructor() {
280
+ throw new TypeError("Unable to create an instance of a static class");
281
+ }
282
+ /**
283
+ * Creates a portable wrapper for nullable types.
284
+ * @param type The inner portable type.
285
+ */
286
+ static Of(type) {
287
+ return {
288
+ [Symbol.hasInstance](instance) {
289
+ return type[Symbol.hasInstance](instance);
290
+ },
291
+ get name() {
292
+ return `${type.name} | null`;
293
+ },
294
+ import(source, name) {
295
+ return Nullable.map(source, source => type.import(source, name));
296
+ },
297
+ export(source) {
298
+ return Nullable.map(source, source => type.export(source));
299
+ },
300
+ };
301
+ }
302
+ /**
303
+ * Applies a callback to a non-null value, or passes through `null` unchanged.
304
+ * @param value The value to map.
305
+ * @param callback The function to apply if the value is not null.
306
+ */
307
+ static map(value, callback) {
308
+ if (value === null)
309
+ return value;
310
+ return callback(value);
311
+ }
350
312
  }
351
313
  /**
352
- * Creates a portable wrapper for enum types, strictly operating only on enum values.
353
- * @param reference The enum object reference.
314
+ * Portable adapter class for enum types.
315
+ * Use `Enum.Of(reference)` to create an adapter that validates against enum values.
354
316
  */
355
- export function EnumAs(reference) {
356
- const values = new Set();
357
- for (const [key, value] of Object.entries(reference)) {
358
- const index = Number(key);
359
- if (String(index) === key && typeof value === "string" && Reflect.get(reference, value) === index)
360
- continue;
361
- values.add(value);
317
+ export class Enum {
318
+ constructor() {
319
+ throw new TypeError("Unable to create an instance of a static class");
320
+ }
321
+ /**
322
+ * Creates a portable wrapper for enum types, strictly operating only on enum values.
323
+ * @param reference The enum object reference.
324
+ */
325
+ static Of(reference) {
326
+ const values = new Set();
327
+ for (const [key, value] of Object.entries(reference)) {
328
+ const index = Number(key);
329
+ if (String(index) === key && typeof value === "string" && Reflect.get(reference, value) === index)
330
+ continue;
331
+ values.add(value);
332
+ }
333
+ return {
334
+ [Symbol.hasInstance](instance) {
335
+ return values.has(instance);
336
+ },
337
+ get name() {
338
+ return "Enum";
339
+ },
340
+ import(source, name) {
341
+ if (!values.has(source))
342
+ throw new TypeError(`Unable to import enum from ${name} due to invalid value`);
343
+ return source;
344
+ },
345
+ export(source) {
346
+ return source;
347
+ },
348
+ };
362
349
  }
363
- return {
364
- [Symbol.hasInstance](instance) {
365
- return values.has(instance);
366
- },
367
- get name() {
368
- return "Enum";
369
- },
370
- import(source, name) {
371
- if (!values.has(source))
372
- throw new TypeError(`Unable to import enum from ${name} due to invalid value`);
373
- return source;
374
- },
375
- export(source) {
376
- return source;
377
- },
378
- };
379
350
  }
380
351
  /**
381
- * A portable adapter that facilitates the conversion between `Date` instances and millisecond timestamps.
382
- */
383
- export const Timestamp = {
384
- [Symbol.hasInstance](instance) {
385
- return Date[Symbol.hasInstance](instance);
386
- },
387
- get name() {
388
- return "Timestamp";
389
- },
390
- import(source, name) {
391
- if (typeof (source) !== "number")
392
- throw new TypeError(`Unable to import date from ${name} due its ${typename(source)} type`);
393
- return new Date(source);
394
- },
395
- export(source) {
396
- return source.getTime();
397
- },
398
- };
399
- /**
400
- * A portable adapter that facilitates the conversion between `Date` instances and Unix second timestamps.
401
- */
402
- export const UnixSeconds = {
403
- [Symbol.hasInstance](instance) {
404
- return Date[Symbol.hasInstance](instance);
405
- },
406
- get name() {
407
- return "UnixSeconds";
408
- },
409
- import(source, name) {
410
- if (typeof (source) !== "number")
411
- throw new TypeError(`Unable to import date from ${name} due its ${typename(source)} type`);
412
- return new Date(source * 1000);
413
- },
414
- export(source) {
415
- return Math.trunc(source.getTime() / 1000);
416
- },
417
- };
418
- /**
419
- * A portable adapter that allows any value to pass through without validation or transformation.
352
+ * Portable adapter class for unknown/any types.
353
+ * Pass `Any` directly to `@Field` to allow any value without validation or transformation.
420
354
  */
421
- export const Any = {
422
- [Symbol.hasInstance](instance) {
355
+ export class Any {
356
+ constructor() {
357
+ throw new TypeError("Unable to create an instance of a static class");
358
+ }
359
+ static [Symbol.hasInstance](instance) {
423
360
  void instance;
424
361
  return true;
425
- },
426
- get name() {
427
- return "Any";
428
- },
429
- import(source, name) {
362
+ }
363
+ static import(source, name) {
430
364
  void name;
431
365
  return source;
432
- },
433
- export(source) {
366
+ }
367
+ static export(source) {
434
368
  return source;
435
- },
436
- };
369
+ }
370
+ }
@@ -1,17 +1,2 @@
1
1
  "use strict";
2
- Reflect.mapNull = function (value, callback) {
3
- if (value === null)
4
- return value;
5
- return callback(value);
6
- };
7
- Reflect.mapUndefined = function (value, callback) {
8
- if (value === undefined)
9
- return value;
10
- return callback(value);
11
- };
12
- Reflect.mapNullable = function (value, callback) {
13
- if (value === null || value === undefined)
14
- return value;
15
- return callback(value);
16
- };
17
2
  export {};
package/dist/core/set.js CHANGED
@@ -1,4 +1,21 @@
1
1
  "use strict";
2
+ import {} from "./portable.js";
3
+ Set.Of = function (type) {
4
+ return {
5
+ [Symbol.hasInstance](instance) {
6
+ return Set[Symbol.hasInstance](instance);
7
+ },
8
+ get name() {
9
+ return `Set<${type.name}>`;
10
+ },
11
+ import(source, name) {
12
+ return new Set(Array.import(source, name).map((item, index) => type.import(item, `${name}[${index}]`)));
13
+ },
14
+ export(source) {
15
+ return Array.from(source, item => type.export(item));
16
+ },
17
+ };
18
+ };
2
19
  Set.prototype.toggle = function (value, force) {
3
20
  if (force === undefined) {
4
21
  if (this.has(value)) {
@@ -15,4 +32,3 @@ Set.prototype.toggle = function (value, force) {
15
32
  this.delete(value);
16
33
  return false;
17
34
  };
18
- export {};
@@ -1,23 +1,26 @@
1
1
  "use strict";
2
2
  import "../core/index.js";
3
3
  import {} from "../core/index.js";
4
- //#region Archive
4
+ //#region Cell
5
5
  /**
6
- * Low-level interface for persistent data storage.
7
- * Handles direct serialization and retrieval from the platform's local storage.
6
+ * Low-level interface for a single keyed entry in a {@link Storage} backend.
7
+ * Handles direct serialization and retrieval of raw data.
8
8
  */
9
- class Archive {
9
+ export class Cell {
10
+ #storage;
10
11
  #key;
11
12
  /**
13
+ * @param storage The underlying storage backend.
12
14
  * @param key Unique storage identifier.
13
- * @param initial Default value used if no data exists at the specified key.
15
+ * @param initial Default value written if no data exists at the specified key.
14
16
  */
15
- constructor(key, initial) {
17
+ constructor(storage, key, initial) {
18
+ this.#storage = storage;
16
19
  this.#key = key;
17
20
  this.#initialize(initial);
18
21
  }
19
22
  #initialize(value) {
20
- if (localStorage.getItem(this.#key) !== null)
23
+ if (this.#storage.getItem(this.#key) !== null)
21
24
  return;
22
25
  this.data = value;
23
26
  }
@@ -26,7 +29,7 @@ class Archive {
26
29
  return JSON.stringify(value);
27
30
  }
28
31
  catch {
29
- throw new SyntaxError(`Archive [${key}]: Serialization failed.`);
32
+ throw new SyntaxError(`Cell [${key}]: Serialization failed.`);
30
33
  }
31
34
  }
32
35
  static #decompress(key, text) {
@@ -34,7 +37,7 @@ class Archive {
34
37
  return JSON.parse(text);
35
38
  }
36
39
  catch {
37
- throw new SyntaxError(`Archive [${key}]: Data corrupted.`);
40
+ throw new SyntaxError(`Cell [${key}]: Data corrupted.`);
38
41
  }
39
42
  }
40
43
  /**
@@ -49,10 +52,10 @@ class Archive {
49
52
  * @throws {SyntaxError} If the data is corrupted and cannot be parsed.
50
53
  */
51
54
  get data() {
52
- const text = localStorage.getItem(this.#key);
55
+ const text = this.#storage.getItem(this.#key);
53
56
  if (text === null)
54
- throw new ReferenceError(`Archive [${this.#key}]: Entry not found.`);
55
- return Archive.#decompress(this.#key, text);
57
+ throw new ReferenceError(`Cell [${this.#key}]: Entry not found.`);
58
+ return Cell.#decompress(this.#key, text);
56
59
  }
57
60
  /**
58
61
  * Overwrites the raw data in the underlying storage.
@@ -60,28 +63,29 @@ class Archive {
60
63
  * @throws {SyntaxError} If the value cannot be serialized.
61
64
  */
62
65
  set data(value) {
63
- const text = Archive.#compress(this.#key, value);
64
- localStorage.setItem(this.#key, text);
66
+ const text = Cell.#compress(this.#key, value);
67
+ this.#storage.setItem(this.#key, text);
65
68
  }
66
69
  }
67
70
  //#endregion
68
- //#region Archive manager
71
+ //#region Portable cell
69
72
  /**
70
73
  * Orchestrates the lifecycle and state-to-model mapping for a specific data type.
71
74
  */
72
- export class ArchiveManager {
73
- #archive;
75
+ export class PortableCell {
76
+ #cell;
74
77
  #model;
75
78
  #initial;
76
79
  /**
80
+ * @param storage The underlying storage backend.
77
81
  * @param key Unique storage identifier.
78
82
  * @param model Constructor with import/export capabilities.
79
83
  * @param instance Baseline object state for initialization and resets.
80
84
  * @throws {TypeError} If the provided instance is incompatible with the model schema.
81
85
  */
82
- constructor(key, model, instance) {
83
- const scheme = ArchiveManager.#ensureCompatibility(key, model, instance);
84
- this.#archive = new Archive(key, scheme);
86
+ constructor(storage, key, model, instance) {
87
+ const scheme = PortableCell.#ensureCompatibility(key, model, instance);
88
+ this.#cell = new Cell(storage, key, scheme);
85
89
  this.#model = model;
86
90
  this.#initial = scheme;
87
91
  }
@@ -95,14 +99,14 @@ export class ArchiveManager {
95
99
  }
96
100
  catch (reason) {
97
101
  const { message } = Error.from(reason);
98
- throw new TypeError(`Archive [${key}]: Schema validation failed: ${message}`);
102
+ throw new TypeError(`PortableCell [${key}]: Schema validation failed: ${message}`);
99
103
  }
100
104
  }
101
105
  /**
102
106
  * The storage identifier managed by this instance.
103
107
  */
104
108
  get key() {
105
- return this.#archive.key;
109
+ return this.#cell.key;
106
110
  }
107
111
  /**
108
112
  * Deserializes and reconstructs the model instance from the storage.
@@ -110,12 +114,12 @@ export class ArchiveManager {
110
114
  */
111
115
  get content() {
112
116
  try {
113
- return this.#model.import(this.#archive.data, this.#archive.key);
117
+ return this.#model.import(this.#cell.data, this.#cell.key);
114
118
  }
115
119
  catch (error) {
116
120
  if (!(error instanceof TypeError))
117
121
  throw error;
118
- throw new SyntaxError(`Archive [${this.#archive.key}]: Content restoration failed.`);
122
+ throw new SyntaxError(`PortableCell [${this.#cell.key}]: Content restoration failed.`);
119
123
  }
120
124
  }
121
125
  /**
@@ -124,17 +128,17 @@ export class ArchiveManager {
124
128
  * @throws {SyntaxError} If the instance state cannot be serialized.
125
129
  */
126
130
  set content(value) {
127
- this.#archive.data = this.#model.export(value);
131
+ this.#cell.data = this.#model.export(value);
128
132
  }
129
133
  /**
130
134
  * Reverts the storage to the original state provided at construction.
131
135
  */
132
136
  reset() {
133
- this.#archive.data = this.#initial;
137
+ this.#cell.data = this.#initial;
134
138
  }
135
139
  }
136
140
  //#endregion
137
- //#region Archive repository
141
+ //#region Buffered cell
138
142
  class SaveTransaction {
139
143
  #idTimeout;
140
144
  #resolve;
@@ -144,14 +148,14 @@ class SaveTransaction {
144
148
  this.#resolve = resolve;
145
149
  this.#reject = reject;
146
150
  }
147
- cancel(reason) {
151
+ cancel() {
148
152
  clearTimeout(this.#idTimeout);
149
- this.#reject(new DOMException(reason, "AbortError"));
153
+ this.#resolve(false);
150
154
  }
151
155
  settle(callback) {
152
156
  try {
153
- const result = callback();
154
- this.#resolve(result);
157
+ callback();
158
+ this.#resolve(true);
155
159
  }
156
160
  catch (reason) {
157
161
  this.#reject(Error.from(reason));
@@ -159,20 +163,21 @@ class SaveTransaction {
159
163
  }
160
164
  }
161
165
  /**
162
- * A high-level repository providing buffered access to persistent data with auto-save management.
166
+ * A high-level cell providing buffered access to persistent data with auto-save management.
163
167
  */
164
- export class ArchiveRepository {
165
- #manager;
168
+ export class BufferedCell {
169
+ #cell;
166
170
  #content;
167
171
  #transaction = null;
168
172
  /**
173
+ * @param storage The underlying storage backend.
169
174
  * @param key Unique storage identifier.
170
175
  * @param model Constructor for state transformation.
171
176
  * @param instance Initial state template.
172
177
  */
173
- constructor(key, model, instance) {
174
- this.#manager = new ArchiveManager(key, model, instance);
175
- this.#content = this.#manager.content;
178
+ constructor(storage, key, model, instance) {
179
+ this.#cell = new PortableCell(storage, key, model, instance);
180
+ this.#content = this.#cell.content;
176
181
  this.#initializeUnloadHandler();
177
182
  }
178
183
  #initializeUnloadHandler() {
@@ -187,7 +192,7 @@ export class ArchiveRepository {
187
192
  * The unique storage identifier.
188
193
  */
189
194
  get key() {
190
- return this.#manager.key;
195
+ return this.#cell.key;
191
196
  }
192
197
  /**
193
198
  * Retrieves the in-memory instance of the content.
@@ -200,22 +205,23 @@ export class ArchiveRepository {
200
205
  const transaction = this.#transaction;
201
206
  this.#transaction = null;
202
207
  transaction?.settle(() => {
203
- this.#manager.content = this.#content;
208
+ this.#cell.content = this.#content;
204
209
  });
205
210
  }
206
211
  async save(delay) {
207
212
  const transaction = this.#transaction;
208
- transaction?.cancel("Save superseded by a subsequent call.");
213
+ transaction?.cancel();
209
214
  return await new Promise((resolve, reject) => {
210
215
  this.#transaction = new SaveTransaction(this.#handler.bind(this), delay, resolve, reject);
211
216
  });
212
217
  }
213
218
  /**
214
219
  * Cancels any scheduled save operations.
220
+ * Any pending {@linkcode save} promise resolves to `false`.
215
221
  */
216
222
  abort() {
217
223
  const transaction = this.#transaction;
218
- transaction?.cancel("Save operation explicitly aborted.");
224
+ transaction?.cancel();
219
225
  this.#transaction = null;
220
226
  }
221
227
  /**
@@ -223,8 +229,17 @@ export class ArchiveRepository {
223
229
  */
224
230
  reset() {
225
231
  this.abort();
226
- const manager = this.#manager;
227
- manager.reset();
228
- this.#content = manager.content;
232
+ const cell = this.#cell;
233
+ cell.reset();
234
+ this.#content = cell.content;
229
235
  }
230
236
  }
237
+ Storage.prototype.openCell = function (key, initial) {
238
+ return new Cell(this, key, initial);
239
+ };
240
+ Storage.prototype.openPortableCell = function (key, model, instance) {
241
+ return new PortableCell(this, key, model, instance);
242
+ };
243
+ Storage.prototype.openBufferedCell = function (key, model, instance) {
244
+ return new BufferedCell(this, key, model, instance);
245
+ };
@@ -34,7 +34,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
34
34
  return useValue ? value : void 0;
35
35
  };
36
36
  import "adaptive-extender/web";
37
- import { Model, Field, Optional, ArrayOf, DiscriminatorKey, Descendant, Deferred } from "adaptive-extender/web";
37
+ import { Model, Field, Optional, DiscriminatorKey, Descendant, Deferred } from "adaptive-extender/web";
38
38
  //#region URL adapter
39
39
  const URLAdapter = {
40
40
  [Symbol.hasInstance](instance) {
@@ -80,12 +80,12 @@ let Metadata = (() => {
80
80
  static { _classThis = this; }
81
81
  static {
82
82
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
83
- _context_decorators = [Field(String, "@context")];
84
- _name_decorators = [Field(String, "name")];
85
- _webpage_decorators = [Field(URLAdapter, "url")];
86
- _preview_decorators = [Field(Optional(URLAdapter), "image")];
87
- _description_decorators = [Field(Optional(String), "description")];
88
- _keywords_decorators = [Field(Optional(ArrayOf(String)), "keywords")];
83
+ _context_decorators = [Field(String, { name: "@context" })];
84
+ _name_decorators = [Field(String, { name: "name" })];
85
+ _webpage_decorators = [Field(URLAdapter, { name: "url" })];
86
+ _preview_decorators = [Field(Optional.Of(URLAdapter), { name: "image" })];
87
+ _description_decorators = [Field(Optional.Of(String), { name: "description" })];
88
+ _keywords_decorators = [Field(Optional.Of(Array.Of(String)), { name: "keywords" })];
89
89
  __esDecorate(null, null, _context_decorators, { kind: "field", name: "context", static: false, private: false, access: { has: obj => "context" in obj, get: obj => obj.context, set: (obj, value) => { obj.context = value; } }, metadata: _metadata }, _context_initializers, _context_extraInitializers);
90
90
  __esDecorate(null, null, _name_decorators, { kind: "field", name: "name", static: false, private: false, access: { has: obj => "name" in obj, get: obj => obj.name, set: (obj, value) => { obj.name = value; } }, metadata: _metadata }, _name_initializers, _name_extraInitializers);
91
91
  __esDecorate(null, null, _webpage_decorators, { kind: "field", name: "webpage", static: false, private: false, access: { has: obj => "webpage" in obj, get: obj => obj.webpage, set: (obj, value) => { obj.webpage = value; } }, metadata: _metadata }, _webpage_initializers, _webpage_extraInitializers);
@@ -135,9 +135,9 @@ let PersonMetadata = (() => {
135
135
  return class PersonMetadata extends _classSuper {
136
136
  static {
137
137
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
138
- _associations_decorators = [Field(Optional(ArrayOf(URLAdapter)), "sameAs")];
139
- _job_decorators = [Field(Optional(String), "jobTitle")];
140
- _knowledge_decorators = [Field(Optional(ArrayOf(String)), "knowsAbout")];
138
+ _associations_decorators = [Field(Optional.Of(Array.Of(URLAdapter)), { name: "sameAs" })];
139
+ _job_decorators = [Field(Optional.Of(String), { name: "jobTitle" })];
140
+ _knowledge_decorators = [Field(Optional.Of(Array.Of(String)), { name: "knowsAbout" })];
141
141
  __esDecorate(null, null, _associations_decorators, { kind: "field", name: "associations", static: false, private: false, access: { has: obj => "associations" in obj, get: obj => obj.associations, set: (obj, value) => { obj.associations = value; } }, metadata: _metadata }, _associations_initializers, _associations_extraInitializers);
142
142
  __esDecorate(null, null, _job_decorators, { kind: "field", name: "job", static: false, private: false, access: { has: obj => "job" in obj, get: obj => obj.job, set: (obj, value) => { obj.job = value; } }, metadata: _metadata }, _job_initializers, _job_extraInitializers);
143
143
  __esDecorate(null, null, _knowledge_decorators, { kind: "field", name: "knowledge", static: false, private: false, access: { has: obj => "knowledge" in obj, get: obj => obj.knowledge, set: (obj, value) => { obj.knowledge = value; } }, metadata: _metadata }, _knowledge_initializers, _knowledge_extraInitializers);
@@ -173,9 +173,9 @@ let ApplicationMetadata = (() => {
173
173
  return class ApplicationMetadata extends _classSuper {
174
174
  static {
175
175
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
176
- _category_decorators = [Field(String, "applicationCategory")];
177
- _os_decorators = [Field(String, "operatingSystem")];
178
- _version_decorators = [Field(Optional(String), "softwareVersion")];
176
+ _category_decorators = [Field(String, { name: "applicationCategory" })];
177
+ _os_decorators = [Field(String, { name: "operatingSystem" })];
178
+ _version_decorators = [Field(Optional.Of(String), { name: "softwareVersion" })];
179
179
  __esDecorate(null, null, _category_decorators, { kind: "field", name: "category", static: false, private: false, access: { has: obj => "category" in obj, get: obj => obj.category, set: (obj, value) => { obj.category = value; } }, metadata: _metadata }, _category_initializers, _category_extraInitializers);
180
180
  __esDecorate(null, null, _os_decorators, { kind: "field", name: "os", static: false, private: false, access: { has: obj => "os" in obj, get: obj => obj.os, set: (obj, value) => { obj.os = value; } }, metadata: _metadata }, _os_initializers, _os_extraInitializers);
181
181
  __esDecorate(null, null, _version_decorators, { kind: "field", name: "version", static: false, private: false, access: { has: obj => "version" in obj, get: obj => obj.version, set: (obj, value) => { obj.version = value; } }, metadata: _metadata }, _version_initializers, _version_extraInitializers);
@@ -211,9 +211,9 @@ let OrganizationMetadata = (() => {
211
211
  return class OrganizationMetadata extends _classSuper {
212
212
  static {
213
213
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
214
- _logo_decorators = [Field(Optional(URLAdapter), "logo")];
215
- _email_decorators = [Field(Optional(String), "email")];
216
- _foundation_decorators = [Field(Optional(Date), "foundingDate")];
214
+ _logo_decorators = [Field(Optional.Of(URLAdapter), { name: "logo" })];
215
+ _email_decorators = [Field(Optional.Of(String), { name: "email" })];
216
+ _foundation_decorators = [Field(Optional.Of(Date), { name: "foundingDate" })];
217
217
  __esDecorate(null, null, _logo_decorators, { kind: "field", name: "logo", static: false, private: false, access: { has: obj => "logo" in obj, get: obj => obj.logo, set: (obj, value) => { obj.logo = value; } }, metadata: _metadata }, _logo_initializers, _logo_extraInitializers);
218
218
  __esDecorate(null, null, _email_decorators, { kind: "field", name: "email", static: false, private: false, access: { has: obj => "email" in obj, get: obj => obj.email, set: (obj, value) => { obj.email = value; } }, metadata: _metadata }, _email_initializers, _email_extraInitializers);
219
219
  __esDecorate(null, null, _foundation_decorators, { kind: "field", name: "foundation", static: false, private: false, access: { has: obj => "foundation" in obj, get: obj => obj.foundation, set: (obj, value) => { obj.foundation = value; } }, metadata: _metadata }, _foundation_initializers, _foundation_extraInitializers);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adaptive-extender",
3
- "version": "0.10.5",
3
+ "version": "0.11.0",
4
4
  "description": "Adaptive library for JS/TS development environments",
5
5
  "type": "module",
6
6
  "main": "./dist/core/index.js",
@@ -57,6 +57,7 @@
57
57
  "build:web": "tsc -p ./src/web/tsconfig.json",
58
58
  "build:worker": "tsc -p ./src/worker/tsconfig.json",
59
59
  "build": "npm run build:core && npm run build:node && npm run build:web && npm run build:worker",
60
+ "prepublishOnly": "npm run build",
60
61
  "test": "npm run build & vitest run",
61
62
  "coverage": "vitest run --coverage"
62
63
  },