sonamu 0.10.0 → 0.10.2
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/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +13 -22
- package/dist/api/websocket-helpers.js +1 -1
- package/dist/auth/audit-log/builders.d.ts.map +1 -1
- package/dist/auth/audit-log/builders.js +3 -1
- package/dist/auth/audit-log/client-ip.d.ts +3 -0
- package/dist/auth/audit-log/client-ip.d.ts.map +1 -0
- package/dist/auth/audit-log/client-ip.js +27 -0
- package/dist/auth/audit-log/events.d.ts +1 -0
- package/dist/auth/audit-log/events.d.ts.map +1 -1
- package/dist/auth/audit-log/events.js +1 -1
- package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
- package/dist/auth/audit-log-ingestor.js +8 -3
- package/dist/auth/better-auth-request.d.ts +3 -0
- package/dist/auth/better-auth-request.d.ts.map +1 -0
- package/dist/auth/better-auth-request.js +23 -0
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +3 -3
- package/dist/bin/cli.js +1 -1
- package/dist/entity/entity.js +1 -1
- package/dist/index.js +1 -1
- package/dist/migration/code-generation.js +1 -1
- package/dist/syncer/checksum.js +6 -13
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +4 -2
- package/dist/ui/api.js +1 -1
- package/package.json +3 -3
- package/src/api/sonamu.ts +14 -29
- package/src/auth/audit-log/builders.ts +3 -0
- package/src/auth/audit-log/client-ip.ts +38 -0
- package/src/auth/audit-log/events.ts +1 -0
- package/src/auth/audit-log-ingestor.ts +22 -15
- package/src/auth/better-auth-request.ts +20 -0
- package/src/bin/build-config.ts +3 -2
- package/src/skills/sonamu/puri.md +33 -0
- package/src/syncer/checksum.ts +7 -12
- package/src/testing/index.ts +1 -0
package/dist/syncer/checksum.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __esmMin } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { differenceWith, init_utils } from "../utils/utils.js";
|
|
2
3
|
import { globAsync, init_async_utils } from "../utils/async-utils.js";
|
|
3
4
|
import { exists, init_fs_utils } from "../utils/fs-utils.js";
|
|
4
|
-
import { differenceWith, init_utils } from "../utils/utils.js";
|
|
5
5
|
import { Sonamu, init_sonamu } from "../api/sonamu.js";
|
|
6
6
|
import { GLOB_EXCLUDE, getChecksumPatternGroupInAbsolutePath, init_file_patterns } from "./file-patterns.js";
|
|
7
7
|
import { isEqual } from "radashi";
|
|
@@ -67,17 +67,10 @@ async function saveChecksums(checksums) {
|
|
|
67
67
|
await writeFile(checksumFilePath, JSON.stringify(serialized, null, 2), "utf-8");
|
|
68
68
|
}
|
|
69
69
|
async function getChecksumOfFile(filePath) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
input.on("data", (chunk) => {
|
|
75
|
-
hash.update(chunk);
|
|
76
|
-
});
|
|
77
|
-
input.on("close", () => {
|
|
78
|
-
resolve(hash.digest("hex"));
|
|
79
|
-
});
|
|
80
|
-
});
|
|
70
|
+
const hash = crypto.createHash("sha1");
|
|
71
|
+
const input = createReadStream(filePath);
|
|
72
|
+
for await (const chunk of input) hash.update(chunk);
|
|
73
|
+
return hash.digest("hex");
|
|
81
74
|
}
|
|
82
75
|
var init_checksum = __esmMin((() => {
|
|
83
76
|
init_sonamu();
|
|
@@ -90,4 +83,4 @@ var init_checksum = __esmMin((() => {
|
|
|
90
83
|
init_checksum();
|
|
91
84
|
export { findChangedFilesUsingChecksums, init_checksum, renewChecksums };
|
|
92
85
|
|
|
93
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
86
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2tzdW0uanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N5bmNlci9jaGVja3N1bS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY3J5cHRvIGZyb20gXCJjcnlwdG9cIjtcbmltcG9ydCB7IGNyZWF0ZVJlYWRTdHJlYW0sIHR5cGUgUGF0aExpa2UgfSBmcm9tIFwiZnNcIjtcbmltcG9ydCB7IHJlYWRGaWxlLCB3cml0ZUZpbGUgfSBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5cbmltcG9ydCBlcXVhbCBmcm9tIFwiZmFzdC1kZWVwLWVxdWFsXCI7XG5pbXBvcnQgeyBpc0VxdWFsIH0gZnJvbSBcInJhZGFzaGlcIjtcblxuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB7IGdsb2JBc3luYyB9IGZyb20gXCIuLi91dGlscy9hc3luYy11dGlsc1wiO1xuaW1wb3J0IHsgZXhpc3RzIH0gZnJvbSBcIi4uL3V0aWxzL2ZzLXV0aWxzXCI7XG5pbXBvcnQgeyB0eXBlIEFic29sdXRlUGF0aCwgdHlwZSBBcHBSZWxhdGl2ZVBhdGggfSBmcm9tIFwiLi4vdXRpbHMvcGF0aC11dGlsc1wiO1xuaW1wb3J0IHsgZGlmZmVyZW5jZVdpdGggfSBmcm9tIFwiLi4vdXRpbHMvdXRpbHNcIjtcbmltcG9ydCB7IGdldENoZWNrc3VtUGF0dGVybkdyb3VwSW5BYnNvbHV0ZVBhdGgsIEdMT0JfRVhDTFVERSB9IGZyb20gXCIuL2ZpbGUtcGF0dGVybnNcIjtcblxudHlwZSBQYXRoQW5kQ2hlY2tzdW0gPSB7XG4gIHBhdGg6IEFic29sdXRlUGF0aDtcbiAgY2hlY2tzdW06IHN0cmluZztcbn07XG5cbi8qKlxuICog7LK07YGs7ISsIO2MjOydvOyXkCDsoIDsnqXrkJwg64K07Jqp6rO8IO2YhOyerCDsi6TsoJwg7YyM7J287J2YIOyytO2BrOyErOydhCDruYTqtZDtlZjsl6wg67OA6rK965CcIO2MjOydvOydhCDssL7sirXri4jri6QuXG4gKiBAcmV0dXJucyDrs4Dqsr3rkJwg7YyM7J28IOqyveuhnCDrsLDsl7QuIO2UhOuhnOygne2KuCDro6jtirjrtoDthLAg7Iqs656Y7Iuc66GcIOyLnOyeke2VqeuLiOuLpC4g7JiI7IucOiBcIi9zcmMvYXBwbGljYXRpb24vdXNlci91c2VyLm1vZGVsLnRzXCJcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZpbmRDaGFuZ2VkRmlsZXNVc2luZ0NoZWNrc3VtcygpOiBQcm9taXNlPEFic29sdXRlUGF0aFtdPiB7XG4gIGNvbnN0IGNhbGN1bGF0ZWRDaGVja3N1bXMgPSBhd2FpdCBnZXRDdXJyZW50Q2hlY2tzdW1zKCk7XG4gIGNvbnN0IHNhdmVkQ2hlY2tzdW1zID0gYXdhaXQgZ2V0UHJldmlvdXNDaGVja3N1bXMoKTtcblxuICBjb25zdCBpc1NhbWUgPSBlcXVhbChjYWxjdWxhdGVkQ2hlY2tzdW1zLCBzYXZlZENoZWNrc3Vtcyk7XG4gIGlmIChpc1NhbWUpIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICByZXR1cm4gZGlmZmVyZW5jZVdpdGgoY2FsY3VsYXRlZENoZWNrc3Vtcywgc2F2ZWRDaGVja3N1bXMsIGlzRXF1YWwpLm1hcCgocikgPT4gci5wYXRoKTtcbn1cblxuLyoqXG4gKiDssrTtgazshKzsnYQg6rCx7Iug7ZWp64uI64ukLlxuICog7ZiE7J6sIO2MjOydvOuTpOydmCDssrTtgazshKzsnYQg6rOE7IKw7ZW07IScIOq1rO2VnCDri6TsnYwsIOyytO2BrOyErCDtjIzsnbzsl5Ag7KCA7J6l65CcIOuCtOyaqeqzvCDri6TrpbTrqbQg7LK07YGs7ISsIO2MjOydvOydhCDqsLHsi6Dtlanri4jri6QuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZW5ld0NoZWNrc3VtcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgY2FsY3VsYXRlZENoZWNrc3VtcyA9IGF3YWl0IGdldEN1cnJlbnRDaGVja3N1bXMoKTtcbiAgY29uc3Qgc2F2ZWRDaGVja3N1bXMgPSBhd2FpdCBnZXRQcmV2aW91c0NoZWNrc3VtcygpO1xuXG4gIGNvbnN0IGlzU2FtZSA9IGVxdWFsKGNhbGN1bGF0ZWRDaGVja3N1bXMsIHNhdmVkQ2hlY2tzdW1zKTtcbiAgaWYgKGlzU2FtZSkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGF3YWl0IHNhdmVDaGVja3N1bXMoY2FsY3VsYXRlZENoZWNrc3Vtcyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEN1cnJlbnRDaGVja3N1bXMoKTogUHJvbWlzZTxQYXRoQW5kQ2hlY2tzdW1bXT4ge1xuICBjb25zdCBhbGxQYXRocyA9IChcbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIE9iamVjdC5lbnRyaWVzKGdldENoZWNrc3VtUGF0dGVybkdyb3VwSW5BYnNvbHV0ZVBhdGgoKSkubWFwKChbX2ZpbGVUeXBlLCBwYXR0ZXJuXSkgPT4ge1xuICAgICAgICByZXR1cm4gZ2xvYkFzeW5jKHBhdHRlcm4sIHsgZXhjbHVkZTogR0xPQl9FWENMVURFIH0pO1xuICAgICAgfSksXG4gICAgKVxuICApLmZsYXQoKTtcblxuICAvLyDrj5nsnbwg7YyM7J287J20IOyXrOufrCDtjKjthLTsl5Ag66ek7LmY65CgIOyImCDsnojsnLzrr4DroZwo7JiIOiBzZC5nZW5lcmF0ZWQudHPripQgZ2VuZXJhdGVk7JmAIHNkR2VuZXJhdGVk7JeQIOuqqOuRkCDrp6TsuZgpXG4gIC8vIOykkeuztSDsoJzqsbAg7ZuEIOyViOyglSDsoJXroKwuXG4gIGNvbnN0IGZpbGVQYXRocyA9IEFycmF5LmZyb20obmV3IFNldChhbGxQYXRocykpLnRvU29ydGVkKCkgYXMgQWJzb2x1dGVQYXRoW107XG5cbiAgcmV0dXJuIGF3YWl0IFByb21pc2UuYWxsKFxuICAgIGZpbGVQYXRocy5tYXAoYXN5bmMgKGZpbGVQYXRoKSA9PiB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBwYXRoOiBmaWxlUGF0aCxcbiAgICAgICAgY2hlY2tzdW06IGF3YWl0IGdldENoZWNrc3VtT2ZGaWxlKGZpbGVQYXRoKSxcbiAgICAgIH07XG4gICAgfSksXG4gICk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFByZXZpb3VzQ2hlY2tzdW1zKCk6IFByb21pc2U8UGF0aEFuZENoZWNrc3VtW10+IHtcbiAgY29uc3QgY2hlY2tzdW1GaWxlUGF0aCA9IGdldENoZWNrc3VtRmlsZVBhdGgoKTtcbiAgaWYgKCEoYXdhaXQgZXhpc3RzKGNoZWNrc3VtRmlsZVBhdGgpKSkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgY29uc3QgcHJldmlvdXNDaGVja3N1bXMgPSBKU09OLnBhcnNlKGF3YWl0IHJlYWRGaWxlKGNoZWNrc3VtRmlsZVBhdGgsIFwidXRmLThcIikpLm1hcChcbiAgICAgIChyOiB7IHBhdGg6IEFwcFJlbGF0aXZlUGF0aDsgY2hlY2tzdW06IHN0cmluZyB9KSA9PiAoe1xuICAgICAgICBwYXRoOiBwYXRoLmpvaW4oU29uYW11LmFwcFJvb3RQYXRoLCByLnBhdGgpLCAvLyDssrTtgazshKwg7YyM7J287JeQ7IScIOydveydhCDrlYw6IGFwcFJvb3Qg7IOB64yAIOqyveuhnCDihpIg7KCI64yAIOqyveuhnFxuICAgICAgICBjaGVja3N1bTogci5jaGVja3N1bSxcbiAgICAgIH0pLFxuICAgICkgYXMgUGF0aEFuZENoZWNrc3VtW107XG4gICAgcmV0dXJuIHByZXZpb3VzQ2hlY2tzdW1zO1xuICB9IGNhdGNoIChlKSB7XG4gICAgLy8g7LK07YGs7ISsIO2MjOydvOydtCDshpDsg4HrkJwg6rK97JqwIOu5iCDrsLDsl7Qg67CY7ZmYICjsoITssrQg7J6s64+Z6riw7ZmUIOycoOuPhClcbiAgICBjb25zb2xlLndhcm4oXG4gICAgICBg7LK07YGs7ISsIO2MjOydvCgke2NoZWNrc3VtRmlsZVBhdGh9KeydhCDtjIzsi7HtlZjripQg642wIOyLpO2MqO2WiOyKteuLiOuLpC4g7KCE7LK0IOyerOuPmeq4sO2ZlOulvCDsp4Ttlontlanri4jri6QuYCxcbiAgICAgIGUsXG4gICAgKTtcbiAgICByZXR1cm4gW107XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0Q2hlY2tzdW1GaWxlUGF0aCgpOiBBYnNvbHV0ZVBhdGgge1xuICByZXR1cm4gcGF0aC5qb2luKFNvbmFtdS5hcGlSb290UGF0aCwgXCJzb25hbXUubG9ja1wiKSBhcyBBYnNvbHV0ZVBhdGg7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNhdmVDaGVja3N1bXMoY2hlY2tzdW1zOiBQYXRoQW5kQ2hlY2tzdW1bXSk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBjaGVja3N1bUZpbGVQYXRoID0gZ2V0Q2hlY2tzdW1GaWxlUGF0aCgpO1xuICAvLyBhcHBSb290IOyDgeuMgCDqsr3roZzroZwg7KeB66Cs7ZmUICsg7JWM7YyM67KzIOyViOyglSDsoJXroKwgKFBSIGRpZmYg6rmo64GX7ZWY6rKMIOycoOyngClcbiAgY29uc3Qgc2VyaWFsaXplZCA9IGNoZWNrc3Vtc1xuICAgIC5tYXAoKHIpID0+ICh7XG4gICAgICBwYXRoOiBwYXRoLnJlbGF0aXZlKFNvbmFtdS5hcHBSb290UGF0aCwgci5wYXRoKSwgLy8g7LK07YGs7ISsIO2MjOydvOyXkCDsoIDsnqXtlaAg65WMOiDsoIjrjIAg6rK966GcIOKGkiBhcHBSb290IOyDgeuMgCDqsr3roZxcbiAgICAgIGNoZWNrc3VtOiByLmNoZWNrc3VtLFxuICAgIH0pKVxuICAgIC5zb3J0KChhLCBiKSA9PiBhLnBhdGgubG9jYWxlQ29tcGFyZShiLnBhdGgpKTtcbiAgYXdhaXQgd3JpdGVGaWxlKGNoZWNrc3VtRmlsZVBhdGgsIEpTT04uc3RyaW5naWZ5KHNlcmlhbGl6ZWQsIG51bGwsIDIpLCBcInV0Zi04XCIpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRDaGVja3N1bU9mRmlsZShmaWxlUGF0aDogUGF0aExpa2UpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBoYXNoID0gY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGExXCIpO1xuICBjb25zdCBpbnB1dCA9IGNyZWF0ZVJlYWRTdHJlYW0oZmlsZVBhdGgpO1xuICBmb3IgYXdhaXQgKGNvbnN0IGNodW5rIG9mIGlucHV0KSB7XG4gICAgaGFzaC51cGRhdGUoY2h1bmspO1xuICB9XG4gIHJldHVybiBoYXNoLmRpZ2VzdChcImhleFwiKTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7QUF3QkEsZUFBc0IsaUNBQTBEO0NBQzlFLE1BQU0sc0JBQXNCLE1BQU0sb0JBQW9CO0NBQ3RELE1BQU0saUJBQWlCLE1BQU0scUJBQXFCO0NBR2xELElBRGUsTUFBTSxxQkFBcUIsY0FDdEMsR0FDRixPQUFPLENBQUM7Q0FHVixPQUFPLGVBQWUscUJBQXFCLGdCQUFnQixPQUFPLENBQUMsQ0FBQyxLQUFLLE1BQU0sRUFBRSxJQUFJO0FBQ3ZGOzs7OztBQU1BLGVBQXNCLGlCQUFnQztDQUNwRCxNQUFNLHNCQUFzQixNQUFNLG9CQUFvQjtDQUl0RCxJQURlLE1BQU0scUJBQXFCLE1BRmIscUJBQXFCLENBRzlDLEdBQ0Y7Q0FHRixNQUFNLGNBQWMsbUJBQW1CO0FBQ3pDO0FBRUEsZUFBZSxzQkFBa0Q7Q0FDL0QsTUFBTSxZQUNKLE1BQU0sUUFBUSxJQUNaLE9BQU8sUUFBUSxzQ0FBc0MsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLFdBQVcsYUFBYTtFQUNwRixPQUFPLFVBQVUsU0FBUyxFQUFFLFNBQVMsYUFBYSxDQUFDO0NBQ3JELENBQUMsQ0FDSCxFQUFBLENBQ0EsS0FBSztDQUlQLE1BQU0sWUFBWSxNQUFNLEtBQUssSUFBSSxJQUFJLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUztDQUV6RCxPQUFPLE1BQU0sUUFBUSxJQUNuQixVQUFVLElBQUksT0FBTyxhQUFhO0VBQ2hDLE9BQU87R0FDTCxNQUFNO0dBQ04sVUFBVSxNQUFNLGtCQUFrQixRQUFRO0VBQzVDO0NBQ0YsQ0FBQyxDQUNIO0FBQ0Y7QUFFQSxlQUFlLHVCQUFtRDtDQUNoRSxNQUFNLG1CQUFtQixvQkFBb0I7Q0FDN0MsSUFBSSxDQUFFLE1BQU0sT0FBTyxnQkFBZ0IsR0FDakMsT0FBTyxDQUFDO0NBR1YsSUFBSTtFQU9GLE9BTjBCLEtBQUssTUFBTSxNQUFNLFNBQVMsa0JBQWtCLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FDN0UsT0FBb0Q7R0FDbkQsTUFBTSxLQUFLLEtBQUssT0FBTyxhQUFhLEVBQUUsSUFBSTtHQUMxQyxVQUFVLEVBQUU7RUFDZCxFQUVLO0NBQ1QsU0FBUyxHQUFHO0VBRVYsUUFBUSxLQUNOLFVBQVUsaUJBQWlCLG9DQUMzQixDQUNGO0VBQ0EsT0FBTyxDQUFDO0NBQ1Y7QUFDRjtBQUVBLFNBQVMsc0JBQW9DO0NBQzNDLE9BQU8sS0FBSyxLQUFLLE9BQU8sYUFBYSxhQUFhO0FBQ3BEO0FBRUEsZUFBZSxjQUFjLFdBQTZDO0NBQ3hFLE1BQU0sbUJBQW1CLG9CQUFvQjtDQUU3QyxNQUFNLGFBQWEsVUFDaEIsS0FBSyxPQUFPO0VBQ1gsTUFBTSxLQUFLLFNBQVMsT0FBTyxhQUFhLEVBQUUsSUFBSTtFQUM5QyxVQUFVLEVBQUU7Q0FDZCxFQUFFLENBQUMsQ0FDRixNQUFNLEdBQUcsTUFBTSxFQUFFLEtBQUssY0FBYyxFQUFFLElBQUksQ0FBQztDQUM5QyxNQUFNLFVBQVUsa0JBQWtCLEtBQUssVUFBVSxZQUFZLE1BQU0sQ0FBQyxHQUFHLE9BQU87QUFDaEY7QUFFQSxlQUFlLGtCQUFrQixVQUFxQztDQUNwRSxNQUFNLE9BQU8sT0FBTyxXQUFXLE1BQU07Q0FDckMsTUFBTSxRQUFRLGlCQUFpQixRQUFRO0NBQ3ZDLFdBQVcsTUFBTSxTQUFTLE9BQ3hCLEtBQUssT0FBTyxLQUFLO0NBRW5CLE9BQU8sS0FBSyxPQUFPLEtBQUs7QUFDMUI7O2FBbEhzQztrQkFDVTtlQUNOO1lBRUs7b0JBQ3NDIn0=
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
|
package/dist/testing/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createBetterAuthRequest, init_better_auth_request } from "../auth/better-auth-request.js";
|
|
1
2
|
import { FixtureManager, FixtureManagerClass, init_fixture_manager } from "./fixture-manager.js";
|
|
2
3
|
import { DataExplorer, init_data_explorer } from "./data-explorer.js";
|
|
3
4
|
import { FixtureGenerator, init_fixture_generator } from "./fixture-generator.js";
|
|
@@ -9,11 +10,12 @@ import { createGlobalSetup, setup } from "./global-setup.js";
|
|
|
9
10
|
import { NaiteVitestReporter } from "./naite-vitest-reporter.js";
|
|
10
11
|
import { getSonamuTestConfig } from "./vitest-helpers.js";
|
|
11
12
|
//#region src/testing/index.ts
|
|
13
|
+
init_better_auth_request();
|
|
12
14
|
init_data_explorer();
|
|
13
15
|
init_dev_vitest_manager();
|
|
14
16
|
init_fixture_generator();
|
|
15
17
|
init_fixture_manager();
|
|
16
18
|
//#endregion
|
|
17
|
-
export { DataExplorer, DevVitestManager, FixtureGenerator, FixtureManager, FixtureManagerClass, NaiteVitestReporter, ParallelDBManager, bootstrap, createFixtureLoader, createGlobalSetup, getSonamuTestConfig, runWithContext, runWithMockContext, setup, test, testAs };
|
|
19
|
+
export { DataExplorer, DevVitestManager, FixtureGenerator, FixtureManager, FixtureManagerClass, NaiteVitestReporter, ParallelDBManager, bootstrap, createBetterAuthRequest, createFixtureLoader, createGlobalSetup, getSonamuTestConfig, runWithContext, runWithMockContext, setup, test, testAs };
|
|
18
20
|
|
|
19
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
21
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3RpbmcvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgY3JlYXRlQmV0dGVyQXV0aFJlcXVlc3QgfSBmcm9tIFwiLi4vYXV0aC9iZXR0ZXItYXV0aC1yZXF1ZXN0XCI7XG5leHBvcnQgKiBmcm9tIFwiLi9ib290c3RyYXBcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2RhdGEtZXhwbG9yZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2Rldi12aXRlc3QtbWFuYWdlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vZml4dHVyZS1nZW5lcmF0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2ZpeHR1cmUtbG9hZGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9maXh0dXJlLW1hbmFnZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2dsb2JhbC1zZXR1cFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vbmFpdGUtdml0ZXN0LXJlcG9ydGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9wYXJhbGxlbC1kYi1tYW5hZ2VyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi92aXRlc3QtaGVscGVyc1wiO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7eUJBQXFFIn0=
|
package/dist/ui/api.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { __esmMin } from "../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { createKnexInstance, init_knex } from "../database/knex.js";
|
|
3
3
|
import { DB, init_db } from "../database/db.js";
|
|
4
|
+
import { init_utils, nonNullable } from "../utils/utils.js";
|
|
4
5
|
import { SD, init_sd } from "../dict/sd.js";
|
|
5
6
|
import { BadRequestException, ServiceUnavailableException, init_so_exceptions, isSoException } from "../exceptions/so-exceptions.js";
|
|
6
|
-
import { init_utils, nonNullable } from "../utils/utils.js";
|
|
7
7
|
import { Sonamu, init_sonamu } from "../api/sonamu.js";
|
|
8
8
|
import { BUILT_IN_TYPE_IDS, TemplateKey, init_types } from "../types/types.js";
|
|
9
9
|
import { EntityManager, init_entity_manager } from "../entity/entity-manager.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonamu",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "Sonamu — TypeScript Fullstack API Framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -129,10 +129,10 @@
|
|
|
129
129
|
"tsicli": "^1.0.5",
|
|
130
130
|
"vite": "8.0.16",
|
|
131
131
|
"vitest": "^4.1.9",
|
|
132
|
+
"@sonamu-kit/hmr-hook": "^0.5.1",
|
|
132
133
|
"@sonamu-kit/hmr-runner": "^0.2.0",
|
|
133
134
|
"@sonamu-kit/tasks": "^0.3.1",
|
|
134
|
-
"@sonamu-kit/ts-loader": "^2.2.0"
|
|
135
|
-
"@sonamu-kit/hmr-hook": "^0.5.1"
|
|
135
|
+
"@sonamu-kit/ts-loader": "^2.2.0"
|
|
136
136
|
},
|
|
137
137
|
"devDependencies": {
|
|
138
138
|
"@types/bcrypt": "^6",
|
package/src/api/sonamu.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { type WebSocket } from "ws";
|
|
|
15
15
|
import { type ZodObject } from "zod";
|
|
16
16
|
|
|
17
17
|
import { BASE_FIELD_MAPPINGS } from "../auth/better-auth-entities";
|
|
18
|
+
import { createBetterAuthRequest } from "../auth/better-auth-request";
|
|
18
19
|
import { applyCacheHeaders, CachePresets } from "../cache-control/cache-control";
|
|
19
20
|
import { type CacheControlConfig, type CacheControlRequest } from "../cache-control/types";
|
|
20
21
|
import { type CacheConfig, type CacheManager } from "../cache/types";
|
|
@@ -1115,12 +1116,6 @@ class SonamuClass {
|
|
|
1115
1116
|
traceContext = this.websocketRuntime.telemetryController.createConnectionContext({
|
|
1116
1117
|
headers: request.headers,
|
|
1117
1118
|
});
|
|
1118
|
-
runGuards({
|
|
1119
|
-
guards: api.options.guards,
|
|
1120
|
-
config,
|
|
1121
|
-
request,
|
|
1122
|
-
api,
|
|
1123
|
-
});
|
|
1124
1119
|
|
|
1125
1120
|
preRegisterPhase = "query";
|
|
1126
1121
|
const reqBody = await this.parseWebSocketRequestParams(api, request);
|
|
@@ -1139,6 +1134,16 @@ class SonamuClass {
|
|
|
1139
1134
|
|
|
1140
1135
|
const scopedWs = this.createScopedWebSocketConnection(rawWs, () => wsContext);
|
|
1141
1136
|
wsContext = await this.createWebSocketContext(config, request, scopedWs);
|
|
1137
|
+
|
|
1138
|
+
await this.asyncLocalStorage.run({ context: wsContext }, async () => {
|
|
1139
|
+
runGuards({
|
|
1140
|
+
guards: api.options.guards,
|
|
1141
|
+
config,
|
|
1142
|
+
request,
|
|
1143
|
+
api,
|
|
1144
|
+
});
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1142
1147
|
this.websocketRuntime.activateConnection(rawWs.id);
|
|
1143
1148
|
preRegisterPhase = "handler";
|
|
1144
1149
|
|
|
@@ -1801,29 +1806,9 @@ class SonamuClass {
|
|
|
1801
1806
|
method: ["GET", "POST"],
|
|
1802
1807
|
url: `${basePath}/*`,
|
|
1803
1808
|
handler: async (request, reply) => {
|
|
1804
|
-
const
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
// IP 헤더 fallback: 프록시가 표준 IP 헤더를 주입하지 않는 환경에서도
|
|
1808
|
-
// better-auth/infra의 getClientIpFromRequest()가 IP를 인식할 수 있도록
|
|
1809
|
-
// Fastify가 resolve한 request.ip를 x-real-ip로 주입한다.
|
|
1810
|
-
const IP_HEADERS = [
|
|
1811
|
-
"cf-connecting-ip",
|
|
1812
|
-
"x-forwarded-for",
|
|
1813
|
-
"x-real-ip",
|
|
1814
|
-
"x-vercel-forwarded-for",
|
|
1815
|
-
];
|
|
1816
|
-
if (request.ip && !IP_HEADERS.some((h) => headers.has(h))) {
|
|
1817
|
-
headers.set("x-real-ip", request.ip);
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
const req = new Request(url.toString(), {
|
|
1821
|
-
method: request.method,
|
|
1822
|
-
headers,
|
|
1823
|
-
...(request.body ? { body: JSON.stringify(request.body) } : {}),
|
|
1824
|
-
});
|
|
1825
|
-
|
|
1826
|
-
const response = await this.auth.handler(req);
|
|
1809
|
+
const response = await this.auth.handler(
|
|
1810
|
+
createBetterAuthRequest(request, options.advanced?.ipAddress?.ipAddressHeaders),
|
|
1811
|
+
);
|
|
1827
1812
|
|
|
1828
1813
|
reply.status(response.status);
|
|
1829
1814
|
response.headers.forEach((value: string, key: string) => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
type AccountSnapshot,
|
|
3
5
|
type AuditLogEvent,
|
|
@@ -24,6 +26,7 @@ const createEvent = (
|
|
|
24
26
|
location?: BuilderLocation,
|
|
25
27
|
): AuditLogEvent => ({
|
|
26
28
|
...base,
|
|
29
|
+
eventId: randomUUID(),
|
|
27
30
|
eventData: {
|
|
28
31
|
...data,
|
|
29
32
|
triggeredBy: trigger.triggeredBy,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
|
|
3
|
+
const CLIENT_IP_HEADERS = [
|
|
4
|
+
"cf-connecting-ip",
|
|
5
|
+
"x-forwarded-for",
|
|
6
|
+
"x-real-ip",
|
|
7
|
+
"x-vercel-forwarded-for",
|
|
8
|
+
] as const;
|
|
9
|
+
|
|
10
|
+
const HEADER_NAME_PATTERN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
11
|
+
|
|
12
|
+
export function replaceClientIpHeaders(
|
|
13
|
+
headers: Headers,
|
|
14
|
+
clientIp: string,
|
|
15
|
+
configuredHeaders: readonly string[] = [],
|
|
16
|
+
): void {
|
|
17
|
+
const candidates = new Set(
|
|
18
|
+
[...CLIENT_IP_HEADERS, ...configuredHeaders]
|
|
19
|
+
.map((header) => header.trim().toLowerCase())
|
|
20
|
+
.filter((header) => HEADER_NAME_PATTERN.test(header)),
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
for (const header of candidates) {
|
|
24
|
+
headers.delete(header);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for (const header of candidates) {
|
|
28
|
+
headers.set(header, clientIp);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getValidClientIp(value: unknown): string | null {
|
|
33
|
+
if (typeof value !== "string" || value.length > 45 || isIP(value) === 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
|
|
3
3
|
import { type Knex } from "knex";
|
|
4
4
|
|
|
5
|
+
import { getValidClientIp } from "./audit-log/client-ip";
|
|
5
6
|
import { type AuditLogEvent } from "./audit-log/events";
|
|
6
7
|
|
|
7
8
|
const AUDIT_EVENT_SOURCE = "better_auth";
|
|
@@ -137,6 +138,10 @@ function computeDedupeKey(parts: {
|
|
|
137
138
|
return createHash("sha256").update(raw).digest("hex");
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
function computeEventIdDedupeKey(source: string, eventId: string): string {
|
|
142
|
+
return createHash("sha256").update(`${source}|${eventId}`).digest("hex");
|
|
143
|
+
}
|
|
144
|
+
|
|
140
145
|
/**
|
|
141
146
|
* sonamuAuditLog 플러그인이 구성한 AuditLogEvent를 audit_events 테이블에 적재합니다.
|
|
142
147
|
* ON CONFLICT (dedupe_key) DO NOTHING으로 중복을 silent 무시합니다.
|
|
@@ -172,26 +177,28 @@ export async function ingestAuditEvent(db: Knex, event: AuditLogEvent): Promise<
|
|
|
172
177
|
const trigger_context = pickString(eventData, "triggerContext");
|
|
173
178
|
const user_agent = pickString(eventData, "userAgent");
|
|
174
179
|
|
|
175
|
-
const ip_address = event.ipAddress
|
|
180
|
+
const ip_address = getValidClientIp(event.ipAddress);
|
|
176
181
|
const city = event.city ?? null;
|
|
177
182
|
const country = event.country ?? null;
|
|
178
183
|
const country_code = event.countryCode ?? null;
|
|
179
184
|
|
|
180
185
|
const category = classifyCategory(event.eventType);
|
|
181
|
-
const dedupe_key =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
186
|
+
const dedupe_key = event.eventId
|
|
187
|
+
? computeEventIdDedupeKey(AUDIT_EVENT_SOURCE, event.eventId)
|
|
188
|
+
: computeDedupeKey({
|
|
189
|
+
source: AUDIT_EVENT_SOURCE,
|
|
190
|
+
event_type: event.eventType,
|
|
191
|
+
event_key: event.eventKey,
|
|
192
|
+
actor_user_id,
|
|
193
|
+
subject_user_id,
|
|
194
|
+
organization_id,
|
|
195
|
+
team_id,
|
|
196
|
+
session_id,
|
|
197
|
+
identifier,
|
|
198
|
+
reason,
|
|
199
|
+
action,
|
|
200
|
+
occurred_at,
|
|
201
|
+
});
|
|
195
202
|
|
|
196
203
|
// ON CONFLICT DO NOTHING: dedupe_key UNIQUE 위반을 silent 무시.
|
|
197
204
|
// try/catch 방식은 PG 커넥션을 aborted 상태로 만드므로 사용하지 않는다.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type FastifyRequest } from "fastify";
|
|
2
|
+
|
|
3
|
+
import { convertFastifyHeadersToStandard } from "../utils/utils";
|
|
4
|
+
import { replaceClientIpHeaders } from "./audit-log/client-ip";
|
|
5
|
+
|
|
6
|
+
export function createBetterAuthRequest(
|
|
7
|
+
request: FastifyRequest,
|
|
8
|
+
ipAddressHeaders?: readonly string[],
|
|
9
|
+
): Request {
|
|
10
|
+
const url = new URL(request.url, `http://${request.headers.host}`);
|
|
11
|
+
const headers = convertFastifyHeadersToStandard(request.headers);
|
|
12
|
+
|
|
13
|
+
replaceClientIpHeaders(headers, request.ip, ipAddressHeaders);
|
|
14
|
+
|
|
15
|
+
return new Request(url.toString(), {
|
|
16
|
+
method: request.method,
|
|
17
|
+
headers,
|
|
18
|
+
...(request.body ? { body: JSON.stringify(request.body) } : {}),
|
|
19
|
+
});
|
|
20
|
+
}
|
package/src/bin/build-config.ts
CHANGED
|
@@ -32,7 +32,8 @@ export const WEB_ARTIFACTS: BuildArtifact[] = [
|
|
|
32
32
|
description: "Web 프로젝트 클라이언트 빌드 산출물",
|
|
33
33
|
projectPath: "web",
|
|
34
34
|
preBuildCommand: () => "rm -rf dist/client",
|
|
35
|
-
buildCommand: () =>
|
|
35
|
+
buildCommand: () =>
|
|
36
|
+
"tsc -b --noEmit && vite build --config vite.config.ts --outDir dist/client",
|
|
36
37
|
},
|
|
37
38
|
{
|
|
38
39
|
name: "Web Server",
|
|
@@ -40,7 +41,7 @@ export const WEB_ARTIFACTS: BuildArtifact[] = [
|
|
|
40
41
|
projectPath: "web",
|
|
41
42
|
preBuildCommand: () => "rm -rf dist/server",
|
|
42
43
|
buildCommand: () =>
|
|
43
|
-
"tsc --noEmit && vite build --config vite.config.ts --ssr src/entry-server.generated.tsx --outDir dist/server",
|
|
44
|
+
"tsc -b --noEmit && vite build --config vite.config.ts --ssr src/entry-server.generated.tsx --outDir dist/server",
|
|
44
45
|
postBuildCommand: () =>
|
|
45
46
|
"rm -rf ../api/web-dist && mkdir -p ../api/web-dist && cp -r dist/* ../api/web-dist",
|
|
46
47
|
},
|
|
@@ -18,6 +18,35 @@ await this.getPuri("w").table("users").where("id", 1).update({ is_active: false
|
|
|
18
18
|
const users = await db.table({ u: "users" }).select({ id: "u.id" });
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
### Where to obtain a Puri instance
|
|
22
|
+
|
|
23
|
+
Route every query — reads and writes alike — through Puri. Do NOT run queries directly on a raw `getDB()` knex handle (the only exceptions are migration files, `db.ts`, tests, and the `.knex` escape hatch below).
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// Inside a Model
|
|
27
|
+
const rows = await this.getPuri("r").table("users").select({ id: "id" });
|
|
28
|
+
|
|
29
|
+
// Inside a Frame — Frame has no getPuri (only getDB / getUpsertBuilder),
|
|
30
|
+
// so use the associated Model's getPuri
|
|
31
|
+
const rows = await UserModel.getPuri("r").table("users").select({ id: "id" });
|
|
32
|
+
|
|
33
|
+
// Outside a Model (seed / batch / monitoring scripts) — wrap knex in a PuriWrapper
|
|
34
|
+
import { DB, PuriWrapper, UpsertBuilder } from "sonamu";
|
|
35
|
+
const puri = new PuriWrapper(DB.getDB("r"), new UpsertBuilder());
|
|
36
|
+
const rows = await puri.table("users").select({ id: "id" });
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> `UpsertBuilder` is a required constructor argument even for read-only wrappers; it simply stays unused for pure reads.
|
|
40
|
+
|
|
41
|
+
### Escape hatch: `.knex` for non-entity / framework-internal tables
|
|
42
|
+
|
|
43
|
+
Puri's typed `.table()` only knows registered entity tables. For framework-internal or unregistered tables (e.g. `workflow_runs`), reach the raw knex handle via `puri.knex` instead of calling `DB.getDB()` directly:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const puri = new PuriWrapper(DB.getDB("r"), new UpsertBuilder());
|
|
47
|
+
const runs = await puri.knex.table("workflow_runs").where("status", "running").select("*");
|
|
48
|
+
```
|
|
49
|
+
|
|
21
50
|
## SELECT
|
|
22
51
|
|
|
23
52
|
> **CRITICAL: `.select()` must always be used with an object argument.**
|
|
@@ -558,6 +587,10 @@ const results = await this.getPuri("r")
|
|
|
558
587
|
|
|
559
588
|
## Rules
|
|
560
589
|
|
|
590
|
+
- Puri is the standard for BOTH reads and writes in ALL contexts (Model, Frame, scripts) — do NOT run queries on a raw `DB.getDB()` handle (exceptions: migration files, `db.ts`, tests, and the `.knex` escape hatch)
|
|
591
|
+
- Inside a Frame, use the associated Model's `getPuri` (Frame exposes only `getDB` / `getUpsertBuilder`, not `getPuri`)
|
|
592
|
+
- Outside a Model, wrap knex with `new PuriWrapper(DB.getDB(which), new UpsertBuilder())`
|
|
593
|
+
- Use the `puri.knex` escape hatch only for non-entity / framework-internal tables (e.g. `workflow_runs`)
|
|
561
594
|
- MUST use `getPuri("r")` for read queries, `getPuri("w")` for write queries
|
|
562
595
|
- MUST include WHERE condition for UPDATE/DELETE operations
|
|
563
596
|
- MUST use `transaction()` for multiple write operations
|
package/src/syncer/checksum.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import crypto
|
|
1
|
+
import crypto from "crypto";
|
|
2
2
|
import { createReadStream, type PathLike } from "fs";
|
|
3
3
|
import { readFile, writeFile } from "fs/promises";
|
|
4
4
|
import path from "path";
|
|
@@ -114,15 +114,10 @@ async function saveChecksums(checksums: PathAndChecksum[]): Promise<void> {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
async function getChecksumOfFile(filePath: PathLike): Promise<string> {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
});
|
|
124
|
-
input.on("close", () => {
|
|
125
|
-
resolve(hash.digest("hex"));
|
|
126
|
-
});
|
|
127
|
-
});
|
|
117
|
+
const hash = crypto.createHash("sha1");
|
|
118
|
+
const input = createReadStream(filePath);
|
|
119
|
+
for await (const chunk of input) {
|
|
120
|
+
hash.update(chunk);
|
|
121
|
+
}
|
|
122
|
+
return hash.digest("hex");
|
|
128
123
|
}
|
package/src/testing/index.ts
CHANGED