@gettersethya/mira 0.1.0-alpha.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/LICENSE +21 -0
- package/dist/src/app/app.d.ts +96 -0
- package/dist/src/app/app.d.ts.map +1 -0
- package/dist/src/app/app.js +139 -0
- package/dist/src/app/app.js.map +1 -0
- package/dist/src/app/builder.d.ts +106 -0
- package/dist/src/app/builder.d.ts.map +1 -0
- package/dist/src/app/builder.js +122 -0
- package/dist/src/app/builder.js.map +1 -0
- package/dist/src/app/index.d.ts +31 -0
- package/dist/src/app/index.d.ts.map +1 -0
- package/dist/src/app/index.js +29 -0
- package/dist/src/app/index.js.map +1 -0
- package/dist/src/app/types.d.ts +55 -0
- package/dist/src/app/types.d.ts.map +1 -0
- package/dist/src/app/types.js +2 -0
- package/dist/src/app/types.js.map +1 -0
- package/dist/src/cache/cached-collection.d.ts +30 -0
- package/dist/src/cache/cached-collection.d.ts.map +1 -0
- package/dist/src/cache/cached-collection.js +107 -0
- package/dist/src/cache/cached-collection.js.map +1 -0
- package/dist/src/cache/collection-cache.d.ts +17 -0
- package/dist/src/cache/collection-cache.d.ts.map +1 -0
- package/dist/src/cache/collection-cache.js +37 -0
- package/dist/src/cache/collection-cache.js.map +1 -0
- package/dist/src/cache/index.d.ts +4 -0
- package/dist/src/cache/index.d.ts.map +1 -0
- package/dist/src/cache/index.js +3 -0
- package/dist/src/cache/index.js.map +1 -0
- package/dist/src/cache/types.d.ts +12 -0
- package/dist/src/cache/types.d.ts.map +1 -0
- package/dist/src/cache/types.js +2 -0
- package/dist/src/cache/types.js.map +1 -0
- package/dist/src/collection-service/collection-service.d.ts +62 -0
- package/dist/src/collection-service/collection-service.d.ts.map +1 -0
- package/dist/src/collection-service/collection-service.js +267 -0
- package/dist/src/collection-service/collection-service.js.map +1 -0
- package/dist/src/collection-service/context.d.ts +17 -0
- package/dist/src/collection-service/context.d.ts.map +1 -0
- package/dist/src/collection-service/context.js +2 -0
- package/dist/src/collection-service/context.js.map +1 -0
- package/dist/src/collection-service/decode.d.ts +6 -0
- package/dist/src/collection-service/decode.d.ts.map +1 -0
- package/dist/src/collection-service/decode.js +26 -0
- package/dist/src/collection-service/decode.js.map +1 -0
- package/dist/src/collection-service/errors.d.ts +67 -0
- package/dist/src/collection-service/errors.d.ts.map +1 -0
- package/dist/src/collection-service/errors.js +43 -0
- package/dist/src/collection-service/errors.js.map +1 -0
- package/dist/src/collection-service/index.d.ts +5 -0
- package/dist/src/collection-service/index.d.ts.map +1 -0
- package/dist/src/collection-service/index.js +3 -0
- package/dist/src/collection-service/index.js.map +1 -0
- package/dist/src/collection-service/input-schema.d.ts +10 -0
- package/dist/src/collection-service/input-schema.d.ts.map +1 -0
- package/dist/src/collection-service/input-schema.js +109 -0
- package/dist/src/collection-service/input-schema.js.map +1 -0
- package/dist/src/collection-service/where.d.ts +35 -0
- package/dist/src/collection-service/where.d.ts.map +1 -0
- package/dist/src/collection-service/where.js +88 -0
- package/dist/src/collection-service/where.js.map +1 -0
- package/dist/src/config/config.d.ts +44 -0
- package/dist/src/config/config.d.ts.map +1 -0
- package/dist/src/config/config.js +89 -0
- package/dist/src/config/config.js.map +1 -0
- package/dist/src/config/index.d.ts +3 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +2 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/config/types.d.ts +29 -0
- package/dist/src/config/types.d.ts.map +1 -0
- package/dist/src/config/types.js +2 -0
- package/dist/src/config/types.js.map +1 -0
- package/dist/src/crypto/crypto.d.ts +11 -0
- package/dist/src/crypto/crypto.d.ts.map +1 -0
- package/dist/src/crypto/crypto.js +4 -0
- package/dist/src/crypto/crypto.js.map +1 -0
- package/dist/src/crypto/index.d.ts +3 -0
- package/dist/src/crypto/index.d.ts.map +1 -0
- package/dist/src/crypto/index.js +3 -0
- package/dist/src/crypto/index.js.map +1 -0
- package/dist/src/crypto/node.d.ts +4 -0
- package/dist/src/crypto/node.d.ts.map +1 -0
- package/dist/src/crypto/node.js +9 -0
- package/dist/src/crypto/node.js.map +1 -0
- package/dist/src/databases/index.d.ts +2 -0
- package/dist/src/databases/index.d.ts.map +1 -0
- package/dist/src/databases/index.js +2 -0
- package/dist/src/databases/index.js.map +1 -0
- package/dist/src/databases/sqlite.d.ts +24 -0
- package/dist/src/databases/sqlite.d.ts.map +1 -0
- package/dist/src/databases/sqlite.js +27 -0
- package/dist/src/databases/sqlite.js.map +1 -0
- package/dist/src/http/auth-node.d.ts +4 -0
- package/dist/src/http/auth-node.d.ts.map +1 -0
- package/dist/src/http/auth-node.js +34 -0
- package/dist/src/http/auth-node.js.map +1 -0
- package/dist/src/http/auth.d.ts +38 -0
- package/dist/src/http/auth.d.ts.map +1 -0
- package/dist/src/http/auth.js +66 -0
- package/dist/src/http/auth.js.map +1 -0
- package/dist/src/http/errors.d.ts +31 -0
- package/dist/src/http/errors.d.ts.map +1 -0
- package/dist/src/http/errors.js +36 -0
- package/dist/src/http/errors.js.map +1 -0
- package/dist/src/http/file-serve.d.ts +10 -0
- package/dist/src/http/file-serve.d.ts.map +1 -0
- package/dist/src/http/file-serve.js +159 -0
- package/dist/src/http/file-serve.js.map +1 -0
- package/dist/src/http/file-token.d.ts +7 -0
- package/dist/src/http/file-token.d.ts.map +1 -0
- package/dist/src/http/file-token.js +55 -0
- package/dist/src/http/file-token.js.map +1 -0
- package/dist/src/http/files.d.ts +11 -0
- package/dist/src/http/files.d.ts.map +1 -0
- package/dist/src/http/files.js +85 -0
- package/dist/src/http/files.js.map +1 -0
- package/dist/src/http/index.d.ts +10 -0
- package/dist/src/http/index.d.ts.map +1 -0
- package/dist/src/http/index.js +8 -0
- package/dist/src/http/index.js.map +1 -0
- package/dist/src/http/ip-middleware.d.ts +4 -0
- package/dist/src/http/ip-middleware.d.ts.map +1 -0
- package/dist/src/http/ip-middleware.js +21 -0
- package/dist/src/http/ip-middleware.js.map +1 -0
- package/dist/src/http/params.d.ts +15 -0
- package/dist/src/http/params.d.ts.map +1 -0
- package/dist/src/http/params.js +48 -0
- package/dist/src/http/params.js.map +1 -0
- package/dist/src/http/router.d.ts +11 -0
- package/dist/src/http/router.d.ts.map +1 -0
- package/dist/src/http/router.js +216 -0
- package/dist/src/http/router.js.map +1 -0
- package/dist/src/http/server-factory-node.d.ts +4 -0
- package/dist/src/http/server-factory-node.d.ts.map +1 -0
- package/dist/src/http/server-factory-node.js +8 -0
- package/dist/src/http/server-factory-node.js.map +1 -0
- package/dist/src/http/server-factory.d.ts +11 -0
- package/dist/src/http/server-factory.d.ts.map +1 -0
- package/dist/src/http/server-factory.js +4 -0
- package/dist/src/http/server-factory.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +10 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/migrator/dialect-sqlite.d.ts +9 -0
- package/dist/src/migrator/dialect-sqlite.d.ts.map +1 -0
- package/dist/src/migrator/dialect-sqlite.js +102 -0
- package/dist/src/migrator/dialect-sqlite.js.map +1 -0
- package/dist/src/migrator/dialect.d.ts +24 -0
- package/dist/src/migrator/dialect.d.ts.map +1 -0
- package/dist/src/migrator/dialect.js +5 -0
- package/dist/src/migrator/dialect.js.map +1 -0
- package/dist/src/migrator/index.d.ts +8 -0
- package/dist/src/migrator/index.d.ts.map +1 -0
- package/dist/src/migrator/index.js +6 -0
- package/dist/src/migrator/index.js.map +1 -0
- package/dist/src/migrator/migrator.d.ts +36 -0
- package/dist/src/migrator/migrator.d.ts.map +1 -0
- package/dist/src/migrator/migrator.js +200 -0
- package/dist/src/migrator/migrator.js.map +1 -0
- package/dist/src/migrator/schema-diff.d.ts +25 -0
- package/dist/src/migrator/schema-diff.d.ts.map +1 -0
- package/dist/src/migrator/schema-diff.js +157 -0
- package/dist/src/migrator/schema-diff.js.map +1 -0
- package/dist/src/migrator/types.d.ts +91 -0
- package/dist/src/migrator/types.d.ts.map +1 -0
- package/dist/src/migrator/types.js +13 -0
- package/dist/src/migrator/types.js.map +1 -0
- package/dist/src/platforms/node.d.ts +40 -0
- package/dist/src/platforms/node.d.ts.map +1 -0
- package/dist/src/platforms/node.js +45 -0
- package/dist/src/platforms/node.js.map +1 -0
- package/dist/src/repository/id.d.ts +5 -0
- package/dist/src/repository/id.d.ts.map +1 -0
- package/dist/src/repository/id.js +9 -0
- package/dist/src/repository/id.js.map +1 -0
- package/dist/src/repository/index.d.ts +3 -0
- package/dist/src/repository/index.d.ts.map +1 -0
- package/dist/src/repository/index.js +2 -0
- package/dist/src/repository/index.js.map +1 -0
- package/dist/src/repository/repository.d.ts +53 -0
- package/dist/src/repository/repository.d.ts.map +1 -0
- package/dist/src/repository/repository.js +150 -0
- package/dist/src/repository/repository.js.map +1 -0
- package/dist/src/repository/types.d.ts +42 -0
- package/dist/src/repository/types.d.ts.map +1 -0
- package/dist/src/repository/types.js +2 -0
- package/dist/src/repository/types.js.map +1 -0
- package/dist/src/rule/compiler.d.ts +52 -0
- package/dist/src/rule/compiler.d.ts.map +1 -0
- package/dist/src/rule/compiler.js +113 -0
- package/dist/src/rule/compiler.js.map +1 -0
- package/dist/src/rule/enforcer.d.ts +47 -0
- package/dist/src/rule/enforcer.d.ts.map +1 -0
- package/dist/src/rule/enforcer.js +60 -0
- package/dist/src/rule/enforcer.js.map +1 -0
- package/dist/src/rule/index.d.ts +3 -0
- package/dist/src/rule/index.d.ts.map +1 -0
- package/dist/src/rule/index.js +3 -0
- package/dist/src/rule/index.js.map +1 -0
- package/dist/src/storage/index.d.ts +3 -0
- package/dist/src/storage/index.d.ts.map +1 -0
- package/dist/src/storage/index.js +3 -0
- package/dist/src/storage/index.js.map +1 -0
- package/dist/src/storage/local-preset.d.ts +21 -0
- package/dist/src/storage/local-preset.d.ts.map +1 -0
- package/dist/src/storage/local-preset.js +21 -0
- package/dist/src/storage/local-preset.js.map +1 -0
- package/dist/src/storage/storage.d.ts +83 -0
- package/dist/src/storage/storage.d.ts.map +1 -0
- package/dist/src/storage/storage.js +120 -0
- package/dist/src/storage/storage.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +6 -0
- package/dist/src/telemetry/index.d.ts.map +1 -0
- package/dist/src/telemetry/index.js +7 -0
- package/dist/src/telemetry/index.js.map +1 -0
- package/dist/src/telemetry/logger.d.ts +4 -0
- package/dist/src/telemetry/logger.d.ts.map +1 -0
- package/dist/src/telemetry/logger.js +27 -0
- package/dist/src/telemetry/logger.js.map +1 -0
- package/dist/src/telemetry/tracer.d.ts +16 -0
- package/dist/src/telemetry/tracer.d.ts.map +1 -0
- package/dist/src/telemetry/tracer.js +106 -0
- package/dist/src/telemetry/tracer.js.map +1 -0
- package/dist/src/thumbnail/index.d.ts +4 -0
- package/dist/src/thumbnail/index.d.ts.map +1 -0
- package/dist/src/thumbnail/index.js +3 -0
- package/dist/src/thumbnail/index.js.map +1 -0
- package/dist/src/thumbnail/photon.d.ts +9 -0
- package/dist/src/thumbnail/photon.d.ts.map +1 -0
- package/dist/src/thumbnail/photon.js +73 -0
- package/dist/src/thumbnail/photon.js.map +1 -0
- package/dist/src/thumbnail/types.d.ts +23 -0
- package/dist/src/thumbnail/types.d.ts.map +1 -0
- package/dist/src/thumbnail/types.js +22 -0
- package/dist/src/thumbnail/types.js.map +1 -0
- package/dist/tests/app/app.test.d.ts +2 -0
- package/dist/tests/app/app.test.d.ts.map +1 -0
- package/dist/tests/app/app.test.js +78 -0
- package/dist/tests/app/app.test.js.map +1 -0
- package/dist/tests/app/builder.test.d.ts +2 -0
- package/dist/tests/app/builder.test.d.ts.map +1 -0
- package/dist/tests/app/builder.test.js +69 -0
- package/dist/tests/app/builder.test.js.map +1 -0
- package/dist/tests/cache/cached-collection.test.d.ts +2 -0
- package/dist/tests/cache/cached-collection.test.d.ts.map +1 -0
- package/dist/tests/cache/cached-collection.test.js +244 -0
- package/dist/tests/cache/cached-collection.test.js.map +1 -0
- package/dist/tests/cache/collection-cache.test.d.ts +2 -0
- package/dist/tests/cache/collection-cache.test.d.ts.map +1 -0
- package/dist/tests/cache/collection-cache.test.js +73 -0
- package/dist/tests/cache/collection-cache.test.js.map +1 -0
- package/dist/tests/collection-service/collection-service.test.d.ts +2 -0
- package/dist/tests/collection-service/collection-service.test.d.ts.map +1 -0
- package/dist/tests/collection-service/collection-service.test.js +805 -0
- package/dist/tests/collection-service/collection-service.test.js.map +1 -0
- package/dist/tests/collection-service/input-schema.test.d.ts +2 -0
- package/dist/tests/collection-service/input-schema.test.d.ts.map +1 -0
- package/dist/tests/collection-service/input-schema.test.js +260 -0
- package/dist/tests/collection-service/input-schema.test.js.map +1 -0
- package/dist/tests/config/config.test.d.ts +2 -0
- package/dist/tests/config/config.test.d.ts.map +1 -0
- package/dist/tests/config/config.test.js +84 -0
- package/dist/tests/config/config.test.js.map +1 -0
- package/dist/tests/crypto/crypto.test.d.ts +2 -0
- package/dist/tests/crypto/crypto.test.d.ts.map +1 -0
- package/dist/tests/crypto/crypto.test.js +56 -0
- package/dist/tests/crypto/crypto.test.js.map +1 -0
- package/dist/tests/http/file-serve.test.d.ts +2 -0
- package/dist/tests/http/file-serve.test.d.ts.map +1 -0
- package/dist/tests/http/file-serve.test.js +210 -0
- package/dist/tests/http/file-serve.test.js.map +1 -0
- package/dist/tests/http/file-token.test.d.ts +2 -0
- package/dist/tests/http/file-token.test.d.ts.map +1 -0
- package/dist/tests/http/file-token.test.js +155 -0
- package/dist/tests/http/file-token.test.js.map +1 -0
- package/dist/tests/http/ip-middleware.test.d.ts +2 -0
- package/dist/tests/http/ip-middleware.test.d.ts.map +1 -0
- package/dist/tests/http/ip-middleware.test.js +58 -0
- package/dist/tests/http/ip-middleware.test.js.map +1 -0
- package/dist/tests/http/router.test.d.ts +2 -0
- package/dist/tests/http/router.test.d.ts.map +1 -0
- package/dist/tests/http/router.test.js +252 -0
- package/dist/tests/http/router.test.js.map +1 -0
- package/dist/tests/migrator/dialect-sqlite.test.d.ts +2 -0
- package/dist/tests/migrator/dialect-sqlite.test.d.ts.map +1 -0
- package/dist/tests/migrator/dialect-sqlite.test.js +90 -0
- package/dist/tests/migrator/dialect-sqlite.test.js.map +1 -0
- package/dist/tests/migrator/integration.test.d.ts +2 -0
- package/dist/tests/migrator/integration.test.d.ts.map +1 -0
- package/dist/tests/migrator/integration.test.js +180 -0
- package/dist/tests/migrator/integration.test.js.map +1 -0
- package/dist/tests/migrator/migrator.test.d.ts +2 -0
- package/dist/tests/migrator/migrator.test.d.ts.map +1 -0
- package/dist/tests/migrator/migrator.test.js +225 -0
- package/dist/tests/migrator/migrator.test.js.map +1 -0
- package/dist/tests/migrator/schema-diff.test.d.ts +2 -0
- package/dist/tests/migrator/schema-diff.test.d.ts.map +1 -0
- package/dist/tests/migrator/schema-diff.test.js +323 -0
- package/dist/tests/migrator/schema-diff.test.js.map +1 -0
- package/dist/tests/repository/repository.test.d.ts +2 -0
- package/dist/tests/repository/repository.test.d.ts.map +1 -0
- package/dist/tests/repository/repository.test.js +255 -0
- package/dist/tests/repository/repository.test.js.map +1 -0
- package/dist/tests/rule/compiler.test.d.ts +2 -0
- package/dist/tests/rule/compiler.test.d.ts.map +1 -0
- package/dist/tests/rule/compiler.test.js +226 -0
- package/dist/tests/rule/compiler.test.js.map +1 -0
- package/dist/tests/rule/enforcer.test.d.ts +2 -0
- package/dist/tests/rule/enforcer.test.d.ts.map +1 -0
- package/dist/tests/rule/enforcer.test.js +190 -0
- package/dist/tests/rule/enforcer.test.js.map +1 -0
- package/dist/tests/storage/storage.test.d.ts +2 -0
- package/dist/tests/storage/storage.test.d.ts.map +1 -0
- package/dist/tests/storage/storage.test.js +76 -0
- package/dist/tests/storage/storage.test.js.map +1 -0
- package/dist/tests/telemetry/instrumentation.test.d.ts +2 -0
- package/dist/tests/telemetry/instrumentation.test.d.ts.map +1 -0
- package/dist/tests/telemetry/instrumentation.test.js +226 -0
- package/dist/tests/telemetry/instrumentation.test.js.map +1 -0
- package/dist/tests/telemetry/logger.test.d.ts +2 -0
- package/dist/tests/telemetry/logger.test.d.ts.map +1 -0
- package/dist/tests/telemetry/logger.test.js +56 -0
- package/dist/tests/telemetry/logger.test.js.map +1 -0
- package/dist/tests/telemetry/tracer.test.d.ts +2 -0
- package/dist/tests/telemetry/tracer.test.d.ts.map +1 -0
- package/dist/tests/telemetry/tracer.test.js +63 -0
- package/dist/tests/telemetry/tracer.test.js.map +1 -0
- package/dist/tests/thumbnail/photon.test.d.ts +2 -0
- package/dist/tests/thumbnail/photon.test.d.ts.map +1 -0
- package/dist/tests/thumbnail/photon.test.js +478 -0
- package/dist/tests/thumbnail/photon.test.js.map +1 -0
- package/dist/tests/thumbnail/thumbnail.test.d.ts +2 -0
- package/dist/tests/thumbnail/thumbnail.test.d.ts.map +1 -0
- package/dist/tests/thumbnail/thumbnail.test.js +35 -0
- package/dist/tests/thumbnail/thumbnail.test.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RepoRecord } from "../repository/types.js";
|
|
2
|
+
/** Auth-resolved request context. JWT parsing is not done here — the route handler provides this. */
|
|
3
|
+
export type RequestCtx = {
|
|
4
|
+
auth?: {
|
|
5
|
+
collection: string;
|
|
6
|
+
record: RepoRecord;
|
|
7
|
+
};
|
|
8
|
+
headers: Record<string, string>;
|
|
9
|
+
query: Record<string, string | ReadonlyArray<string>>;
|
|
10
|
+
};
|
|
11
|
+
/** Paginated result — cursor-based via seqId. Used for all collection kinds. */
|
|
12
|
+
export type CursorPage = {
|
|
13
|
+
items: ReadonlyArray<RepoRecord>;
|
|
14
|
+
/** seqId of the last item. Pass as `after` to fetch the next page. null = no more pages. */
|
|
15
|
+
nextCursor: number | null;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/collection-service/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAEvD,qGAAqG;AACrG,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAA;IACjD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;CACtD,CAAA;AAED,gFAAgF;AAChF,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IAChC,4FAA4F;IAC5F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/collection-service/context.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { CollectionSchema } from "@gettersethya/mira-client";
|
|
3
|
+
import type { RepoRecord } from "../repository/types.js";
|
|
4
|
+
export type RowDecoder = (record: RepoRecord) => Effect.Effect<RepoRecord>;
|
|
5
|
+
export declare function makeRowDecoder(colSchema: CollectionSchema): RowDecoder;
|
|
6
|
+
//# sourceMappingURL=decode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decode.d.ts","sourceRoot":"","sources":["../../../src/collection-service/decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAIvD,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;AAE1E,wBAAgB,cAAc,CAAC,SAAS,EAAE,gBAAgB,GAAG,UAAU,CAsBtE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
const RecordSchema = Schema.Record({ key: Schema.String, value: Schema.Unknown });
|
|
3
|
+
export function makeRowDecoder(colSchema) {
|
|
4
|
+
const boolKeys = new Set();
|
|
5
|
+
for (const [key, prop] of Object.entries(colSchema.properties)) {
|
|
6
|
+
if (prop.type === "boolean")
|
|
7
|
+
boolKeys.add(key);
|
|
8
|
+
}
|
|
9
|
+
if (boolKeys.size === 0)
|
|
10
|
+
return Effect.succeed;
|
|
11
|
+
const RowSchema = Schema.transform(RecordSchema, RecordSchema, {
|
|
12
|
+
decode: (record) => {
|
|
13
|
+
const result = { ...record };
|
|
14
|
+
for (const key of boolKeys) {
|
|
15
|
+
const v = result[key];
|
|
16
|
+
if (v === 0 || v === 1)
|
|
17
|
+
result[key] = v === 1;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
},
|
|
21
|
+
encode: (v) => v
|
|
22
|
+
});
|
|
23
|
+
const decode = Schema.decodeUnknown(RowSchema);
|
|
24
|
+
return (record) => decode(record).pipe(Effect.orDie, Effect.map((r) => r));
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=decode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decode.js","sourceRoot":"","sources":["../../../src/collection-service/decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAIvC,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;AAIjF,MAAM,UAAU,cAAc,CAAC,SAA2B;IACxD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAClC,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/D,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAChD,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,OAAO,CAAA;IAE9C,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE;QAC7D,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;YACjB,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,CAAA;YAC5B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;gBACrB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;oBAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC/C,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC;QACD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;KACjB,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAA;IAC9C,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAe,CAAC,CAAC,CAAA;AAC1F,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { SqlError } from "@effect/sql";
|
|
2
|
+
import { ValidationError } from "@gettersethya/mira-client";
|
|
3
|
+
export { ValidationError };
|
|
4
|
+
declare const NotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
5
|
+
readonly _tag: "NotFoundError";
|
|
6
|
+
} & Readonly<A>;
|
|
7
|
+
/**
|
|
8
|
+
* Error raised when a requested record is not found.
|
|
9
|
+
* Contains the collection name and the requested record ID.
|
|
10
|
+
*
|
|
11
|
+
* The server returns HTTP 404 when this error propagates to the HTTP layer.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* new NotFoundError({ collection: "posts", id: "abc123" })
|
|
15
|
+
*
|
|
16
|
+
* @see CollectionService — raises this error on getOne/update/delete for missing records
|
|
17
|
+
*/
|
|
18
|
+
export declare class NotFoundError extends NotFoundError_base<{
|
|
19
|
+
collection: string;
|
|
20
|
+
id: string;
|
|
21
|
+
}> {
|
|
22
|
+
}
|
|
23
|
+
declare const ForbiddenError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
24
|
+
readonly _tag: "ForbiddenError";
|
|
25
|
+
} & Readonly<A>;
|
|
26
|
+
/**
|
|
27
|
+
* Error raised when an action is forbidden by access rules.
|
|
28
|
+
* Contains the collection name and the attempted action.
|
|
29
|
+
*
|
|
30
|
+
* The server returns HTTP 403 when this error propagates to the HTTP layer.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* new ForbiddenError({ collection: "posts", action: "update" })
|
|
34
|
+
*
|
|
35
|
+
* @see CollectionService — raises this error when rules deny an action
|
|
36
|
+
*/
|
|
37
|
+
export declare class ForbiddenError extends ForbiddenError_base<{
|
|
38
|
+
collection: string;
|
|
39
|
+
action: string;
|
|
40
|
+
}> {
|
|
41
|
+
}
|
|
42
|
+
declare const ReadOnlyError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
43
|
+
readonly _tag: "ReadOnlyError";
|
|
44
|
+
} & Readonly<A>;
|
|
45
|
+
/**
|
|
46
|
+
* Error raised when a write operation is attempted on a read-only collection.
|
|
47
|
+
* View collections always raise this on create/update/delete.
|
|
48
|
+
*
|
|
49
|
+
* The server returns HTTP 405 (Method Not Allowed) when this error propagates.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* new ReadOnlyError({ collection: "active_posts" })
|
|
53
|
+
*
|
|
54
|
+
* @see ViewCollection — view collections are read-only
|
|
55
|
+
*/
|
|
56
|
+
export declare class ReadOnlyError extends ReadOnlyError_base<{
|
|
57
|
+
collection: string;
|
|
58
|
+
}> {
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Union of all errors that can be raised by CollectionService operations.
|
|
62
|
+
* Includes NotFoundError, ForbiddenError, ValidationError, ReadOnlyError, and SqlError.
|
|
63
|
+
*
|
|
64
|
+
* @see CollectionService — all methods fail with CollectionError
|
|
65
|
+
*/
|
|
66
|
+
export type CollectionError = NotFoundError | ForbiddenError | ValidationError | ReadOnlyError | SqlError.SqlError;
|
|
67
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/collection-service/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE3D,OAAO,EAAE,eAAe,EAAE,CAAA;;;;AAE1B;;;;;;;;;;GAUG;AACH,qBAAa,aAAc,SAAQ,mBAAkC;IACnE,UAAU,EAAE,MAAM,CAAA;IAClB,EAAE,EAAE,MAAM,CAAA;CACX,CAAC;CAAG;;;;AAEL;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,oBAAmC;IACrE,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;CACf,CAAC;CAAG;;;;AAEL;;;;;;;;;;GAUG;AACH,qBAAa,aAAc,SAAQ,mBAAkC;IACnE,UAAU,EAAE,MAAM,CAAA;CACnB,CAAC;CAAG;AAEL;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GACvB,aAAa,GACb,cAAc,GACd,eAAe,GACf,aAAa,GACb,QAAQ,CAAC,QAAQ,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Data } from "effect";
|
|
2
|
+
import { ValidationError } from "@gettersethya/mira-client";
|
|
3
|
+
export { ValidationError };
|
|
4
|
+
/**
|
|
5
|
+
* Error raised when a requested record is not found.
|
|
6
|
+
* Contains the collection name and the requested record ID.
|
|
7
|
+
*
|
|
8
|
+
* The server returns HTTP 404 when this error propagates to the HTTP layer.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* new NotFoundError({ collection: "posts", id: "abc123" })
|
|
12
|
+
*
|
|
13
|
+
* @see CollectionService — raises this error on getOne/update/delete for missing records
|
|
14
|
+
*/
|
|
15
|
+
export class NotFoundError extends Data.TaggedError("NotFoundError") {
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Error raised when an action is forbidden by access rules.
|
|
19
|
+
* Contains the collection name and the attempted action.
|
|
20
|
+
*
|
|
21
|
+
* The server returns HTTP 403 when this error propagates to the HTTP layer.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* new ForbiddenError({ collection: "posts", action: "update" })
|
|
25
|
+
*
|
|
26
|
+
* @see CollectionService — raises this error when rules deny an action
|
|
27
|
+
*/
|
|
28
|
+
export class ForbiddenError extends Data.TaggedError("ForbiddenError") {
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Error raised when a write operation is attempted on a read-only collection.
|
|
32
|
+
* View collections always raise this on create/update/delete.
|
|
33
|
+
*
|
|
34
|
+
* The server returns HTTP 405 (Method Not Allowed) when this error propagates.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* new ReadOnlyError({ collection: "active_posts" })
|
|
38
|
+
*
|
|
39
|
+
* @see ViewCollection — view collections are read-only
|
|
40
|
+
*/
|
|
41
|
+
export class ReadOnlyError extends Data.TaggedError("ReadOnlyError") {
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/collection-service/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAE7B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAE3D,OAAO,EAAE,eAAe,EAAE,CAAA;AAE1B;;;;;;;;;;GAUG;AACH,MAAM,OAAO,aAAc,SAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAGjE;CAAG;AAEL;;;;;;;;;;GAUG;AACH,MAAM,OAAO,cAAe,SAAQ,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAGnE;CAAG;AAEL;;;;;;;;;;GAUG;AACH,MAAM,OAAO,aAAc,SAAQ,IAAI,CAAC,WAAW,CAAC,eAAe,CAEjE;CAAG"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { CollectionService, CollectionServiceLive, makeCollectionServiceLayer } from "./collection-service.js";
|
|
2
|
+
export type { CollectionError } from "./errors.js";
|
|
3
|
+
export { ForbiddenError, NotFoundError, ReadOnlyError, ValidationError } from "./errors.js";
|
|
4
|
+
export type { CursorPage, RequestCtx } from "./context.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/collection-service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AAC9G,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC3F,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/collection-service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AAE9G,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ParseResult, Schema } from "effect";
|
|
2
|
+
import type { AnyCollectionDef } from "@gettersethya/mira-client";
|
|
3
|
+
import { ValidationError } from "./errors.js";
|
|
4
|
+
export type InputSchemas = {
|
|
5
|
+
create: Schema.Schema<any, any, never>;
|
|
6
|
+
update: Schema.Schema<any, any, never>;
|
|
7
|
+
};
|
|
8
|
+
export declare function buildInputSchemas(colDef: AnyCollectionDef): InputSchemas;
|
|
9
|
+
export declare function parseErrToValidationError(collection: string): (err: ParseResult.ParseError) => ValidationError;
|
|
10
|
+
//# sourceMappingURL=input-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-schema.d.ts","sourceRoot":"","sources":["../../../src/collection-service/input-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAgD,MAAM,2BAA2B,CAAA;AAC/G,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAI7C,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;CACvC,CAAA;AAgFD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,YAAY,CAiCxE;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,IAClD,KAAK,WAAW,CAAC,UAAU,KAAG,eAAe,CAOtD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { ParseResult, Schema } from "effect";
|
|
2
|
+
import { ValidationError } from "./errors.js";
|
|
3
|
+
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4
|
+
function filterAnnotations(kind, errorFn) {
|
|
5
|
+
if (errorFn === undefined)
|
|
6
|
+
return undefined;
|
|
7
|
+
const msg = errorFn(kind);
|
|
8
|
+
if (msg === undefined)
|
|
9
|
+
return undefined;
|
|
10
|
+
return { message: () => msg };
|
|
11
|
+
}
|
|
12
|
+
function propertyToSchema(prop, fieldDef) {
|
|
13
|
+
const errorFn = fieldDef?.error;
|
|
14
|
+
if (prop["x-kind"] === "json")
|
|
15
|
+
return Schema.Unknown;
|
|
16
|
+
if (prop["x-kind"] === "date" ||
|
|
17
|
+
prop["x-kind"] === "relation" ||
|
|
18
|
+
prop["x-kind"] === "file")
|
|
19
|
+
return Schema.String;
|
|
20
|
+
if (prop.type === "string") {
|
|
21
|
+
const typeMsg = errorFn?.("type");
|
|
22
|
+
const base = typeMsg !== undefined
|
|
23
|
+
? Schema.String.annotations({ message: () => typeMsg })
|
|
24
|
+
: Schema.String;
|
|
25
|
+
let s = base;
|
|
26
|
+
if (prop.format === "email") {
|
|
27
|
+
s = s.pipe(Schema.pattern(EMAIL_RE, filterAnnotations("email", errorFn)));
|
|
28
|
+
}
|
|
29
|
+
if (prop.minLength !== undefined) {
|
|
30
|
+
s = s.pipe(Schema.minLength(prop.minLength, filterAnnotations("minLength", errorFn)));
|
|
31
|
+
}
|
|
32
|
+
if (prop.maxLength !== undefined) {
|
|
33
|
+
s = s.pipe(Schema.maxLength(prop.maxLength, filterAnnotations("maxLength", errorFn)));
|
|
34
|
+
}
|
|
35
|
+
return s;
|
|
36
|
+
}
|
|
37
|
+
if (prop.type === "integer") {
|
|
38
|
+
const typeMsg = errorFn?.("type");
|
|
39
|
+
const base = typeMsg !== undefined
|
|
40
|
+
? Schema.Number.annotations({ message: () => typeMsg })
|
|
41
|
+
: Schema.Number;
|
|
42
|
+
let s = base.pipe(Schema.int(filterAnnotations("int", errorFn)));
|
|
43
|
+
if (prop.minimum !== undefined) {
|
|
44
|
+
s = s.pipe(Schema.greaterThanOrEqualTo(prop.minimum, filterAnnotations("minimum", errorFn)));
|
|
45
|
+
}
|
|
46
|
+
if (prop.maximum !== undefined) {
|
|
47
|
+
s = s.pipe(Schema.lessThanOrEqualTo(prop.maximum, filterAnnotations("maximum", errorFn)));
|
|
48
|
+
}
|
|
49
|
+
return s;
|
|
50
|
+
}
|
|
51
|
+
if (prop.type === "number") {
|
|
52
|
+
const typeMsg = errorFn?.("type");
|
|
53
|
+
const base = typeMsg !== undefined
|
|
54
|
+
? Schema.Number.annotations({ message: () => typeMsg })
|
|
55
|
+
: Schema.Number;
|
|
56
|
+
let s = base;
|
|
57
|
+
if (prop.minimum !== undefined) {
|
|
58
|
+
s = s.pipe(Schema.greaterThanOrEqualTo(prop.minimum, filterAnnotations("minimum", errorFn)));
|
|
59
|
+
}
|
|
60
|
+
if (prop.maximum !== undefined) {
|
|
61
|
+
s = s.pipe(Schema.lessThanOrEqualTo(prop.maximum, filterAnnotations("maximum", errorFn)));
|
|
62
|
+
}
|
|
63
|
+
return s;
|
|
64
|
+
}
|
|
65
|
+
if (prop.type === "boolean") {
|
|
66
|
+
const typeMsg = errorFn?.("type");
|
|
67
|
+
return typeMsg !== undefined
|
|
68
|
+
? Schema.Boolean.annotations({ message: () => typeMsg })
|
|
69
|
+
: Schema.Boolean;
|
|
70
|
+
}
|
|
71
|
+
return Schema.Unknown;
|
|
72
|
+
}
|
|
73
|
+
export function buildInputSchemas(colDef) {
|
|
74
|
+
const schema = colDef.schema;
|
|
75
|
+
const required = new Set(schema.required ?? []);
|
|
76
|
+
const createFields = {};
|
|
77
|
+
const updateFields = {};
|
|
78
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
79
|
+
if (prop["x-system"] === true)
|
|
80
|
+
continue;
|
|
81
|
+
const fieldDef = colDef.fields[key];
|
|
82
|
+
const errorFn = fieldDef?.error;
|
|
83
|
+
const base = propertyToSchema(prop, fieldDef);
|
|
84
|
+
if (required.has(key)) {
|
|
85
|
+
const requiredMsg = errorFn?.("required");
|
|
86
|
+
createFields[key] = requiredMsg !== undefined
|
|
87
|
+
? Schema.propertySignature(base).annotations({ missingMessage: () => requiredMsg })
|
|
88
|
+
: base;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
createFields[key] = Schema.optional(base);
|
|
92
|
+
}
|
|
93
|
+
updateFields[key] = Schema.optional(base);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
create: Schema.Struct(createFields),
|
|
97
|
+
update: Schema.Struct(updateFields)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export function parseErrToValidationError(collection) {
|
|
101
|
+
return (err) => {
|
|
102
|
+
const issues = ParseResult.ArrayFormatter.formatIssueSync(err.issue).map((i) => {
|
|
103
|
+
const prefix = i.path.length > 0 ? `${i.path.join(".")}: ` : "";
|
|
104
|
+
return `${prefix}${i.message}`;
|
|
105
|
+
});
|
|
106
|
+
return new ValidationError({ collection, issues });
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=input-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-schema.js","sourceRoot":"","sources":["../../../src/collection-service/input-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { CollectionSchema } from "@gettersethya/mira-client";
|
|
3
|
+
import type { EnforceResult } from "../rule/enforcer.js";
|
|
4
|
+
import type { RepoRecord, SortOrder, WhereClause } from "../repository/types.js";
|
|
5
|
+
import type { RequestCtx } from "./context.js";
|
|
6
|
+
import { ForbiddenError } from "./errors.js";
|
|
7
|
+
/** Combines two WHERE clauses with AND. Both inputs are trusted internal code. */
|
|
8
|
+
export declare function andWhere(a: WhereClause, b: WhereClause): WhereClause;
|
|
9
|
+
/** Produces a WHERE clause that matches a single record by id. */
|
|
10
|
+
export declare function idClause(id: string): WhereClause;
|
|
11
|
+
/** Produces a WHERE clause for cursor pagination: seqId strictly after the given cursor. */
|
|
12
|
+
export declare function cursorClause(after: number): WhereClause;
|
|
13
|
+
/**
|
|
14
|
+
* Resolves `@auth_<field>` and `@request_<source>_<key>` placeholders produced by the
|
|
15
|
+
* rule compiler into positional `?` params bound from `RequestCtx`.
|
|
16
|
+
*
|
|
17
|
+
* The replacement is done in a single left-to-right pass so that the param array stays
|
|
18
|
+
* in the same order as the `?` placeholders in the resulting SQL.
|
|
19
|
+
*
|
|
20
|
+
* Returns `ForbiddenError` if the rule references auth but `ctx.auth` is absent.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveCtxPlaceholders(result: EnforceResult, ctx: RequestCtx, collection: string, action: string): Effect.Effect<{
|
|
23
|
+
sql: string;
|
|
24
|
+
params: unknown[];
|
|
25
|
+
}, ForbiddenError, never>;
|
|
26
|
+
/**
|
|
27
|
+
* Replaces `t.<fieldName>` column references in a WHERE clause with `?` params
|
|
28
|
+
* bound to the corresponding values in `record`.
|
|
29
|
+
*
|
|
30
|
+
* Used for the `create` permission pre-check: `SELECT 1 WHERE <rule>` without a FROM.
|
|
31
|
+
* The replacement is done left-to-right to preserve param ordering with existing `?`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveFieldRefs(clause: WhereClause, record: RepoRecord): WhereClause;
|
|
34
|
+
export declare function buildUserSort(query: RequestCtx["query"], schema: CollectionSchema): SortOrder | null;
|
|
35
|
+
//# sourceMappingURL=where.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"where.d.ts","sourceRoot":"","sources":["../../../src/collection-service/where.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,WAAW,CAKpE;AAED,kEAAkE;AAClE,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAEhD;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAEvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;0BA+BhH;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,GAAG,WAAW,CAgBrF;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,EAC1B,MAAM,EAAE,gBAAgB,GACvB,SAAS,GAAG,IAAI,CAMlB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { ForbiddenError } from "./errors.js";
|
|
3
|
+
/** Combines two WHERE clauses with AND. Both inputs are trusted internal code. */
|
|
4
|
+
export function andWhere(a, b) {
|
|
5
|
+
return {
|
|
6
|
+
sql: `(${a.sql}) AND (${b.sql})`,
|
|
7
|
+
params: [...a.params, ...b.params]
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/** Produces a WHERE clause that matches a single record by id. */
|
|
11
|
+
export function idClause(id) {
|
|
12
|
+
return { sql: "t.id = ?", params: [id] };
|
|
13
|
+
}
|
|
14
|
+
/** Produces a WHERE clause for cursor pagination: seqId strictly after the given cursor. */
|
|
15
|
+
export function cursorClause(after) {
|
|
16
|
+
return { sql: "t.seqId > ?", params: [after] };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves `@auth_<field>` and `@request_<source>_<key>` placeholders produced by the
|
|
20
|
+
* rule compiler into positional `?` params bound from `RequestCtx`.
|
|
21
|
+
*
|
|
22
|
+
* The replacement is done in a single left-to-right pass so that the param array stays
|
|
23
|
+
* in the same order as the `?` placeholders in the resulting SQL.
|
|
24
|
+
*
|
|
25
|
+
* Returns `ForbiddenError` if the rule references auth but `ctx.auth` is absent.
|
|
26
|
+
*/
|
|
27
|
+
export function resolveCtxPlaceholders(result, ctx, collection, action) {
|
|
28
|
+
return Effect.gen(function* () {
|
|
29
|
+
const needsAuth = /@auth_\w+/.test(result.sql);
|
|
30
|
+
if (needsAuth && ctx.auth === undefined) {
|
|
31
|
+
return yield* new ForbiddenError({ collection, action });
|
|
32
|
+
}
|
|
33
|
+
const resolved = [];
|
|
34
|
+
let pIdx = 0;
|
|
35
|
+
const { params } = result;
|
|
36
|
+
// Single-pass left-to-right replacement preserves param ordering.
|
|
37
|
+
// Groups: (1) @auth field, (2) @request source, (3) @request key
|
|
38
|
+
const newSql = result.sql.replace(/\?|@auth_(\w+)|@request_(\w+)_(\w+)/g, (match, g1, g2, g3) => {
|
|
39
|
+
const authField = typeof g1 === "string" ? g1 : undefined;
|
|
40
|
+
const reqSource = typeof g2 === "string" ? g2 : undefined;
|
|
41
|
+
const reqKey = typeof g3 === "string" ? g3 : undefined;
|
|
42
|
+
if (match === "?") {
|
|
43
|
+
resolved.push(params[pIdx++]);
|
|
44
|
+
}
|
|
45
|
+
else if (authField !== undefined) {
|
|
46
|
+
resolved.push(ctx.auth?.record[authField] ?? null);
|
|
47
|
+
}
|
|
48
|
+
else if (reqSource !== undefined && reqKey !== undefined) {
|
|
49
|
+
const val = reqSource === "query" ? ctx.query[reqKey] : ctx.headers[reqKey];
|
|
50
|
+
resolved.push(Array.isArray(val) ? val[0] : (val ?? null));
|
|
51
|
+
}
|
|
52
|
+
return "?";
|
|
53
|
+
});
|
|
54
|
+
return yield* Effect.succeed({ sql: newSql, params: resolved });
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Replaces `t.<fieldName>` column references in a WHERE clause with `?` params
|
|
59
|
+
* bound to the corresponding values in `record`.
|
|
60
|
+
*
|
|
61
|
+
* Used for the `create` permission pre-check: `SELECT 1 WHERE <rule>` without a FROM.
|
|
62
|
+
* The replacement is done left-to-right to preserve param ordering with existing `?`.
|
|
63
|
+
*/
|
|
64
|
+
export function resolveFieldRefs(clause, record) {
|
|
65
|
+
const resolved = [];
|
|
66
|
+
let pIdx = 0;
|
|
67
|
+
const { params } = clause;
|
|
68
|
+
const newSql = clause.sql.replace(/\?|\bt\.(\w+)\b/g, (_, g1) => {
|
|
69
|
+
const field = typeof g1 === "string" ? g1 : undefined;
|
|
70
|
+
if (field !== undefined) {
|
|
71
|
+
resolved.push(record[field] ?? null);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
resolved.push(params[pIdx++]);
|
|
75
|
+
}
|
|
76
|
+
return "?";
|
|
77
|
+
});
|
|
78
|
+
return { sql: newSql, params: resolved };
|
|
79
|
+
}
|
|
80
|
+
export function buildUserSort(query, schema) {
|
|
81
|
+
const sortField = typeof query["sort"] === "string" ? query["sort"] : null;
|
|
82
|
+
if (sortField === null || !schema.properties[sortField])
|
|
83
|
+
return null;
|
|
84
|
+
const rawOrder = typeof query["order"] === "string" ? query["order"] : null;
|
|
85
|
+
const direction = rawOrder === "desc" ? "desc" : "asc";
|
|
86
|
+
return { field: sortField, direction };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=where.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"where.js","sourceRoot":"","sources":["../../../src/collection-service/where.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { SqlClient } from "@effect/sql";
|
|
2
|
+
import { CryptoService } from "../crypto/index.js";
|
|
3
|
+
import { Context, Layer } from "effect";
|
|
4
|
+
import type { AppConfigShape } from "./types.js";
|
|
5
|
+
declare const AppConfig_base: Context.TagClass<AppConfig, "AppConfig", AppConfigShape>;
|
|
6
|
+
/**
|
|
7
|
+
* Application configuration tag, backed by the `_config` table in the database.
|
|
8
|
+
*
|
|
9
|
+
* On first boot, seeds default values (including an auto-generated `jwt_secret`)
|
|
10
|
+
* into the `_config` table. Runtime reads go through the database — no env vars
|
|
11
|
+
* or config files are needed for basic operation.
|
|
12
|
+
*
|
|
13
|
+
* Provides access to:
|
|
14
|
+
* - `appName`, `port`, `applicationUrl` — basic server configuration
|
|
15
|
+
* - `jwtSecret` — Redacted JWT signing secret (auto-generated)
|
|
16
|
+
* - `useS3`, `s3Config` — optional S3 storage configuration
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { AppConfig } from "@gettersethya/mira"
|
|
20
|
+
*
|
|
21
|
+
* Effect.gen(function* () {
|
|
22
|
+
* const cfg = yield* AppConfig
|
|
23
|
+
* console.log(cfg.appName, cfg.port)
|
|
24
|
+
* const secret = cfg.jwtSecret // Redacted<string>
|
|
25
|
+
* })
|
|
26
|
+
*
|
|
27
|
+
* @see AppConfigLive — the live layer implementation
|
|
28
|
+
* @see AppConfigShape — the full config shape
|
|
29
|
+
*/
|
|
30
|
+
export declare class AppConfig extends AppConfig_base {
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Live layer for `AppConfig`.
|
|
34
|
+
* Seeds the `_config` table on first boot with sensible defaults
|
|
35
|
+
* (including auto-generating `jwt_secret` via CryptoService).
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* Layer.provideMerge(AppConfigLive)
|
|
39
|
+
*
|
|
40
|
+
* @see AppConfig — the service tag
|
|
41
|
+
*/
|
|
42
|
+
export declare const AppConfigLive: Layer.Layer<AppConfig, import("effect/ParseResult").ParseError | import("@effect/sql/SqlError").SqlError, CryptoService | SqlClient.SqlClient>;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAU,KAAK,EAA4B,MAAM,QAAQ,CAAA;AACzE,OAAO,KAAK,EAAE,cAAc,EAAY,MAAM,YAAY,CAAA;;AAO1D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,SAAU,SAAQ,cAAqD;CAAG;AAEvF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,gJA8DzB,CAAA"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { SqlClient, SqlSchema } from "@effect/sql";
|
|
2
|
+
import { CryptoService } from "../crypto/index.js";
|
|
3
|
+
import { Context, Effect, Layer, Option, Redacted, Schema } from "effect";
|
|
4
|
+
const ConfigRowSchema = Schema.Struct({
|
|
5
|
+
key: Schema.String,
|
|
6
|
+
value: Schema.String
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Application configuration tag, backed by the `_config` table in the database.
|
|
10
|
+
*
|
|
11
|
+
* On first boot, seeds default values (including an auto-generated `jwt_secret`)
|
|
12
|
+
* into the `_config` table. Runtime reads go through the database — no env vars
|
|
13
|
+
* or config files are needed for basic operation.
|
|
14
|
+
*
|
|
15
|
+
* Provides access to:
|
|
16
|
+
* - `appName`, `port`, `applicationUrl` — basic server configuration
|
|
17
|
+
* - `jwtSecret` — Redacted JWT signing secret (auto-generated)
|
|
18
|
+
* - `useS3`, `s3Config` — optional S3 storage configuration
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* import { AppConfig } from "@gettersethya/mira"
|
|
22
|
+
*
|
|
23
|
+
* Effect.gen(function* () {
|
|
24
|
+
* const cfg = yield* AppConfig
|
|
25
|
+
* console.log(cfg.appName, cfg.port)
|
|
26
|
+
* const secret = cfg.jwtSecret // Redacted<string>
|
|
27
|
+
* })
|
|
28
|
+
*
|
|
29
|
+
* @see AppConfigLive — the live layer implementation
|
|
30
|
+
* @see AppConfigShape — the full config shape
|
|
31
|
+
*/
|
|
32
|
+
export class AppConfig extends Context.Tag("AppConfig")() {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Live layer for `AppConfig`.
|
|
36
|
+
* Seeds the `_config` table on first boot with sensible defaults
|
|
37
|
+
* (including auto-generating `jwt_secret` via CryptoService).
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* Layer.provideMerge(AppConfigLive)
|
|
41
|
+
*
|
|
42
|
+
* @see AppConfig — the service tag
|
|
43
|
+
*/
|
|
44
|
+
export const AppConfigLive = Layer.effect(AppConfig, Effect.gen(function* () {
|
|
45
|
+
const sql = yield* SqlClient.SqlClient;
|
|
46
|
+
// DDL — sql.unsafe is fine for CREATE TABLE
|
|
47
|
+
yield* sql.unsafe(`CREATE TABLE IF NOT EXISTS _config (key TEXT PRIMARY KEY, value TEXT NOT NULL)`);
|
|
48
|
+
const rows = yield* SqlSchema.findAll({
|
|
49
|
+
Request: Schema.Void,
|
|
50
|
+
Result: ConfigRowSchema,
|
|
51
|
+
execute: () => sql `SELECT key, value FROM ${sql("_config")}`
|
|
52
|
+
})(undefined);
|
|
53
|
+
const stored = new Map(rows.map((r) => [r.key, r.value]));
|
|
54
|
+
const seed = (key, defaultValue) => Effect.gen(function* () {
|
|
55
|
+
const existing = stored.get(key);
|
|
56
|
+
if (existing !== undefined)
|
|
57
|
+
return existing;
|
|
58
|
+
yield* sql `INSERT INTO ${sql("_config")} ${sql.insert({ key, value: defaultValue })}`;
|
|
59
|
+
return defaultValue;
|
|
60
|
+
});
|
|
61
|
+
const require = (key) => Effect.fromNullable(stored.get(key)).pipe(Effect.mapError(() => new Error(`_config key "${key}" is required when use_s3=true`)), Effect.orDie);
|
|
62
|
+
const appName = yield* seed("app_name", "mira");
|
|
63
|
+
const port = Number(yield* seed("port", "8080"));
|
|
64
|
+
const applicationUrl = yield* seed("application_url", `http://localhost:${port}`);
|
|
65
|
+
// Generated once on first boot, persisted so tokens survive restarts
|
|
66
|
+
const existingSecret = stored.get("jwt_secret");
|
|
67
|
+
const jwtSecretStr = existingSecret !== undefined
|
|
68
|
+
? existingSecret
|
|
69
|
+
: yield* Effect.gen(function* () {
|
|
70
|
+
const cryptoSvc = yield* CryptoService;
|
|
71
|
+
const generated = Buffer.from(yield* cryptoSvc.randomBytes(48)).toString("hex");
|
|
72
|
+
yield* sql `INSERT INTO ${sql("_config")} ${sql.insert({ key: "jwt_secret", value: generated })}`;
|
|
73
|
+
yield* Effect.logInfo("jwt_secret generated and persisted to _config table.");
|
|
74
|
+
return generated;
|
|
75
|
+
});
|
|
76
|
+
const jwtSecret = Redacted.make(jwtSecretStr);
|
|
77
|
+
const useS3 = (yield* seed("use_s3", "false")) === "true";
|
|
78
|
+
const s3Config = useS3
|
|
79
|
+
? Option.some({
|
|
80
|
+
endpoint: Redacted.make(yield* require("s3_endpoint")),
|
|
81
|
+
bucketName: yield* require("s3_bucket_name"),
|
|
82
|
+
regionName: yield* require("s3_region_name"),
|
|
83
|
+
accessKey: Redacted.make(yield* require("s3_access_key")),
|
|
84
|
+
secret: Redacted.make(yield* require("s3_secret"))
|
|
85
|
+
})
|
|
86
|
+
: Option.none();
|
|
87
|
+
return { appName, port, applicationUrl, jwtSecret, useS3, s3Config };
|
|
88
|
+
}));
|
|
89
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/config/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGzE,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC,MAAM;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM;CACrB,CAAC,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,SAAU,SAAQ,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAA6B;CAAG;AAEvF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CACvC,SAAS,EACT,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAA;IAEtC,4CAA4C;IAC5C,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,gFAAgF,CAAC,CAAA;IAEnG,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC;QACpC,OAAO,EAAE,MAAM,CAAC,IAAI;QACpB,MAAM,EAAE,eAAe;QACvB,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAA,0BAA0B,GAAG,CAAC,SAAS,CAAC,EAAE;KAC7D,CAAC,CAAC,SAAS,CAAC,CAAA;IAEb,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAEzD,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,YAAoB,EAAE,EAAE,CACjD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO,QAAQ,CAAA;QAC3C,KAAK,CAAC,CAAC,GAAG,CAAA,eAAe,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,CAAA;QACrF,OAAO,YAAY,CAAA;IACrB,CAAC,CAAC,CAAA;IAEJ,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,EAAE,CAC9B,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CACvC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,gBAAgB,GAAG,gCAAgC,CAAC,CAAC,EACrF,MAAM,CAAC,KAAK,CACb,CAAA;IAEH,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChD,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAA;IAEjF,qEAAqE;IACrE,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;IAC/C,MAAM,YAAY,GAChB,cAAc,KAAK,SAAS;QAC1B,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACzB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,aAAa,CAAA;YACtC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;YAC/E,KAAK,CAAC,CAAC,GAAG,CAAA,eAAe,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,CAAA;YAChG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,sDAAsD,CAAC,CAAA;YAC7E,OAAO,SAAS,CAAA;QAClB,CAAC,CAAC,CAAA;IACR,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IAE7C,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,MAAM,CAAA;IAEzD,MAAM,QAAQ,GAA4B,KAAK;QAC7C,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACtD,UAAU,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC;YAC5C,UAAU,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC;YAC5C,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YACzD,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;SACnD,CAAC;QACJ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAA;IAEjB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;AACtE,CAAC,CAAC,CACH,CAAA"}
|