@character-foundry/character-foundry 0.4.1 → 0.4.2-dev.1765997746

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.
Files changed (57) hide show
  1. package/dist/charx.cjs +17 -38
  2. package/dist/charx.cjs.map +1 -1
  3. package/dist/charx.d.cts +27 -18
  4. package/dist/charx.d.ts +27 -18
  5. package/dist/charx.js +17 -38
  6. package/dist/charx.js.map +1 -1
  7. package/dist/exporter.cjs +36 -40
  8. package/dist/exporter.cjs.map +1 -1
  9. package/dist/exporter.d.cts +27 -18
  10. package/dist/exporter.d.ts +27 -18
  11. package/dist/exporter.js +36 -40
  12. package/dist/exporter.js.map +1 -1
  13. package/dist/federation.cjs +104 -36
  14. package/dist/federation.cjs.map +1 -1
  15. package/dist/federation.d.cts +62 -18
  16. package/dist/federation.d.ts +62 -18
  17. package/dist/federation.js +104 -36
  18. package/dist/federation.js.map +1 -1
  19. package/dist/index.cjs +36 -40
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +63 -42
  22. package/dist/index.d.ts +63 -42
  23. package/dist/index.js +36 -40
  24. package/dist/index.js.map +1 -1
  25. package/dist/loader.cjs +103 -17
  26. package/dist/loader.cjs.map +1 -1
  27. package/dist/loader.d.cts +56 -28
  28. package/dist/loader.d.ts +56 -28
  29. package/dist/loader.js +103 -17
  30. package/dist/loader.js.map +1 -1
  31. package/dist/lorebook.d.cts +51 -34
  32. package/dist/lorebook.d.ts +51 -34
  33. package/dist/normalizer.cjs +4 -4
  34. package/dist/normalizer.cjs.map +1 -1
  35. package/dist/normalizer.d.cts +90 -60
  36. package/dist/normalizer.d.ts +90 -60
  37. package/dist/normalizer.js +4 -4
  38. package/dist/normalizer.js.map +1 -1
  39. package/dist/png.cjs +4 -4
  40. package/dist/png.cjs.map +1 -1
  41. package/dist/png.d.cts +48 -32
  42. package/dist/png.d.ts +48 -32
  43. package/dist/png.js +4 -4
  44. package/dist/png.js.map +1 -1
  45. package/dist/schemas.cjs +9 -9
  46. package/dist/schemas.cjs.map +1 -1
  47. package/dist/schemas.d.cts +144 -96
  48. package/dist/schemas.d.ts +144 -96
  49. package/dist/schemas.js +9 -9
  50. package/dist/schemas.js.map +1 -1
  51. package/dist/voxta.cjs +23 -6
  52. package/dist/voxta.cjs.map +1 -1
  53. package/dist/voxta.d.cts +42 -28
  54. package/dist/voxta.d.ts +42 -28
  55. package/dist/voxta.js +23 -6
  56. package/dist/voxta.js.map +1 -1
  57. package/package.json +6 -6
@@ -44,6 +44,50 @@ function generateUUID() {
44
44
  }
45
45
 
46
46
  // ../federation/dist/index.js
