unikvs 0.0.10 → 0.0.13

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 (77) hide show
  1. package/README.md +3 -0
  2. package/dist/index.d.ts +1553 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +4032 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +35 -34
  7. package/src/_contexts.ts +1089 -0
  8. package/src/_logger.ts +5 -3
  9. package/src/_middleware.ts +207 -0
  10. package/src/_pipeline-graph.helpers.ts +183 -0
  11. package/src/_pipeline-graph.ts +1307 -0
  12. package/src/_pipeline-graph.types.ts +303 -0
  13. package/src/_pipeline-leaf-resolver.ts +70 -0
  14. package/src/_plugin-lifecycle.ts +201 -0
  15. package/src/_storage.ts +173 -96
  16. package/src/_streams.schemas.ts +21 -0
  17. package/src/_streams.ts +73 -0
  18. package/src/_to-value-stream.ts +22 -11
  19. package/src/_types.ts +237 -0
  20. package/src/_unikvs-branch.ts +94 -0
  21. package/src/_unikvs.schemas.ts +451 -0
  22. package/src/_valibot.ts +17 -3
  23. package/src/_value-schemas.ts +192 -0
  24. package/src/_value-validation.ts +57 -0
  25. package/src/errors.ts +446 -252
  26. package/src/index.ts +46 -26
  27. package/src/types.ts +13 -0
  28. package/src/unikvs-branch.ts +445 -0
  29. package/src/unikvs-builder.ts +706 -0
  30. package/src/unikvs.ts +1456 -971
  31. package/src/unikvs.types.ts +194 -0
  32. package/src/value-schemas.ts +98 -0
  33. package/dist/src/_logger.d.ts +0 -3
  34. package/dist/src/_logger.d.ts.map +0 -1
  35. package/dist/src/_logger.js +0 -3
  36. package/dist/src/_merge-context.d.ts +0 -13
  37. package/dist/src/_merge-context.d.ts.map +0 -1
  38. package/dist/src/_merge-context.js +0 -12
  39. package/dist/src/_storage.d.ts +0 -18
  40. package/dist/src/_storage.d.ts.map +0 -1
  41. package/dist/src/_storage.js +0 -94
  42. package/dist/src/_to-value-stream.d.ts +0 -12
  43. package/dist/src/_to-value-stream.d.ts.map +0 -1
  44. package/dist/src/_to-value-stream.js +0 -102
  45. package/dist/src/_transformer.d.ts +0 -13
  46. package/dist/src/_transformer.d.ts.map +0 -1
  47. package/dist/src/_transformer.js +0 -60
  48. package/dist/src/_valibot.d.ts +0 -15
  49. package/dist/src/_valibot.d.ts.map +0 -1
  50. package/dist/src/_valibot.js +0 -23
  51. package/dist/src/context.types.d.ts +0 -17
  52. package/dist/src/context.types.d.ts.map +0 -1
  53. package/dist/src/context.types.js +0 -1
  54. package/dist/src/errors.d.ts +0 -340
  55. package/dist/src/errors.d.ts.map +0 -1
  56. package/dist/src/errors.js +0 -250
  57. package/dist/src/index.d.ts +0 -10
  58. package/dist/src/index.d.ts.map +0 -1
  59. package/dist/src/index.js +0 -3
  60. package/dist/src/unikvs-config.d.ts +0 -255
  61. package/dist/src/unikvs-config.d.ts.map +0 -1
  62. package/dist/src/unikvs-config.js +0 -105
  63. package/dist/src/unikvs.d.ts +0 -354
  64. package/dist/src/unikvs.d.ts.map +0 -1
  65. package/dist/src/unikvs.js +0 -867
  66. package/dist/src/utils.types.d.ts +0 -7
  67. package/dist/src/utils.types.d.ts.map +0 -1
  68. package/dist/src/utils.types.js +0 -1
  69. package/dist/src/value-stream.types.d.ts +0 -16
  70. package/dist/src/value-stream.types.d.ts.map +0 -1
  71. package/dist/src/value-stream.types.js +0 -1
  72. package/src/_merge-context.ts +0 -19
  73. package/src/_transformer.ts +0 -89
  74. package/src/context.types.ts +0 -19
  75. package/src/unikvs-config.ts +0 -426
  76. package/src/utils.types.ts +0 -6
  77. package/src/value-stream.types.ts +0 -19
package/src/_logger.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { getLogger } from "@logtape/logtape";
1
+ import { type Logger, getLogger } from "@logtape/logtape";
2
2
 
3
- const logger = getLogger("unikvs");
3
+ // 既定のロガーです。
4
+ export const logger: Logger = getLogger("unikvs");
4
5
 
