@jskit-ai/kernel 0.1.8 → 0.1.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/kernel",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "typebox": "^1.0.81"
@@ -32,6 +32,10 @@
32
32
  "./shared/support": "./shared/support/index.js",
33
33
  "./shared/support/tokens": "./shared/support/tokens.js",
34
34
  "./shared/support/normalize": "./shared/support/normalize.js",
35
+ "./shared/support/permissions": "./shared/support/permissions.js",
36
+ "./shared/support/deepFreeze": "./shared/support/deepFreeze.js",
37
+ "./shared/support/listenerSet": "./shared/support/listenerSet.js",
38
+ "./shared/support/providerLogger": "./shared/support/providerLogger.js",
35
39
  "./shared/support/returnToPath": "./shared/support/returnToPath.js",
36
40
  "./shared/support/visibility": "./shared/support/visibility.js",
37
41
  "./shared/support/linkPath": "./shared/support/linkPath.js",
@@ -1,4 +1,5 @@
1
1
  import { Check, Errors, Parse } from "typebox/value";
2
+ import { deepFreeze } from "../../shared/support/deepFreeze.js";
2
3
  import { normalizeObject, normalizeText } from "../../shared/support/normalize.js";
3
4
 
4
5
  function normalizeModuleId(value) {
@@ -71,23 +72,6 @@ function buildInvalidConfigMessage(moduleId, issues = []) {
71
72
  return `Invalid config for module "${moduleId}": ${summary}`;
72
73
  }
73
74
 
74
- function deepFreeze(value, seen = new WeakSet()) {
75
- if (!value || typeof value !== "object") {
76
- return value;
77
- }
78
-
79
- if (seen.has(value)) {
80
- return value;
81
- }
82
- seen.add(value);
83
-
84
- for (const key of Object.getOwnPropertyNames(value)) {
85
- deepFreeze(value[key], seen);
86
- }
87
-
88
- return Object.freeze(value);
89
- }
90
-
91
75
  function normalizeCustomValidationIssues(result) {
92
76
  if (result == null || result === true) {
93
77
  return [];
@@ -1,10 +1,6 @@
1
1
  import { normalizeRequestMeta } from "./requestMeta.js";
2
2
  import { normalizeLowerText, normalizeText } from "./textNormalization.js";
3
-
4
- function normalizePermissions(value) {
5
- const source = Array.isArray(value) ? value : [];
6
- return Array.from(new Set(source.map((entry) => normalizeText(entry)).filter(Boolean)));
7
- }
3
+ import { normalizePermissionList } from "../support/permissions.js";
8
4
 
9
5
  function copyRecord(value) {
10
6
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -31,10 +27,6 @@ function normalizeActor(actor) {
31
27
  return source;
32
28
  }
33
29
 
34
- function normalizeMembership(membership) {
35
- return copyRecord(membership);
36
- }
37
-
38
30
  function normalizeTimeMeta(timeMeta) {
39
31
  const source = timeMeta && typeof timeMeta === "object" ? timeMeta : {};
40
32
  const nowValue = source.now instanceof Date ? source.now : new Date();
@@ -48,7 +40,6 @@ function normalizeTimeMeta(timeMeta) {
48
40
 
49
41
  const RESERVED_CONTEXT_KEYS = new Set([
50
42
  "actor",
51
- "membership",
52
43
  "permissions",
53
44
  "surface",
54
45
  "channel",
@@ -74,8 +65,7 @@ function normalizeExecutionContext(context = {}) {
74
65
  return Object.freeze({
75
66
  ...passthrough,
76
67
  actor: normalizeActor(source.actor),
77
- membership: normalizeMembership(source.membership),
78
- permissions: normalizePermissions(source.permissions),
68
+ permissions: normalizePermissionList(source.permissions),
79
69
  surface: normalizeLowerText(source.surface),
80
70
  channel: normalizeLowerText(source.channel) || "internal",
81
71
  requestMeta: normalizeRequestMeta(source.requestMeta),
@@ -86,10 +76,9 @@ function normalizeExecutionContext(context = {}) {
86
76
  const __testables = {
87
77
  normalizeText,
88
78
  normalizeLowerText,
89
- normalizePermissions,
79
+ normalizePermissions: normalizePermissionList,
90
80
  copyRecord,
91
81
  normalizeActor,
92
- normalizeMembership,
93
82
  normalizeRequestMeta,
94
83
  normalizeTimeMeta
95
84
  };
@@ -0,0 +1,18 @@
1
+ function deepFreeze(value, seen = new WeakSet()) {
2
+ if (!value || typeof value !== "object") {
3
+ return value;
4
+ }
5
+
6
+ if (seen.has(value)) {
7
+ return value;
8
+ }
9
+ seen.add(value);
10
+
11
+ for (const key of Object.getOwnPropertyNames(value)) {
12
+ deepFreeze(value[key], seen);
13
+ }
14
+
15
+ return Object.freeze(value);
16
+ }
17
+
18
+ export { deepFreeze };
@@ -0,0 +1,26 @@
1
+ function subscribeListener(listeners, listener) {
2
+ if (!(listeners instanceof Set)) {
3
+ throw new TypeError("subscribeListener requires a Set.");
4
+ }
5
+
6
+ if (typeof listener !== "function") {
7
+ return () => {};
8
+ }
9
+
10
+ listeners.add(listener);
11
+ return () => {
12
+ listeners.delete(listener);
13
+ };
14
+ }
15
+
16
+ function createListenerSubscription(listeners) {
17
+ if (!(listeners instanceof Set)) {
18
+ throw new TypeError("createListenerSubscription requires a Set.");
19
+ }
20
+
21
+ return function subscribe(listener) {
22
+ return subscribeListener(listeners, listener);
23
+ };
24
+ }
25
+
26
+ export { subscribeListener, createListenerSubscription };
@@ -29,6 +29,11 @@ function normalizeArray(value) {
29
29
  return Array.isArray(value) ? value : [];
30
30
  }
31
31
 
32
+ function normalizeUniqueTextList(value, { acceptSingle = false } = {}) {
33
+ const source = Array.isArray(value) ? value : acceptSingle ? [value] : [];
34
+ return Array.from(new Set(source.map((entry) => normalizeText(entry)).filter(Boolean)));
35
+ }
36
+
32
37
  function normalizeInteger(value, { fallback = 0, min = null, max = null } = {}) {
33
38
  const numeric = Number(value);
34
39
  if (!Number.isFinite(numeric)) {
@@ -108,6 +113,7 @@ export {
108
113
  normalizeObject,
109
114
  isRecord,
110
115
  normalizeArray,
116
+ normalizeUniqueTextList,
111
117
  normalizeInteger,
112
118
  normalizePositiveInteger,
113
119
  normalizeOpaqueId,
@@ -4,7 +4,8 @@ import {
4
4
  normalizeOpaqueId,
5
5
  normalizePositiveInteger,
6
6
  normalizeOneOf,
7
- normalizeQueryToken
7
+ normalizeQueryToken,
8
+ normalizeUniqueTextList
8
9
  } from "./normalize.js";
9
10
 
10
11
  test("normalizeQueryToken trims, lowercases, and falls back when empty", () => {
@@ -46,3 +47,14 @@ test("normalizeOpaqueId preserves opaque identifiers", () => {
46
47
  assert.equal(normalizeOpaqueId(""), null);
47
48
  assert.equal(normalizeOpaqueId(null), null);
48
49
  });
50
+
51
+ test("normalizeUniqueTextList trims, dedupes, and supports optional single values", () => {
52
+ assert.deepEqual(normalizeUniqueTextList([" one ", "two", "one", "", null]), ["one", "two"]);
53
+ assert.deepEqual(normalizeUniqueTextList("one"), []);
54
+ assert.deepEqual(
55
+ normalizeUniqueTextList(" one ", {
56
+ acceptSingle: true
57
+ }),
58
+ ["one"]
59
+ );
60
+ });
@@ -0,0 +1,42 @@
1
+ function asLogger(value) {
2
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3
+ return null;
4
+ }
5
+ return value;
6
+ }
7
+
8
+ function callLoggerMethod(logger, methodName, fallbackMethodName, args) {
9
+ if (logger && typeof logger[methodName] === "function") {
10
+ logger[methodName](...args);
11
+ return;
12
+ }
13
+
14
+ if (typeof console[fallbackMethodName] === "function") {
15
+ console[fallbackMethodName](...args);
16
+ }
17
+ }
18
+
19
+ function createProviderLogger(loggerLike = null, { debugEnabled = false, debugMethod = "info" } = {}) {
20
+ const logger = asLogger(loggerLike);
21
+ const resolvedDebugMethod = String(debugMethod || "info").trim() || "info";
22
+
23
+ return Object.freeze({
24
+ debug: (...args) => {
25
+ if (debugEnabled !== true) {
26
+ return;
27
+ }
28
+ callLoggerMethod(logger, resolvedDebugMethod, "info", args);
29
+ },
30
+ info: (...args) => {
31
+ callLoggerMethod(logger, "info", "info", args);
32
+ },
33
+ warn: (...args) => {
34
+ callLoggerMethod(logger, "warn", "warn", args);
35
+ },
36
+ error: (...args) => {
37
+ callLoggerMethod(logger, "error", "error", args);
38
+ }
39
+ });
40
+ }
41
+
42
+ export { createProviderLogger };
@@ -1,4 +1,4 @@
1
- import { normalizeOpaqueId, normalizeText } from "./normalize.js";
1
+ import { normalizeObject, normalizeOpaqueId, normalizeText } from "./normalize.js";
2
2
  import { ROUTE_VISIBILITY_PUBLIC, ROUTE_VISIBILITY_USER } from "./policies.js";
3
3
 
4
4
  const ROUTE_VISIBILITY_LEVELS = Object.freeze([ROUTE_VISIBILITY_PUBLIC, ROUTE_VISIBILITY_USER]);
@@ -40,7 +40,7 @@ function normalizeVisibilityScopeKind(value) {
40
40
  }
41
41
 
42
42
  function normalizeVisibilityContext(value = {}) {
43
- const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
43
+ const source = normalizeObject(value);
44
44
  const normalizedVisibility = normalizeRouteVisibilityToken(source.visibility);
45
45
  const normalizedScopeKind = normalizeVisibilityScopeKind(source.scopeKind);
46
46
 
@@ -1,3 +1,5 @@
1
+ import { normalizeObject } from "../support/normalize.js";
2
+
1
3
  function normalizeSurfaceId(value) {
2
4
  return String(value || "")
3
5
  .trim()
@@ -59,7 +61,7 @@ function createSurfaceRegistry(options = {}) {
59
61
 
60
62
  const normalizedEntries = Object.entries(rawSurfaces)
61
63
  .map(([key, value]) => {
62
- const sourceDefinition = value && typeof value === "object" && !Array.isArray(value) ? value : {};
64
+ const sourceDefinition = normalizeObject(value);
63
65
  const normalizedId = normalizeSurfaceId(sourceDefinition.id || key);
64
66
  if (!normalizedId) {
65
67
  return null;
@@ -5,6 +5,7 @@ export { mergeObjectSchemas } from "./mergeObjectSchemas.js";
5
5
  export { mergeValidators } from "./mergeValidators.js";
6
6
  export { nestValidator } from "./nestValidator.js";
7
7
  export { recordIdParamsValidator, positiveIntegerValidator } from "./recordIdParamsValidator.js";
8
+ export { normalizeSettingsFieldInput, normalizeSettingsFieldOutput } from "./settingsFieldNormalization.js";
8
9
  export {
9
10
  normalizeRequiredFieldList,
10
11
  deriveRequiredFieldsFromSchema,
@@ -0,0 +1,40 @@
1
+ import { normalizeObjectInput } from "./inputNormalization.js";
2
+
3
+ function normalizeSettingsFieldInput(payload = {}, fields = []) {
4
+ const source = normalizeObjectInput(payload);
5
+ const normalized = {};
6
+
7
+ for (const field of Array.isArray(fields) ? fields : []) {
8
+ if (!Object.hasOwn(source, field.key)) {
9
+ continue;
10
+ }
11
+ normalized[field.key] = field.normalizeInput(source[field.key], {
12
+ payload: source
13
+ });
14
+ }
15
+
16
+ return normalized;
17
+ }
18
+
19
+ function normalizeSettingsFieldOutput(payload = {}, fields = []) {
20
+ const settingsSource = normalizeObjectInput(payload);
21
+ const normalized = {};
22
+
23
+ for (const field of Array.isArray(fields) ? fields : []) {
24
+ const rawValue = Object.hasOwn(settingsSource, field.key)
25
+ ? settingsSource[field.key]
26
+ : field.resolveDefault({
27
+ settings: settingsSource
28
+ });
29
+ normalized[field.key] = field.normalizeOutput(rawValue, {
30
+ settings: settingsSource
31
+ });
32
+ }
33
+
34
+ return normalized;
35
+ }
36
+
37
+ export {
38
+ normalizeSettingsFieldInput,
39
+ normalizeSettingsFieldOutput
40
+ };