47
+ var LEVELS = {
48
+ silent: 0,
49
+ error: 1,
50
+ warn: 2,
51
+ info: 3,
52
+ debug: 4
53
+ };
54
+ var noop = () => {
55
+ };
56
+ function createConsoleLogger(level = "warn") {
57
+ const severity = LEVELS[level] ?? LEVELS.warn;
58
+ const hasConsole = typeof console !== "undefined";
59
+ const c = hasConsole ? console : void 0;
60
+ const debugImpl = c?.debug ? c.debug.bind(c) : c?.log ? c.log.bind(c) : noop;
61
+ const infoImpl = c?.info ? c.info.bind(c) : c?.log ? c.log.bind(c) : noop;
62
+ const warnImpl = c?.warn ? c.warn.bind(c) : c?.log ? c.log.bind(c) : noop;
63
+ const errorImpl = c?.error ? c.error.bind(c) : c?.log ? c.log.bind(c) : noop;
64
+ return {
65
+ debug: severity >= LEVELS.debug ? debugImpl : noop,
66
+ info: severity >= LEVELS.info ? infoImpl : noop,
67
+ warn: severity >= LEVELS.warn ? warnImpl : noop,
68
+ error: severity >= LEVELS.error ? errorImpl : noop
69
+ };
70
+ }
71
+ var federationLogger = createConsoleLogger("warn");
72
+ function getLogger() {
73
+ return federationLogger;
74
+ }
75
+ function setLogger(logger) {
76
+ federationLogger = logger;
77
+ }
78
+ function setLogLevel(level) {
79
+ federationLogger = createConsoleLogger(level);
80
+ }
81
+ function configureLogger(options) {
82
+ if (!options) return;
83
+ if (options.logger) {
84
+ setLogger(options.logger);
85
+ return;
86
+ }
87
+ if (options.logLevel) {
88
+ setLogLevel(options.logLevel);
89
+ }
90
+ }
47
91
  var ACTIVITY_CONTEXT = [
48
92
  "https://www.w3.org/ns/activitystreams",
49
93
  {
@@ -402,7 +446,7 @@ var SyncEngine = class {
402
446
  try {
403
447
  listener(event);
404
448
  } catch (err) {
405
- console.error(`Event listener error:`, err);
449
+ getLogger().error("[federation] Event listener error:", err);
406
450
  }
407
451
  }
408
452
  }
@@ -1531,7 +1575,7 @@ var HttpPlatformAdapter = class extends BasePlatformAdapter {
1531
1575
  const data = await response.json();
1532
1576
  return this.config.transformers?.get ? this.config.transformers.get(data) : data;
1533
1577
  } catch (err) {
1534
- console.error(`Failed to get card ${localId}:`, err);
1578
+ getLogger().error(`[federation] Failed to get card ${localId}:`, err);
1535
1579
  return null;
1536
1580
  }
1537
1581
  }
@@ -2083,27 +2127,14 @@ function parseSignatureHeader(header) {
2083
2127
  return {
2084
2128
  keyId: params.keyId,
2085
2129
  algorithm: params.algorithm || "rsa-sha256",
2086
- headers: (params.headers || "(request-target) host date").split(" "),
2130
+ headers: (params.headers || "(request-target) host date").trim().split(/\s+/).filter(Boolean).map((h) => h.toLowerCase()),
2087
2131
  signature: params.signature
2088
2132
  };
2089
2133
  }
2090
2134
  function buildSigningString(method, path, headers, headerNames) {
2091
2135
  const result = buildSigningStringStrict(method, path, headers, headerNames);
2092
2136
  if (!result.success) {
2093
- console.warn(`[federation] Signature verification may fail: ${result.error}`);
2094
- const lines = [];
2095
- for (const name of headerNames) {
2096
- if (name === "(request-target)") {
2097
- lines.push(`(request-target): ${method.toLowerCase()} ${path}`);
2098
- } else if (name === "(created)" || name === "(expires)") {
2099
- } else {
2100
- const value = headers.get(name);
2101
- if (value !== null) {
2102
- lines.push(`${name.toLowerCase()}: ${value}`);
2103
- }
2104
- }
2105
- }
2106
- return lines.join("\n");
2137
+ throw new Error(result.error);
2107
2138
  }
2108
2139
  return result.signingString;
2109
2140
  }
@@ -2112,16 +2143,17 @@ function buildSigningStringStrict(method, path, headers, headerNames) {
2112
2143
  const missingHeaders = [];
2113
2144
  const syntheticHeaders = /* @__PURE__ */ new Set(["(request-target)", "(created)", "(expires)"]);
2114
2145
  for (const name of headerNames) {
2115
- if (name === "(request-target)") {
2146
+ const normalizedName = name.toLowerCase();
2147
+ if (normalizedName === "(request-target)") {
2116
2148
  lines.push(`(request-target): ${method.toLowerCase()} ${path}`);
2117
- } else if (name === "(created)") {
2118
- } else if (name === "(expires)") {
2149
+ } else if (normalizedName === "(created)") {
2150
+ } else if (normalizedName === "(expires)") {
2119
2151
  } else {
2120
- const value = headers.get(name);
2152
+ const value = headers.get(normalizedName);
2121
2153
  if (value !== null) {
2122
- lines.push(`${name.toLowerCase()}: ${value}`);
2123
- } else if (!syntheticHeaders.has(name)) {
2124
- missingHeaders.push(name);
2154
+ lines.push(`${normalizedName}: ${value}`);
2155
+ } else if (!syntheticHeaders.has(normalizedName)) {
2156
+ missingHeaders.push(normalizedName);
2125
2157
  }
2126
2158
  }
2127
2159
  }
@@ -2142,7 +2174,7 @@ async function verifyHttpSignature(parsed, publicKeyPem, method, path, headers,
2142
2174
  if (options.strictHeaders) {
2143
2175
  const strictResult = buildSigningStringStrict(method, path, headers, parsed.headers);
2144
2176
  if (!strictResult.success) {
2145
- console.warn(`[federation] Strict header verification failed: ${strictResult.error}`);
2177
+ getLogger().warn(`[federation] Strict header verification failed: ${strictResult.error}`);
2146
2178
  return false;
2147
2179
  }
2148
2180
  }
@@ -2162,7 +2194,7 @@ async function verifyHttpSignature(parsed, publicKeyPem, method, path, headers,
2162
2194
  data
2163
2195
  );
2164
2196
  } catch (error) {
2165
- console.error("Signature verification failed:", error);
2197
+ getLogger().error("[federation] Signature verification failed:", error);
2166
2198
  return false;
2167
2199
  }
2168
2200
  }
@@ -2300,7 +2332,7 @@ async function importPublicKey(pem) {
2300
2332
  ["verify"]
2301
2333
  );
2302
2334
  } catch (error) {
2303
- console.error("Failed to import public key:", error);
2335
+ getLogger().error("[federation] Failed to import public key:", error);
2304
2336
  return null;
2305
2337
  }