5
- export default logger;
6
+ // 書き戻しに関する警告専用のロガーです。
7
+ export const repairLogger: Logger = getLogger(["@unikvs/*", "@unikvs/allow-repair"]);
@@ -0,0 +1,207 @@
1
+ import type { IMiddleware } from "@unikvs/core";
2
+ import { asyncmux } from "asyncmux";
3
+ import { callFnOnce } from "call-fn-once";
4
+
5
+ import { PluginLifecycle } from "./_plugin-lifecycle.js";
6
+ import {
7
+ MiddlewareIsNotOpenError,
8
+ StreamDecodingNotSupportedError,
9
+ StreamEncodingNotSupportedError,
10
+ } from "./errors.js";
11
+
12
+ /**
13
+ * 同じオブジェクトに対して同じ `UniKvsMiddleware` インスタンスを返すためのメモです。
14
+ */
15
+ const instances = /* #__PURE__ */ new WeakMap<IMiddleware, UniKvsMiddleware>();
16
+
17
+ /**
18
+ * `IMiddleware` を `UniKvs` 内部から扱うためのラッパーです。
19
+ *
20
+ * ミドルウェアを安全に使うための検証などの処理が集約されています。
21
+ */
22
+ export default class UniKvsMiddleware {
23
+ /**
24
+ * ラップするミドルウェアです。
25
+ */
26
+ readonly #mw: IMiddleware;
27
+
28
+ /**
29
+ * 参照カウントと実 `close` の再試行を管理します。
30
+ */
31
+ readonly #lifecycle: PluginLifecycle<IMiddleware.OpenContext, IMiddleware.CloseContext>;
32
+
33
+ /**
34
+ * ミドルウェアの名前です。
35
+ */
36
+ public readonly name: string;
37
+
38
+ private constructor(middleware: IMiddleware) {
39
+ this.#mw = middleware;
40
+ this.#lifecycle = new PluginLifecycle(middleware);
41
+ this.name = middleware.name;
42
+ }
43
+
44
+ /**
45
+ * `IMiddleware` から `UniKvs` 内部から扱うためのミドルウェアを作成します。
46
+ *
47
+ * @param middleware 元となるミドルウェアです。
48
+ *
49
+ * @returns 検証などの機能が集約されたミドルウェアです。
50
+ */
51
+ public static from(middleware: IMiddleware): UniKvsMiddleware {
52
+ return callFnOnce(instances, middleware, () => new UniKvsMiddleware(middleware));
53
+ }
54
+
55
+ /**
56
+ * ミドルウェアを開きます。
57
+ *
58
+ * @param c オープンコンテキストです。
59
+ */
60
+ @asyncmux
61
+ public async open(c: IMiddleware.OpenContext): Promise<void> {
62
+ await this.#lifecycle.open(c);
63
+ }
64
+
65
+ /**
66
+ * ミドルウェアを閉じます。
67
+ *
68
+ * @param c クローズコンテキストです。
69
+ */
70
+ @asyncmux
71
+ public async close(c: IMiddleware.CloseContext): Promise<void> {
72
+ await this.#lifecycle.close(c);
73
+ }
74
+
75
+ /**
76
+ * 失敗した実 `close` だけを再試行します。
77
+ *
78
+ * @param c クローズコンテキストです。
79
+ */
80
+ @asyncmux
81
+ public async retryClose(c: IMiddleware.CloseContext): Promise<void> {
82
+ await this.#lifecycle.retryClose(c);
83
+ }
84
+
85
+ /**
86
+ * キーを写像します。
87
+ *
88
+ * @param c キー写像コンテキストです。
89
+ *
90
+ * @returns 写像後のキーを返します。
91
+ */
92
+ public mapKey(c: IMiddleware.MapKeyContext): string {
93
+ if (!this.#mw.isOpen) {
94
+ throw new MiddlewareIsNotOpenError({ name: this.name });
95
+ }
96
+
97
+ if (this.#mw.mapKey === undefined) {
98
+ // 既定ではキーをそのまま似します。
99
+ return c.key;
100
+ }
101
+
102
+ return this.#mw.mapKey(c);
103
+ }
104
+
105
+ /**
106
+ * 任意の操作に割り込みます。
107
+ *
108
+ * @param c 操作コンテキストです。
109
+ * @param next 後段の処理です。
110
+ */
111
+ public async use(c: IMiddleware.UseContext, next: IMiddleware.INext): Promise<void> {
112
+ if (!this.#mw.isOpen) {
113
+ throw new MiddlewareIsNotOpenError({ name: this.name });
114
+ }
115
+
116
+ if (this.#mw.use === undefined) {
117
+ // 既定では後段の処理を実行します。
118
+ await next();
119
+ } else {
120
+ await this.#mw.use(c, next);
121
+ }
122
+ }
123
+
124
+ /**
125
+ * データをエンコードします。
126
+ *
127
+ * @param c エンコードコンテキストです。
128
+ * @param next 後段の処理です。
129
+ */
130
+ public async encode(c: IMiddleware.EncodeContext, next: IMiddleware.INext): Promise<void> {
131
+ if (!this.#mw.isOpen) {
132
+ throw new MiddlewareIsNotOpenError({ name: this.name });
133
+ }
134
+
135
+ if (this.#mw.encode === undefined) {
136
+ // 既定ではデータを素通りさせます。
137
+ c.destination = c.source;
138
+
139
+ await next();
140
+ } else {
141
+ await this.#mw.encode(c, next);
142
+ }
143
+ }
144
+
145
+ /**
146
+ * データをデコードします。
147
+ *
148
+ * @param c デコードコンテキストです。
149
+ * @param next 後段の処理です。
150
+ */
151
+ public async decode(c: IMiddleware.DecodeContext, next: IMiddleware.INext): Promise<void> {
152
+ if (!this.#mw.isOpen) {
153
+ throw new MiddlewareIsNotOpenError({ name: this.name });
154
+ }
155
+
156
+ if (this.#mw.decode === undefined) {
157
+ // 既定ではデータを素通りさせます。
158
+ c.destination = c.source;
159
+
160
+ await next();
161
+ } else {
162
+ await this.#mw.decode(c, next);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * ストリームをエンコードします。
168
+ *
169
+ * @param c エンコードストリームコンテキストです。
170
+ * @param next 後段の処理です。
171
+ */
172
+ public async encodeStream(
173
+ c: IMiddleware.EncodeStreamContext,
174
+ next: IMiddleware.INext,
175
+ ): Promise<void> {
176
+ if (!this.#mw.isOpen) {
177
+ throw new MiddlewareIsNotOpenError({ name: this.name });
178
+ }
179
+
180
+ if (this.#mw.encodeStream === undefined) {
181
+ throw new StreamEncodingNotSupportedError({ name: this.name });
182
+ }
183
+
184
+ await this.#mw.encodeStream(c, next);
185
+ }
186
+
187
+ /**
188
+ * ストリームをデコードします。
189
+ *
190
+ * @param c デコードストリームコンテキストです。
191
+ * @param next 後段の処理です。
192
+ */
193
+ public async decodeStream(
194
+ c: IMiddleware.DecodeStreamContext,
195
+ next: IMiddleware.INext,
196
+ ): Promise<void> {
197
+ if (!this.#mw.isOpen) {
198
+ throw new MiddlewareIsNotOpenError({ name: this.name });
199
+ }
200
+
201
+ if (this.#mw.decodeStream === undefined) {
202
+ throw new StreamDecodingNotSupportedError({ name: this.name });
203
+ }
204
+
205
+ await this.#mw.decodeStream(c, next);
206
+ }
207
+ }
@@ -0,0 +1,183 @@
1
+ import { type IReadableStream, type ITransformContext } from "@unikvs/core";
2
+
3
+ import {
4
+ type DecodeContext,
5
+ type EncodeContext,
6
+ type DecodeStreamContext,
7
+ type EncodeStreamContext,
8
+ MapKeyContext,
9
+ } from "./_contexts.js";
10
+ import type UniKvsMiddleware from "./_middleware.js";
11
+ import type {
12
+ PipelineLeaf,
13
+ PipelineNode,
14
+ PipelineEntry,
15
+ OperationScope,
16
+ IActiveLeafChecker,
17
+ } from "./_pipeline-graph.types.js";
18
+ import { ReadableStreamSchema } from "./_streams.schemas.js";
19
+ import { parseOutput } from "./_valibot.js";
20
+ import { MiddlewareDestinationFrozenError, MiddlewareDestinationMissingError } from "./errors.js";
21
+
22
+ /**
23
+ * 対象判定に通る葉だけを登録順に絞ります。
24
+ *
25
+ * 全葉が対象なら複製せず `node.allLeaves` を返します。
26
+ *
27
+ * @param node 対象の節です。
28
+ * @param isActive 書き込み対象とする葉を判定します。
29
+ *
30
+ * @returns 対象の葉を登録順に返します。
31
+ */
32
+ export function activeLeavesOf(
33
+ node: PipelineNode,
34
+ isActive: IActiveLeafChecker,
35
+ ): readonly PipelineLeaf[] {
36
+ const active = node.allLeaves.filter(isActive);
37
+
38
+ if (active.length === node.allLeaves.length) {
39
+ return node.allLeaves;
40
+ }
41
+
42
+ return active;
43
+ }
44
+
45
+ /**
46
+ * 葉と節を登録順に並べた静的な項目列を作成します。
47
+ *
48
+ * 各操作の走査はこの並びをそのまま読みます。
49
+ * 並べ替え用の順序は項目に保持せず、作成時のローカル変数で解決します。
50
+ *
51
+ * @param leaves この節で終端する葉です。
52
+ * @param children 子の節です。
53
+ *
54
+ * @returns 登録順に並べた項目列を返します。
55
+ */
56
+ export function createEntries(
57
+ leaves: readonly PipelineLeaf[],
58
+ children: readonly PipelineNode[],
59
+ ): PipelineEntry[] {
60
+ return [
61
+ ...leaves.map((leaf) => ({
62
+ entry: {
63
+ kind: "leaf" as const,
64
+ leaf,
65
+ },
66
+ order: leaf.index,
67
+ })),
68
+ ...children.map((child) => {
69
+ const [firstLeaf] = child.allLeaves;
70
+
71
+ if (firstLeaf === undefined) {
72
+ throw new Error("子節に葉が存在しません。");
73
+ }
74
+
75
+ return {
76
+ entry: {
77
+ kind: "node" as const,
78
+ node: child,
79
+ },
80
+ order: firstLeaf.index,
81
+ };
82
+ }),
83
+ ]
84
+ .toSorted((a, b) => a.order - b.order)
85
+ .map((item) => item.entry);
86
+ }
87
+
88
+ /**
89
+ * 変換後のデータが設定されていることを検証し、変換後のデータを返します。
90
+ *
91
+ * ミドルウェアが `destination` を設定しなかったときに投げます。
92
+ *
93
+ * @param middleware 対象のミドルウェアです。
94
+ * @param ctx 検証するコンテキストです。
95
+ * @param operation エラーに付与する操作名です。
96
+ *
97
+ * @returns 変換後のデータを返します。
98
+ */
99
+ export function requireDestination(
100
+ middleware: UniKvsMiddleware,
101
+ ctx: EncodeContext | DecodeContext | EncodeStreamContext | DecodeStreamContext,
102
+ operation: "encode" | "decode",
103
+ ): unknown {
104
+ if ("destination" in ctx) {
105
+ return ctx.destination;
106
+ }
107
+
108
+ throw new MiddlewareDestinationMissingError({
109
+ name: middleware.name,
110
+ operation,
111
+ });
112
+ }
113
+
114
+ /**
115
+ * 変換後のストリームが設定されていることを検証し、型を検証したストリームを返します。
116
+ *
117
+ * ミドルウェアが `destination` を設定しなかったときに投げます。
118
+ * ストリームの場合は存在確認に加えて `ReadableStream` の型も検証します。
119
+ *
120
+ * @param middleware 対象のミドルウェアです。
121
+ * @param ctx 検証するコンテキストです。
122
+ * @param operation エラーに付与する操作名です。
123
+ *
124
+ * @returns 変換後のストリームを返します。
125
+ */
126
+ export function requireStreamDestination(
127
+ middleware: UniKvsMiddleware,
128
+ ctx: EncodeStreamContext | DecodeStreamContext,
129
+ operation: "encode" | "decode",
130
+ ): IReadableStream {
131
+ const destination = requireDestination(middleware, ctx, operation);
132
+
133
+ return parseOutput(ReadableStreamSchema, destination);
134
+ }
135
+
136
+ /**
137
+ * コンテキストの `destination` を凍結します。
138
+ *
139
+ * パイプラインの `next` から同期的に呼び出します。
140
+ * 凍結後の読み取りはできますが、書き込むと `MiddlewareDestinationFrozenError` を投げます。
141
+ *
142
+ * @param ctx 凍結するコンテキストです。
143
+ */
144
+ export function freezeDestination(ctx: ITransformContext): void {
145
+ const { destination } = ctx;
146
+ Object.defineProperty(ctx, "destination", {
147
+ get() {
148
+ return destination;
149
+ },
150
+ set() {
151
+ throw new MiddlewareDestinationFrozenError({
152
+ key: ctx.key,
153
+ action: ctx.action,
154
+ });
155
+ },
156
+ enumerable: true,
157
+ configurable: true,
158
+ });
159
+ }
160
+
161
+ /**
162
+ * 単一ミドルウェアの `mapKey` を実行します。
163
+ *
164
+ * 共有ストアを参照するため、カスタム変数の下流変更が写像にも見えます。
165
+ *
166
+ * @param middleware 対象のミドルウェアです。
167
+ * @param key 写像前のキーです。
168
+ * @param scope 操作共通の実行時情報です。
169
+ *
170
+ * @returns 写像後のキーを返します。
171
+ */
172
+ export function applyMapKey(
173
+ middleware: UniKvsMiddleware,
174
+ key: string,
175
+ scope: OperationScope,
176
+ ): string {
177
+ const c = new MapKeyContext({
178
+ key,
179
+ store: scope.store,
180
+ });
181
+
182
+ return middleware.mapKey(c);
183
+ }