2306
2338
  }
@@ -2316,7 +2348,7 @@ async function importPrivateKey(pem) {
2316
2348
  ["sign"]
2317
2349
  );
2318
2350
  } catch (error) {
2319
- console.error("Failed to import private key:", error);
2351
+ getLogger().error("[federation] Failed to import private key:", error);
2320
2352
  return null;
2321
2353
  }
2322
2354
  }
@@ -2345,9 +2377,31 @@ function extractHostFromActorId(actorId) {
2345
2377
  return null;
2346
2378
  }
2347
2379
  }
2380
+ function timingSafeEqualString(a, b) {
2381
+ let mismatch = a.length === b.length ? 0 : 1;
2382
+ const maxLen = Math.max(a.length, b.length);
2383
+ for (let i = 0; i < maxLen; i++) {
2384
+ const aCode = a.charCodeAt(i) || 0;
2385
+ const bCode = b.charCodeAt(i) || 0;
2386
+ mismatch |= aCode ^ bCode;
2387
+ }
2388
+ return mismatch === 0;
2389
+ }
2348
2390
  async function handleInbox(body, headers, options) {
2349
2391
  assertFederationEnabled("handleInbox");
2350
2392
  try {
2393
+ const normalizedHeaders = headers instanceof Headers ? headers : new Headers(headers);
2394
+ const networkKey = typeof options.networkKey === "string" ? options.networkKey : void 0;
2395
+ const networkKeyHeader = options.networkKeyHeader ?? "X-Foundry-Network-Key";
2396
+ if (networkKey && networkKey.length > 0) {
2397
+ const provided = normalizedHeaders.get(networkKeyHeader);
2398
+ if (!provided || !timingSafeEqualString(provided, networkKey)) {
2399
+ return {
2400
+ accepted: false,
2401
+ error: "Unauthorized: invalid or missing network key"
2402
+ };
2403
+ }
2404
+ }
2351
2405
  if (options.moderationStore) {
2352
2406
  const actorId = typeof body === "object" && body !== null && "actor" in body ? String(body.actor) : null;
2353
2407
  if (actorId) {
@@ -2370,7 +2424,7 @@ async function handleInbox(body, headers, options) {
2370
2424
  };
2371
2425
  }
2372
2426
  if (options.strictMode) {
2373
- const signatureHeader = headers instanceof Headers ? headers.get("signature") : headers["signature"] || headers["Signature"];
2427
+ const signatureHeader = normalizedHeaders.get("signature");
2374
2428
  if (!signatureHeader) {
2375
2429
  return {
2376
2430
  accepted: false,
@@ -2384,6 +2438,15 @@ async function handleInbox(body, headers, options) {
2384
2438
  error: "Invalid Signature header format"
2385
2439
  };
2386
2440
  }
2441
+ if (networkKey && networkKey.length > 0) {
2442
+ const requiredSigned = networkKeyHeader.toLowerCase();
2443
+ if (!parsedSig.headers.includes(requiredSigned)) {
2444
+ return {
2445
+ accepted: false,
2446
+ error: `Strict mode: signature missing required header: ${requiredSigned}`
2447
+ };
2448
+ }
2449
+ }
2387
2450
  const missingSignedHeaders = REQUIRED_SIGNED_HEADERS.filter(
2388
2451
  (h) => !parsedSig.headers.includes(h)
2389
2452
  );
@@ -2393,14 +2456,14 @@ async function handleInbox(body, headers, options) {
2393
2456
  error: `Strict mode: signature missing required headers: ${missingSignedHeaders.join(", ")}`
2394
2457
  };
2395
2458
  }
2396
- const dateHeader = headers instanceof Headers ? headers.get("date") : headers["date"] || headers["Date"];
2459
+ const dateHeader = normalizedHeaders.get("date");
2397
2460
  if (!dateHeader) {
2398
2461
  return {
2399
2462
  accepted: false,
2400
2463
  error: "Strict mode: Date header required"
2401
2464
  };
2402
2465
  }
2403
- const hostHeader = headers instanceof Headers ? headers.get("host") : headers["host"] || headers["Host"];
2466
+ const hostHeader = normalizedHeaders.get("host");
2404
2467
  if (!hostHeader) {
2405
2468
  return {
2406
2469
  accepted: false,
@@ -2443,7 +2506,7 @@ async function handleInbox(body, headers, options) {
2443
2506
  error: `Invalid key ID or actor URL`
2444
2507
  };
2445
2508
  }
2446
- const digestHeader = headers instanceof Headers ? headers.get("digest") : headers["digest"] || headers["Digest"];
2509
+ const digestHeader = normalizedHeaders.get("digest");
2447
2510
  if (digestHeader) {
2448
2511
  if (!options.rawBody) {
2449
2512
  return {
@@ -2474,13 +2537,13 @@ async function handleInbox(body, headers, options) {
2474
2537
  }
2475
2538
  const method = options.method || "POST";
2476
2539
  const path = options.path || "/inbox";
2477
- const normalizedHeaders = headers instanceof Headers ? headers : new Headers(headers);
2478
2540
  const isValid = await verifyHttpSignature(
2479
2541
  parsedSig,
2480
2542
  actor.publicKey.publicKeyPem,
2481
2543
  method,
2482
2544
  path,
2483
- normalizedHeaders
2545
+ normalizedHeaders,
2546
+ { strictHeaders: true }
2484
2547
  );
2485
2548
  if (!isValid) {
2486
2549
  return {
@@ -3559,7 +3622,7 @@ var PolicyEngine = class {
3559
3622
  if (!regex) {
3560
3623
  const safetyWarning = checkRegexSafety(rule.pattern);
3561
3624
  if (safetyWarning) {
3562
- console.warn(`[moderation] Rule "${rule.name}": ${safetyWarning}`);
3625
+ getLogger().warn(`[moderation] Rule "${rule.name}": ${safetyWarning}`);
3563
3626
  }
3564
3627
  try {
3565
3628
  regex = new RegExp(rule.pattern, "i");
@@ -3799,11 +3862,12 @@ function getEnvVar(name) {
3799
3862
  return void 0;
3800
3863
  }
3801
3864
  function enableFederation(options) {
3865
+ configureLogger(options);
3802
3866
  explicitlyEnabled = true;
3803
3867
  envCheckSkipped = options?.skipEnvCheck ?? false;
3804
3868
  const nodeEnv = getEnvVar("NODE_ENV");
3805
3869
  if (nodeEnv === "development" || nodeEnv === "test") {
3806
- console.warn(
3870
+ getLogger().warn(
3807
3871
  "[character-foundry/federation] Federation enabled. WARNING: Verify HTTP signatures in production. Do NOT use in production with untrusted inputs without signature validation."
3808
3872
  );
3809
3873
  }
@@ -3867,6 +3931,7 @@ export {
3867
3931
  createAnnounceActivity,
3868
3932
  createArchiveAdapter,
3869
3933
  createBlockActivity,
3934
+ createConsoleLogger,
3870
3935
  createCreateActivity,
3871
3936
  createDeleteActivity,
3872
3937
  createFlagActivity,
@@ -3881,6 +3946,7 @@ export {
3881
3946
  enableFederation,
3882
3947
  generateActivityId,
3883
3948
  generateCardId,
3949
+ getLogger as getFederationLogger,
3884
3950
  handleActor,
3885
3951
  handleInbox,
3886
3952
  handleNodeInfo,
@@ -3893,6 +3959,8 @@ export {
3893
3959
  parseForkActivity,
3894
3960
  parseInstallActivity,
3895
3961
  parseSignatureHeader,
3962
+ setLogLevel as setFederationLogLevel,
3963
+ setLogger as setFederationLogger,
3896
3964
  signRequest,
3897
3965
  stCharacterToCCv3,
3898
3966
  validateBlockActivity as validateBlockActivityFields,