silgi 0.43.29 → 0.50.0
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/README.md +103 -1
- package/dist/_virtual/_rolldown/runtime.mjs +5 -0
- package/dist/adapters/_fetch-adapter.d.mts +18 -0
- package/dist/adapters/_fetch-adapter.mjs +53 -0
- package/dist/adapters/astro.d.mts +15 -0
- package/dist/adapters/astro.mjs +31 -0
- package/dist/adapters/aws-lambda.d.mts +42 -0
- package/dist/adapters/aws-lambda.mjs +92 -0
- package/dist/adapters/express.d.mts +16 -0
- package/dist/adapters/express.mjs +110 -0
- package/dist/adapters/message-port.d.mts +42 -0
- package/dist/adapters/message-port.mjs +132 -0
- package/dist/adapters/nestjs.d.mts +25 -0
- package/dist/adapters/nestjs.mjs +83 -0
- package/dist/adapters/nextjs.d.mts +14 -0
- package/dist/adapters/nextjs.mjs +29 -0
- package/dist/adapters/peer.d.mts +27 -0
- package/dist/adapters/peer.mjs +36 -0
- package/dist/adapters/remix.d.mts +15 -0
- package/dist/adapters/remix.mjs +30 -0
- package/dist/adapters/solidstart.d.mts +12 -0
- package/dist/adapters/solidstart.mjs +29 -0
- package/dist/adapters/sveltekit.d.mts +14 -0
- package/dist/adapters/sveltekit.mjs +30 -0
- package/dist/broker/index.d.mts +62 -0
- package/dist/broker/index.mjs +153 -0
- package/dist/broker/nats.d.mts +33 -0
- package/dist/broker/nats.mjs +31 -0
- package/dist/broker/redis.d.mts +51 -0
- package/dist/broker/redis.mjs +92 -0
- package/dist/builder.d.mts +55 -0
- package/dist/builder.mjs +70 -0
- package/dist/callable.d.mts +19 -0
- package/dist/callable.mjs +42 -0
- package/dist/caller.mjs +90 -0
- package/dist/client/adapters/fetch/index.d.mts +15 -0
- package/dist/client/adapters/fetch/index.mjs +57 -0
- package/dist/client/adapters/ofetch/index.d.mts +55 -0
- package/dist/client/adapters/ofetch/index.mjs +91 -0
- package/dist/client/adapters/websocket/index.d.mts +20 -0
- package/dist/client/adapters/websocket/index.mjs +101 -0
- package/dist/client/client.d.mts +37 -0
- package/dist/client/client.mjs +80 -0
- package/dist/client/consume.d.mts +50 -0
- package/dist/client/consume.mjs +66 -0
- package/dist/client/dynamic-link.d.mts +16 -0
- package/dist/client/dynamic-link.mjs +19 -0
- package/dist/client/index.d.mts +6 -0
- package/dist/client/index.mjs +5 -0
- package/dist/client/interceptor.d.mts +31 -0
- package/dist/client/interceptor.mjs +34 -0
- package/dist/client/openapi.d.mts +29 -0
- package/dist/client/openapi.mjs +89 -0
- package/dist/client/plugins/batch.d.mts +26 -0
- package/dist/client/plugins/batch.mjs +64 -0
- package/dist/client/plugins/circuit-breaker.d.mts +24 -0
- package/dist/client/plugins/circuit-breaker.mjs +60 -0
- package/dist/client/plugins/csrf.d.mts +13 -0
- package/dist/client/plugins/csrf.mjs +20 -0
- package/dist/client/plugins/dedupe.d.mts +10 -0
- package/dist/client/plugins/dedupe.mjs +28 -0
- package/dist/client/plugins/index.d.mts +8 -0
- package/dist/client/plugins/index.mjs +8 -0
- package/dist/client/plugins/otel.d.mts +12 -0
- package/dist/client/plugins/otel.mjs +27 -0
- package/dist/client/plugins/retry.d.mts +34 -0
- package/dist/client/plugins/retry.mjs +79 -0
- package/dist/client/plugins/timeout.d.mts +10 -0
- package/dist/client/plugins/timeout.mjs +14 -0
- package/dist/client/server.d.mts +16 -0
- package/dist/client/server.mjs +59 -0
- package/dist/client/types.d.mts +29 -0
- package/dist/codec/devalue.d.mts +21 -0
- package/dist/codec/devalue.mjs +33 -0
- package/dist/codec/msgpack.d.mts +18 -0
- package/dist/codec/msgpack.mjs +45 -0
- package/dist/codec/sanitize.mjs +38 -0
- package/dist/codegen/emitters.d.mts +51 -0
- package/dist/codegen/emitters.mjs +143 -0
- package/dist/codegen/generate.d.mts +25 -0
- package/dist/codegen/generate.mjs +224 -0
- package/dist/codegen/index.d.mts +44 -0
- package/dist/codegen/index.mjs +103 -0
- package/dist/codegen/parse.d.mts +124 -0
- package/dist/codegen/parse.mjs +135 -0
- package/dist/codegen/preserve.d.mts +21 -0
- package/dist/codegen/preserve.mjs +62 -0
- package/dist/codegen/schema-to-code.d.mts +57 -0
- package/dist/codegen/schema-to-code.mjs +167 -0
- package/dist/compile.d.mts +46 -0
- package/dist/compile.mjs +332 -0
- package/dist/core/codec.mjs +67 -0
- package/dist/core/context-bridge.mjs +11 -0
- package/dist/core/dispatch.mjs +62 -0
- package/dist/core/error.d.mts +99 -60
- package/dist/core/error.mjs +125 -92
- package/dist/core/handler.d.mts +6 -0
- package/dist/core/handler.mjs +153 -0
- package/dist/core/input.mjs +49 -0
- package/dist/core/iterator.d.mts +17 -0
- package/dist/core/iterator.mjs +79 -0
- package/dist/core/router-utils.mjs +22 -0
- package/dist/core/schema.d.mts +20 -0
- package/dist/core/schema.mjs +33 -0
- package/dist/core/serve.d.mts +51 -0
- package/dist/core/serve.mjs +76 -0
- package/dist/core/sse.d.mts +18 -0
- package/dist/core/sse.mjs +110 -0
- package/dist/core/storage.d.mts +17 -4
- package/dist/core/storage.mjs +60 -13
- package/dist/core/task.d.mts +62 -0
- package/dist/core/task.mjs +165 -0
- package/dist/core/trace-map.d.mts +13 -0
- package/dist/core/trace-map.mjs +13 -0
- package/dist/core/url.mjs +28 -0
- package/dist/core/utils.mjs +24 -0
- package/dist/index.d.mts +17 -21
- package/dist/index.mjs +14 -22
- package/dist/integrations/ai/index.d.mts +25 -0
- package/dist/integrations/ai/index.mjs +117 -0
- package/dist/integrations/better-auth/index.d.mts +41 -0
- package/dist/integrations/better-auth/index.mjs +331 -0
- package/dist/integrations/drizzle/index.d.mts +27 -0
- package/dist/integrations/drizzle/index.mjs +285 -0
- package/dist/integrations/hey-api/index.d.mts +2 -0
- package/dist/integrations/hey-api/index.mjs +2 -0
- package/dist/integrations/hey-api/to-client.d.mts +20 -0
- package/dist/integrations/hey-api/to-client.mjs +39 -0
- package/dist/integrations/pinia-colada/general-utils.d.mts +13 -0
- package/dist/integrations/pinia-colada/general-utils.mjs +9 -0
- package/dist/integrations/pinia-colada/index.d.mts +6 -0
- package/dist/integrations/pinia-colada/index.mjs +5 -0
- package/dist/integrations/pinia-colada/key.d.mts +11 -0
- package/dist/integrations/pinia-colada/key.mjs +11 -0
- package/dist/integrations/pinia-colada/procedure-utils.d.mts +25 -0
- package/dist/integrations/pinia-colada/procedure-utils.mjs +33 -0
- package/dist/integrations/pinia-colada/router-utils.d.mts +17 -0
- package/dist/integrations/pinia-colada/router-utils.mjs +30 -0
- package/dist/integrations/pinia-colada/types.d.mts +25 -0
- package/dist/integrations/react/index.d.mts +83 -0
- package/dist/integrations/react/index.mjs +196 -0
- package/dist/integrations/tanstack-query/index.d.mts +120 -0
- package/dist/integrations/tanstack-query/index.mjs +100 -0
- package/dist/integrations/tanstack-query/ssr.d.mts +60 -0
- package/dist/integrations/tanstack-query/ssr.mjs +102 -0
- package/dist/integrations/zod/converter.d.mts +75 -0
- package/dist/integrations/zod/converter.mjs +345 -0
- package/dist/integrations/zod/index.d.mts +2 -0
- package/dist/integrations/zod/index.mjs +2 -0
- package/dist/lazy.d.mts +22 -0
- package/dist/lazy.mjs +34 -0
- package/dist/lifecycle.d.mts +36 -0
- package/dist/lifecycle.mjs +46 -0
- package/dist/map-input.d.mts +17 -0
- package/dist/map-input.mjs +47 -0
- package/dist/plugins/analytics/accumulator.d.mts +24 -0
- package/dist/plugins/analytics/accumulator.mjs +91 -0
- package/dist/plugins/analytics/alerts.d.mts +59 -0
- package/dist/plugins/analytics/alerts.mjs +140 -0
- package/dist/plugins/analytics/collector.d.mts +38 -0
- package/dist/plugins/analytics/collector.mjs +275 -0
- package/dist/plugins/analytics/cost.d.mts +61 -0
- package/dist/plugins/analytics/cost.mjs +97 -0
- package/dist/plugins/analytics/export.d.mts +7 -0
- package/dist/plugins/analytics/export.mjs +86 -0
- package/dist/plugins/analytics/normalize.mjs +144 -0
- package/dist/plugins/analytics/query.mjs +164 -0
- package/dist/plugins/analytics/request-id.mjs +34 -0
- package/dist/plugins/analytics/routes.d.mts +11 -0
- package/dist/plugins/analytics/routes.mjs +211 -0
- package/dist/plugins/analytics/sse.d.mts +31 -0
- package/dist/plugins/analytics/sse.mjs +74 -0
- package/dist/plugins/analytics/store.mjs +103 -0
- package/dist/plugins/analytics/timeseries.d.mts +50 -0
- package/dist/plugins/analytics/timeseries.mjs +169 -0
- package/dist/plugins/analytics/trace.d.mts +48 -0
- package/dist/plugins/analytics/trace.mjs +83 -0
- package/dist/plugins/analytics/types.d.mts +145 -0
- package/dist/plugins/analytics/types.mjs +40 -0
- package/dist/plugins/analytics/utils.d.mts +4 -0
- package/dist/plugins/analytics/utils.mjs +56 -0
- package/dist/plugins/analytics.d.mts +18 -0
- package/dist/plugins/analytics.mjs +188 -0
- package/dist/plugins/batch-server.d.mts +20 -0
- package/dist/plugins/batch-server.mjs +91 -0
- package/dist/plugins/body-limit.d.mts +19 -0
- package/dist/plugins/body-limit.mjs +49 -0
- package/dist/plugins/cache.d.mts +170 -0
- package/dist/plugins/cache.mjs +212 -0
- package/dist/plugins/coerce.d.mts +24 -0
- package/dist/plugins/coerce.mjs +70 -0
- package/dist/plugins/cookies.d.mts +14 -0
- package/dist/plugins/cookies.mjs +48 -0
- package/dist/plugins/cors.d.mts +43 -0
- package/dist/plugins/cors.mjs +62 -0
- package/dist/plugins/file-upload.d.mts +38 -0
- package/dist/plugins/file-upload.mjs +102 -0
- package/dist/plugins/index.d.mts +18 -0
- package/dist/plugins/index.mjs +17 -0
- package/dist/plugins/otel.d.mts +35 -0
- package/dist/plugins/otel.mjs +40 -0
- package/dist/plugins/pino.d.mts +60 -0
- package/dist/plugins/pino.mjs +42 -0
- package/dist/plugins/pubsub.d.mts +50 -0
- package/dist/plugins/pubsub.mjs +53 -0
- package/dist/plugins/ratelimit.d.mts +53 -0
- package/dist/plugins/ratelimit.mjs +92 -0
- package/dist/plugins/signing.d.mts +41 -0
- package/dist/plugins/signing.mjs +118 -0
- package/dist/plugins/strict-get.d.mts +10 -0
- package/dist/plugins/strict-get.mjs +33 -0
- package/dist/scalar.d.mts +49 -0
- package/dist/scalar.mjs +311 -0
- package/dist/silgi.d.mts +144 -0
- package/dist/silgi.mjs +164 -0
- package/dist/trpc-interop.d.mts +22 -0
- package/dist/trpc-interop.mjs +68 -0
- package/dist/types.d.mts +108 -0
- package/dist/ws.d.mts +88 -0
- package/dist/ws.mjs +205 -0
- package/lib/dashboard/index.html +120 -0
- package/lib/ocache.d.mts +1 -0
- package/lib/ocache.mjs +1 -0
- package/lib/ofetch.d.mts +1 -0
- package/lib/ofetch.mjs +1 -0
- package/lib/srvx.d.mts +1 -0
- package/lib/srvx.mjs +1 -0
- package/lib/unstorage.d.mts +1 -0
- package/lib/unstorage.mjs +1 -0
- package/package.json +314 -150
- package/dist/build.d.mts +0 -3
- package/dist/build.mjs +0 -4
- package/dist/cli/build/build.mjs +0 -15
- package/dist/cli/build/dev.d.mts +0 -10
- package/dist/cli/build/dev.mjs +0 -92
- package/dist/cli/build/prepare.d.mts +0 -6
- package/dist/cli/build/prepare.mjs +0 -15
- package/dist/cli/commands/commands.mjs +0 -90
- package/dist/cli/commands/env.mjs +0 -53
- package/dist/cli/commands/init.mjs +0 -84
- package/dist/cli/commands/install.mjs +0 -52
- package/dist/cli/commands/prepare.mjs +0 -65
- package/dist/cli/commands/reset.mjs +0 -46
- package/dist/cli/commands/run.mjs +0 -31
- package/dist/cli/commands/watch.mjs +0 -153
- package/dist/cli/config/defaults.mjs +0 -117
- package/dist/cli/config/index.d.mts +0 -3
- package/dist/cli/config/index.mjs +0 -4
- package/dist/cli/config/loader.d.mts +0 -6
- package/dist/cli/config/loader.mjs +0 -71
- package/dist/cli/config/resolvers/compatibility.mjs +0 -71
- package/dist/cli/config/resolvers/imports.mjs +0 -35
- package/dist/cli/config/resolvers/paths.mjs +0 -98
- package/dist/cli/config/resolvers/storage.mjs +0 -23
- package/dist/cli/config/resolvers/url.mjs +0 -9
- package/dist/cli/config/types.d.mts +0 -14
- package/dist/cli/config/types.mjs +0 -147
- package/dist/cli/core/apiful.mjs +0 -36
- package/dist/cli/core/devServer.mjs +0 -10
- package/dist/cli/core/env.mjs +0 -68
- package/dist/cli/core/installPackage.mjs +0 -60
- package/dist/cli/core/runtimeConfig.mjs +0 -70
- package/dist/cli/core/scan.mjs +0 -35
- package/dist/cli/core/silgi.mjs +0 -111
- package/dist/cli/framework/emptyFramework.mjs +0 -7
- package/dist/cli/framework/h3.mjs +0 -55
- package/dist/cli/framework/index.mjs +0 -15
- package/dist/cli/framework/nitro.mjs +0 -24
- package/dist/cli/framework/nuxt.mjs +0 -10
- package/dist/cli/index.d.mts +0 -1
- package/dist/cli/index.mjs +0 -29
- package/dist/cli/module/exportScan.mjs +0 -180
- package/dist/cli/module/install.mjs +0 -49
- package/dist/cli/module/scan.mjs +0 -193
- package/dist/cli/scan/prepareCommands.mjs +0 -40
- package/dist/cli/scan/prepareConfigs.mjs +0 -33
- package/dist/cli/scan/prepareCoreFile.mjs +0 -118
- package/dist/cli/scan/prepareScanFile.mjs +0 -59
- package/dist/cli/scan/prepareSchema.mjs +0 -128
- package/dist/cli/scan/scanExportFile.mjs +0 -288
- package/dist/cli/scan/writeCoreFile.mjs +0 -22
- package/dist/cli/scan/writeTypesAndFiles.mjs +0 -72
- package/dist/cli/utils/cancel.mjs +0 -14
- package/dist/cli/utils/common.mjs +0 -15
- package/dist/cli/utils/compatibility.mjs +0 -33
- package/dist/cli/utils/debug.mjs +0 -11
- package/dist/cli/utils/ignore.mjs +0 -56
- package/dist/cli/utils/processManager.mjs +0 -170
- package/dist/cli/utils/readScanFile.mjs +0 -58
- package/dist/cli/utils/storage.mjs +0 -23
- package/dist/core/context.d.mts +0 -30
- package/dist/core/context.mjs +0 -32
- package/dist/core/createSilgi.d.mts +0 -6
- package/dist/core/createSilgi.mjs +0 -153
- package/dist/core/event.d.mts +0 -26
- package/dist/core/event.mjs +0 -44
- package/dist/core/index.d.mts +0 -25
- package/dist/core/index.mjs +0 -30
- package/dist/core/orchestrate.mjs +0 -115
- package/dist/core/response.d.mts +0 -20
- package/dist/core/response.mjs +0 -105
- package/dist/core/silgi.d.mts +0 -19
- package/dist/core/silgi.mjs +0 -141
- package/dist/core/silgiApp.d.mts +0 -9
- package/dist/core/silgiApp.mjs +0 -23
- package/dist/core/unctx.d.mts +0 -21
- package/dist/core/unctx.mjs +0 -35
- package/dist/core/utils/event-stream.d.mts +0 -53
- package/dist/core/utils/event-stream.mjs +0 -38
- package/dist/core/utils/event.d.mts +0 -8
- package/dist/core/utils/event.mjs +0 -12
- package/dist/core/utils/internal/event-stream.d.mts +0 -45
- package/dist/core/utils/internal/event-stream.mjs +0 -137
- package/dist/core/utils/internal/obj.mjs +0 -9
- package/dist/core/utils/internal/object.mjs +0 -29
- package/dist/core/utils/internal/query.mjs +0 -73
- package/dist/core/utils/internal/req.mjs +0 -35
- package/dist/core/utils/merge.d.mts +0 -14
- package/dist/core/utils/merge.mjs +0 -27
- package/dist/core/utils/middleware.d.mts +0 -14
- package/dist/core/utils/middleware.mjs +0 -12
- package/dist/core/utils/request.mjs +0 -35
- package/dist/core/utils/resolver.d.mts +0 -7
- package/dist/core/utils/resolver.mjs +0 -29
- package/dist/core/utils/runtime.d.mts +0 -7
- package/dist/core/utils/runtime.mjs +0 -20
- package/dist/core/utils/sanitize.mjs +0 -22
- package/dist/core/utils/schema.d.mts +0 -34
- package/dist/core/utils/schema.mjs +0 -33
- package/dist/core/utils/service.d.mts +0 -13
- package/dist/core/utils/service.mjs +0 -19
- package/dist/core/utils/shared.d.mts +0 -6
- package/dist/core/utils/shared.mjs +0 -7
- package/dist/core/utils/storage.d.mts +0 -24
- package/dist/core/utils/storage.mjs +0 -54
- package/dist/kit/add/add-commands.d.mts +0 -6
- package/dist/kit/add/add-commands.mjs +0 -12
- package/dist/kit/add/add-core-file.d.mts +0 -9
- package/dist/kit/add/add-core-file.mjs +0 -11
- package/dist/kit/add/add-imports.d.mts +0 -14
- package/dist/kit/add/add-imports.mjs +0 -56
- package/dist/kit/add/add-npm.d.mts +0 -14
- package/dist/kit/add/add-npm.mjs +0 -23
- package/dist/kit/define.d.mts +0 -28
- package/dist/kit/define.mjs +0 -25
- package/dist/kit/errors.d.mts +0 -6
- package/dist/kit/errors.mjs +0 -11
- package/dist/kit/esm.d.mts +0 -11
- package/dist/kit/esm.mjs +0 -21
- package/dist/kit/fs.d.mts +0 -4
- package/dist/kit/fs.mjs +0 -13
- package/dist/kit/function-utils.d.mts +0 -27
- package/dist/kit/function-utils.mjs +0 -75
- package/dist/kit/gen.d.mts +0 -5
- package/dist/kit/gen.mjs +0 -26
- package/dist/kit/hash.d.mts +0 -4
- package/dist/kit/hash.mjs +0 -10
- package/dist/kit/index.d.mts +0 -22
- package/dist/kit/index.mjs +0 -23
- package/dist/kit/isFramework.d.mts +0 -6
- package/dist/kit/isFramework.mjs +0 -21
- package/dist/kit/logger.d.mts +0 -6
- package/dist/kit/logger.mjs +0 -10
- package/dist/kit/migration.d.mts +0 -113
- package/dist/kit/migration.mjs +0 -301
- package/dist/kit/module.d.mts +0 -14
- package/dist/kit/module.mjs +0 -53
- package/dist/kit/path.d.mts +0 -7
- package/dist/kit/path.mjs +0 -26
- package/dist/kit/preset.d.mts +0 -8
- package/dist/kit/preset.mjs +0 -11
- package/dist/kit/resolve.d.mts +0 -37
- package/dist/kit/resolve.mjs +0 -82
- package/dist/kit/template.d.mts +0 -19
- package/dist/kit/template.mjs +0 -91
- package/dist/kit/useRequest.d.mts +0 -19
- package/dist/kit/useRequest.mjs +0 -63
- package/dist/kit/utils.d.mts +0 -34
- package/dist/kit/utils.mjs +0 -91
- package/dist/package.mjs +0 -176
- package/dist/presets/_all.gen.d.mts +0 -6
- package/dist/presets/_all.gen.mjs +0 -18
- package/dist/presets/_resolve.d.mts +0 -12
- package/dist/presets/_resolve.mjs +0 -57
- package/dist/presets/_types.gen.d.mts +0 -8
- package/dist/presets/_types.gen.mjs +0 -5
- package/dist/presets/h3/preset.d.mts +0 -6
- package/dist/presets/h3/preset.mjs +0 -35
- package/dist/presets/hono/preset.d.mts +0 -6
- package/dist/presets/hono/preset.mjs +0 -30
- package/dist/presets/index.d.mts +0 -3
- package/dist/presets/index.mjs +0 -3
- package/dist/presets/nitro/preset.d.mts +0 -6
- package/dist/presets/nitro/preset.mjs +0 -37
- package/dist/presets/npmpackage/preset.d.mts +0 -6
- package/dist/presets/npmpackage/preset.mjs +0 -29
- package/dist/presets/nuxt/preset.d.mts +0 -6
- package/dist/presets/nuxt/preset.mjs +0 -41
- package/dist/runtime/index.d.mts +0 -4
- package/dist/runtime/index.mjs +0 -5
- package/dist/runtime/internal/config.d.mts +0 -11
- package/dist/runtime/internal/config.mjs +0 -97
- package/dist/runtime/internal/debug.d.mts +0 -6
- package/dist/runtime/internal/debug.mjs +0 -11
- package/dist/runtime/internal/defu.d.mts +0 -4
- package/dist/runtime/internal/defu.mjs +0 -9
- package/dist/runtime/internal/index.d.mts +0 -7
- package/dist/runtime/internal/index.mjs +0 -8
- package/dist/runtime/internal/nitro.d.mts +0 -6
- package/dist/runtime/internal/nitro.mjs +0 -36
- package/dist/runtime/internal/nuxt.d.mts +0 -12
- package/dist/runtime/internal/nuxt.mjs +0 -16
- package/dist/runtime/internal/ofetch.d.mts +0 -8
- package/dist/runtime/internal/ofetch.mjs +0 -39
- package/dist/runtime/internal/plugin.d.mts +0 -7
- package/dist/runtime/internal/plugin.mjs +0 -8
- package/dist/types/cliConfig.d.mts +0 -288
- package/dist/types/cliConfig.mjs +0 -0
- package/dist/types/cliHooks.d.mts +0 -142
- package/dist/types/cliHooks.mjs +0 -0
- package/dist/types/compatibility.d.mts +0 -13
- package/dist/types/compatibility.mjs +0 -0
- package/dist/types/config.d.mts +0 -46
- package/dist/types/config.mjs +0 -0
- package/dist/types/dotenv.d.mts +0 -29
- package/dist/types/dotenv.mjs +0 -0
- package/dist/types/event.d.mts +0 -63
- package/dist/types/event.mjs +0 -0
- package/dist/types/global.d.mts +0 -24
- package/dist/types/global.mjs +0 -0
- package/dist/types/helper.d.mts +0 -25
- package/dist/types/helper.mjs +0 -0
- package/dist/types/hooks.d.mts +0 -37
- package/dist/types/hooks.mjs +0 -0
- package/dist/types/index.d.mts +0 -26
- package/dist/types/index.mjs +0 -0
- package/dist/types/kits.d.mts +0 -32
- package/dist/types/kits.mjs +0 -0
- package/dist/types/middleware.d.mts +0 -31
- package/dist/types/middleware.mjs +0 -0
- package/dist/types/module.d.mts +0 -102
- package/dist/types/module.mjs +0 -0
- package/dist/types/preset.d.mts +0 -20
- package/dist/types/preset.mjs +0 -0
- package/dist/types/route.d.mts +0 -59
- package/dist/types/route.mjs +0 -0
- package/dist/types/runtime/index.d.mts +0 -5
- package/dist/types/runtime/index.mjs +0 -0
- package/dist/types/runtime/nuxt.d.mts +0 -13
- package/dist/types/runtime/nuxt.mjs +0 -0
- package/dist/types/runtime/ofetch.d.mts +0 -14
- package/dist/types/runtime/ofetch.mjs +0 -0
- package/dist/types/runtime/plugin.d.mts +0 -8
- package/dist/types/runtime/plugin.mjs +0 -0
- package/dist/types/runtime/silgi.d.mts +0 -11
- package/dist/types/runtime/silgi.mjs +0 -0
- package/dist/types/schema.d.mts +0 -86
- package/dist/types/schema.mjs +0 -0
- package/dist/types/service.d.mts +0 -102
- package/dist/types/service.mjs +0 -0
- package/dist/types/shared.d.mts +0 -19
- package/dist/types/shared.mjs +0 -0
- package/dist/types/silgi.d.mts +0 -71
- package/dist/types/silgi.mjs +0 -0
- package/dist/types/silgiCLI.d.mts +0 -118
- package/dist/types/silgiCLI.mjs +0 -0
- package/dist/types/standard-schema.d.mts +0 -61
- package/dist/types/standard-schema.mjs +0 -0
- package/dist/types/storage.d.mts +0 -30
- package/dist/types/storage.mjs +0 -0
- package/dist/types/tree-kill.d.mts +0 -18
- package/dist/types/tree-kill.mjs +0 -0
- package/lib/config.d.mts +0 -7
- package/lib/config.mjs +0 -5
- package/lib/meta.d.mts +0 -4
- package/lib/meta.mjs +0 -6
- package/lib/runtime-meta.d.mts +0 -4
- package/lib/runtime-meta.mjs +0 -32
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { redactHeaderValue, round, safeStringify } from "./utils.mjs";
|
|
2
|
+
//#region src/plugins/analytics/export.ts
|
|
3
|
+
/**
|
|
4
|
+
* Markdown export for analytics entries.
|
|
5
|
+
*/
|
|
6
|
+
function errorToMarkdown(e) {
|
|
7
|
+
const time = new Date(e.timestamp).toISOString();
|
|
8
|
+
const inputJson = safeStringify(e.input);
|
|
9
|
+
let md = `## Error in \`${e.procedure}\`\n\n`;
|
|
10
|
+
md += `**Time:** ${time} \n`;
|
|
11
|
+
md += `**Error:** ${e.code} \n`;
|
|
12
|
+
md += `**Status:** ${e.status} \n`;
|
|
13
|
+
md += `**Duration:** ${e.durationMs}ms\n\n`;
|
|
14
|
+
if (e.input !== void 0) md += `### Input\n\n\`\`\`json\n${inputJson}\n\`\`\`\n\n`;
|
|
15
|
+
if (e.stack) md += `### Stack Trace\n\n\`\`\`\n${e.stack}\n\`\`\`\n\n`;
|
|
16
|
+
if (Object.keys(e.headers).length > 0) {
|
|
17
|
+
md += `### Request Headers\n\n`;
|
|
18
|
+
for (const [k, v] of Object.entries(e.headers)) md += `- \`${k}\`: \`${redactHeaderValue(k, v)}\`\n`;
|
|
19
|
+
md += "\n";
|
|
20
|
+
}
|
|
21
|
+
if (e.spans.length > 0) {
|
|
22
|
+
md += `### Traced Operations\n\n`;
|
|
23
|
+
for (let i = 0; i < e.spans.length; i++) {
|
|
24
|
+
const s = e.spans[i];
|
|
25
|
+
const errMark = s.error ? ` ❌ ${s.error}` : "";
|
|
26
|
+
md += `**${i + 1}. [${s.kind}] ${s.name}** — ${s.durationMs}ms${errMark}\n`;
|
|
27
|
+
if (s.detail) md += `\`\`\`\n${s.detail}\n\`\`\`\n`;
|
|
28
|
+
}
|
|
29
|
+
md += "\n";
|
|
30
|
+
}
|
|
31
|
+
md += `### Error Message\n\n\`\`\`\n${e.error}\n\`\`\``;
|
|
32
|
+
return md;
|
|
33
|
+
}
|
|
34
|
+
function requestToMarkdown(r) {
|
|
35
|
+
const time = new Date(r.timestamp).toISOString();
|
|
36
|
+
let md = `## ${r.status >= 500 ? "💥" : r.status >= 400 ? "⚠️" : "✅"} ${r.method} ${r.path} → ${r.status} (${r.durationMs}ms)\n\n`;
|
|
37
|
+
md += `| Field | Value |\n|-------|-------|\n`;
|
|
38
|
+
md += `| Request ID | \`${r.requestId}\` |\n`;
|
|
39
|
+
md += `| Session ID | \`${r.sessionId}\` |\n`;
|
|
40
|
+
md += `| Method | ${r.method} |\n`;
|
|
41
|
+
md += `| URL | \`${r.url}\` |\n`;
|
|
42
|
+
md += `| Path | \`${r.path}\` |\n`;
|
|
43
|
+
md += `| Status | ${r.status} |\n`;
|
|
44
|
+
md += `| Duration | ${r.durationMs}ms |\n`;
|
|
45
|
+
md += `| Time | ${time} |\n`;
|
|
46
|
+
md += `| IP | ${r.ip} |\n`;
|
|
47
|
+
md += `| Procedures | ${r.procedures.length} |\n`;
|
|
48
|
+
if (r.isBatch) md += `| Batch | Yes |\n`;
|
|
49
|
+
md += "\n";
|
|
50
|
+
for (let i = 0; i < r.procedures.length; i++) {
|
|
51
|
+
const p = r.procedures[i];
|
|
52
|
+
const pEmoji = p.status >= 400 ? "⚠️" : "✅";
|
|
53
|
+
md += `### ${pEmoji} ${i + 1}. \`${p.procedure}\` → ${p.status} (${p.durationMs}ms)\n\n`;
|
|
54
|
+
if (p.input !== void 0 && p.input !== null) md += `#### Input\n\n\`\`\`json\n${safeStringify(p.input)}\n\`\`\`\n\n`;
|
|
55
|
+
if (p.output !== void 0 && p.output !== null) md += `#### Output\n\n\`\`\`json\n${safeStringify(p.output)}\n\`\`\`\n\n`;
|
|
56
|
+
if (p.spans.length > 0) {
|
|
57
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
58
|
+
for (const s of p.spans) byKind.set(s.kind, (byKind.get(s.kind) ?? 0) + s.durationMs);
|
|
59
|
+
const tracedMs = [...byKind.values()].reduce((a, b) => a + b, 0);
|
|
60
|
+
const appMs = Math.max(0, p.durationMs - tracedMs);
|
|
61
|
+
const total = Math.max(p.durationMs, .1);
|
|
62
|
+
md += `#### Timing\n\n| Category | Duration | % |\n|----------|----------|---|\n`;
|
|
63
|
+
md += `| **Total** | **${p.durationMs}ms** | 100% |\n`;
|
|
64
|
+
for (const [kind, ms] of byKind) md += `| ${kind} | ${round(ms)}ms | ${round(ms / total * 100)}% |\n`;
|
|
65
|
+
md += `| App Logic | ${round(appMs)}ms | ${round(appMs / total * 100)}% |\n\n`;
|
|
66
|
+
for (let j = 0; j < p.spans.length; j++) {
|
|
67
|
+
const s = p.spans[j];
|
|
68
|
+
const offset = s.startOffsetMs != null ? ` (at +${s.startOffsetMs}ms)` : "";
|
|
69
|
+
const err = s.error ? ` ❌ ${s.error}` : "";
|
|
70
|
+
md += `**${j + 1}. [${s.kind}] ${s.name}** — ${s.durationMs}ms${offset}${err}\n`;
|
|
71
|
+
if (s.detail) md += `\`\`\`\n${s.detail}\n\`\`\`\n`;
|
|
72
|
+
}
|
|
73
|
+
md += "\n";
|
|
74
|
+
}
|
|
75
|
+
if (p.error) md += `#### Error\n\n\`\`\`\n${p.error}\n\`\`\`\n\n`;
|
|
76
|
+
}
|
|
77
|
+
md += `---\n\n**Analyze this request and suggest performance optimizations:**\n`;
|
|
78
|
+
md += `- Redundant or slow operations that could be combined?\n`;
|
|
79
|
+
md += `- N+1 query pattern?\n`;
|
|
80
|
+
md += `- Data that should be cached?\n`;
|
|
81
|
+
md += `- Sequential calls that could run in parallel?\n`;
|
|
82
|
+
if (r.durationMs > 100) md += `- ⚠️ This request took ${r.durationMs}ms — what is the bottleneck?\n`;
|
|
83
|
+
return md;
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { errorToMarkdown, requestToMarkdown };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { asRecord } from "./utils.mjs";
|
|
2
|
+
//#region src/plugins/analytics/normalize.ts
|
|
3
|
+
/**
|
|
4
|
+
* Normalization functions for analytics data from storage.
|
|
5
|
+
*
|
|
6
|
+
* All data read from persistent storage passes through these functions
|
|
7
|
+
* to ensure type safety and handle schema evolution.
|
|
8
|
+
*/
|
|
9
|
+
function normalizeString(value, fallback = "") {
|
|
10
|
+
return typeof value === "string" ? value : fallback;
|
|
11
|
+
}
|
|
12
|
+
function normalizeNumber(value, fallback = 0) {
|
|
13
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
14
|
+
}
|
|
15
|
+
function normalizeBoolean(value, fallback = false) {
|
|
16
|
+
return typeof value === "boolean" ? value : fallback;
|
|
17
|
+
}
|
|
18
|
+
function normalizeStringMap(value) {
|
|
19
|
+
const record = asRecord(value);
|
|
20
|
+
if (!record) return {};
|
|
21
|
+
const result = {};
|
|
22
|
+
for (const [key, raw] of Object.entries(record)) if (typeof raw === "string") result[key] = raw;
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
function normalizeSpanKind(value) {
|
|
26
|
+
switch (value) {
|
|
27
|
+
case "db":
|
|
28
|
+
case "http":
|
|
29
|
+
case "cache":
|
|
30
|
+
case "queue":
|
|
31
|
+
case "email":
|
|
32
|
+
case "ai":
|
|
33
|
+
case "custom": return value;
|
|
34
|
+
default: return "custom";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function normalizeTraceSpans(value) {
|
|
38
|
+
if (!Array.isArray(value)) return [];
|
|
39
|
+
const spans = [];
|
|
40
|
+
for (const entry of value) {
|
|
41
|
+
const span = asRecord(entry);
|
|
42
|
+
if (!span) continue;
|
|
43
|
+
const attributes = asRecord(span.attributes);
|
|
44
|
+
const normalizedAttributes = {};
|
|
45
|
+
if (attributes) {
|
|
46
|
+
for (const [key, raw] of Object.entries(attributes)) if (typeof raw === "string" || typeof raw === "number" || typeof raw === "boolean") normalizedAttributes[key] = raw;
|
|
47
|
+
}
|
|
48
|
+
spans.push({
|
|
49
|
+
name: normalizeString(span.name, "unknown"),
|
|
50
|
+
kind: normalizeSpanKind(span.kind),
|
|
51
|
+
durationMs: normalizeNumber(span.durationMs),
|
|
52
|
+
startOffsetMs: typeof span.startOffsetMs === "number" ? span.startOffsetMs : void 0,
|
|
53
|
+
detail: typeof span.detail === "string" ? span.detail : void 0,
|
|
54
|
+
input: span.input,
|
|
55
|
+
output: span.output,
|
|
56
|
+
error: typeof span.error === "string" ? span.error : void 0,
|
|
57
|
+
attributes: Object.keys(normalizedAttributes).length > 0 ? normalizedAttributes : void 0
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return spans;
|
|
61
|
+
}
|
|
62
|
+
function inferPathFromUrl(url) {
|
|
63
|
+
if (!url) return "";
|
|
64
|
+
try {
|
|
65
|
+
return new URL(url).pathname || "";
|
|
66
|
+
} catch {
|
|
67
|
+
return "";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function normalizeProcedureCall(value, fallback) {
|
|
71
|
+
const record = asRecord(value);
|
|
72
|
+
return {
|
|
73
|
+
procedure: normalizeString(record?.procedure, fallback.path.replace(/^\//, "") || fallback.path || "request"),
|
|
74
|
+
durationMs: normalizeNumber(record?.durationMs, fallback.durationMs),
|
|
75
|
+
status: normalizeNumber(record?.status, fallback.status),
|
|
76
|
+
input: record?.input ?? null,
|
|
77
|
+
output: record?.output ?? null,
|
|
78
|
+
spans: normalizeTraceSpans(record?.spans),
|
|
79
|
+
error: typeof record?.error === "string" ? record.error : void 0
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function normalizeRequestEntry(value, fallbackId) {
|
|
83
|
+
const record = asRecord(value);
|
|
84
|
+
if (!record) return null;
|
|
85
|
+
const url = normalizeString(record.url);
|
|
86
|
+
const path = normalizeString(record.path, inferPathFromUrl(url));
|
|
87
|
+
const method = normalizeString(record.method, "GET");
|
|
88
|
+
const status = normalizeNumber(record.status, 200);
|
|
89
|
+
const durationMs = normalizeNumber(record.durationMs);
|
|
90
|
+
const procedureFallback = {
|
|
91
|
+
path: path || "/",
|
|
92
|
+
durationMs,
|
|
93
|
+
status
|
|
94
|
+
};
|
|
95
|
+
const proceduresRaw = Array.isArray(record.procedures) ? record.procedures : [];
|
|
96
|
+
const procedures = proceduresRaw.length > 0 ? proceduresRaw.map((entry) => normalizeProcedureCall(entry, procedureFallback)) : [normalizeProcedureCall(null, procedureFallback)];
|
|
97
|
+
return {
|
|
98
|
+
id: normalizeNumber(record.id, fallbackId),
|
|
99
|
+
requestId: normalizeString(record.requestId, String(normalizeNumber(record.id, fallbackId))),
|
|
100
|
+
sessionId: normalizeString(record.sessionId),
|
|
101
|
+
timestamp: normalizeNumber(record.timestamp),
|
|
102
|
+
durationMs,
|
|
103
|
+
method,
|
|
104
|
+
url: url || path,
|
|
105
|
+
path,
|
|
106
|
+
ip: normalizeString(record.ip),
|
|
107
|
+
headers: normalizeStringMap(record.headers),
|
|
108
|
+
responseHeaders: normalizeStringMap(record.responseHeaders),
|
|
109
|
+
userAgent: normalizeString(record.userAgent),
|
|
110
|
+
status,
|
|
111
|
+
procedures,
|
|
112
|
+
isBatch: normalizeBoolean(record.isBatch, procedures.length > 1),
|
|
113
|
+
traceId: normalizeString(record.traceId) || void 0,
|
|
114
|
+
parentRequestId: normalizeString(record.parentRequestId) || void 0
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function normalizeErrorEntry(value, fallbackId) {
|
|
118
|
+
const record = asRecord(value);
|
|
119
|
+
if (!record) return null;
|
|
120
|
+
return {
|
|
121
|
+
id: normalizeNumber(record.id, fallbackId),
|
|
122
|
+
requestId: normalizeString(record.requestId),
|
|
123
|
+
timestamp: normalizeNumber(record.timestamp),
|
|
124
|
+
procedure: normalizeString(record.procedure, "request"),
|
|
125
|
+
error: normalizeString(record.error, "Unknown error"),
|
|
126
|
+
code: normalizeString(record.code, "INTERNAL_SERVER_ERROR"),
|
|
127
|
+
status: normalizeNumber(record.status, 500),
|
|
128
|
+
stack: normalizeString(record.stack),
|
|
129
|
+
input: record.input ?? null,
|
|
130
|
+
headers: normalizeStringMap(record.headers),
|
|
131
|
+
durationMs: normalizeNumber(record.durationMs),
|
|
132
|
+
spans: normalizeTraceSpans(record.spans)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function normalizeRequestEntries(value) {
|
|
136
|
+
if (!Array.isArray(value)) return [];
|
|
137
|
+
return value.map((entry, index) => normalizeRequestEntry(entry, index + 1)).filter((entry) => entry !== null);
|
|
138
|
+
}
|
|
139
|
+
function normalizeErrorEntries(value) {
|
|
140
|
+
if (!Array.isArray(value)) return [];
|
|
141
|
+
return value.map((entry, index) => normalizeErrorEntry(entry, index + 1)).filter((entry) => entry !== null);
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { normalizeErrorEntries, normalizeRequestEntries };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
//#region src/plugins/analytics/query.ts
|
|
2
|
+
function parseQueryParams(params) {
|
|
3
|
+
const q = {};
|
|
4
|
+
const cursor = params.get("cursor");
|
|
5
|
+
if (cursor) q.cursor = Number(cursor);
|
|
6
|
+
const before = params.get("before");
|
|
7
|
+
if (before) q.before = Number(before);
|
|
8
|
+
const limit = params.get("limit");
|
|
9
|
+
q.limit = limit ? Math.max(1, Number(limit)) : 50;
|
|
10
|
+
q.sort = params.get("sort") ?? void 0;
|
|
11
|
+
q.order = params.get("order") ?? void 0;
|
|
12
|
+
q.status = params.get("status") ?? void 0;
|
|
13
|
+
q.path = params.get("path") ?? void 0;
|
|
14
|
+
q.search = params.get("search") ?? void 0;
|
|
15
|
+
q.procedure = params.get("procedure") ?? void 0;
|
|
16
|
+
q.session = params.get("session") ?? void 0;
|
|
17
|
+
const minDuration = params.get("minDuration");
|
|
18
|
+
if (minDuration) q.minDuration = Number(minDuration);
|
|
19
|
+
const maxDuration = params.get("maxDuration");
|
|
20
|
+
if (maxDuration) q.maxDuration = Number(maxDuration);
|
|
21
|
+
return q;
|
|
22
|
+
}
|
|
23
|
+
function matchesStatus(entryStatus, filter) {
|
|
24
|
+
const exact = Number(filter);
|
|
25
|
+
if (Number.isFinite(exact)) return entryStatus === exact;
|
|
26
|
+
if (/^[1-5]xx$/i.test(filter)) {
|
|
27
|
+
const cls = Number(filter[0]);
|
|
28
|
+
return Math.floor(entryStatus / 100) === cls;
|
|
29
|
+
}
|
|
30
|
+
const rangeMatch = filter.match(/^([<>]=?)(\d+)$/);
|
|
31
|
+
if (rangeMatch) {
|
|
32
|
+
const [, op, val] = rangeMatch;
|
|
33
|
+
const n = Number(val);
|
|
34
|
+
switch (op) {
|
|
35
|
+
case ">": return entryStatus > n;
|
|
36
|
+
case ">=": return entryStatus >= n;
|
|
37
|
+
case "<": return entryStatus < n;
|
|
38
|
+
case "<=": return entryStatus <= n;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
function queryRequests(entries, params) {
|
|
44
|
+
let filtered = entries;
|
|
45
|
+
if (params.status) {
|
|
46
|
+
const status = params.status;
|
|
47
|
+
filtered = filtered.filter((r) => matchesStatus(r.status, status));
|
|
48
|
+
}
|
|
49
|
+
if (params.path) {
|
|
50
|
+
const prefix = params.path.toLowerCase();
|
|
51
|
+
filtered = filtered.filter((r) => r.path.toLowerCase().includes(prefix));
|
|
52
|
+
}
|
|
53
|
+
if (params.procedure) {
|
|
54
|
+
const proc = params.procedure.toLowerCase();
|
|
55
|
+
filtered = filtered.filter((r) => r.procedures.some((p) => p.procedure.toLowerCase().includes(proc)));
|
|
56
|
+
}
|
|
57
|
+
if (params.session) {
|
|
58
|
+
const session = params.session;
|
|
59
|
+
filtered = filtered.filter((r) => r.sessionId === session);
|
|
60
|
+
}
|
|
61
|
+
if (params.minDuration != null) {
|
|
62
|
+
const min = params.minDuration;
|
|
63
|
+
filtered = filtered.filter((r) => r.durationMs >= min);
|
|
64
|
+
}
|
|
65
|
+
if (params.maxDuration != null) {
|
|
66
|
+
const max = params.maxDuration;
|
|
67
|
+
filtered = filtered.filter((r) => r.durationMs <= max);
|
|
68
|
+
}
|
|
69
|
+
if (params.search) {
|
|
70
|
+
const term = params.search.toLowerCase();
|
|
71
|
+
filtered = filtered.filter((r) => r.path?.toLowerCase().includes(term) || r.procedures?.some((p) => p.procedure.toLowerCase().includes(term)) || r.method?.toLowerCase().includes(term) || r.requestId?.includes(term));
|
|
72
|
+
}
|
|
73
|
+
const sortField = params.sort ?? "timestamp";
|
|
74
|
+
const desc = (params.order ?? "desc") === "desc";
|
|
75
|
+
filtered = sortEntries(filtered, sortField, desc);
|
|
76
|
+
return paginate(filtered, params);
|
|
77
|
+
}
|
|
78
|
+
function queryErrors(entries, params) {
|
|
79
|
+
let filtered = entries;
|
|
80
|
+
if (params.status) {
|
|
81
|
+
const status = params.status;
|
|
82
|
+
filtered = filtered.filter((e) => matchesStatus(e.status, status));
|
|
83
|
+
}
|
|
84
|
+
if (params.procedure) {
|
|
85
|
+
const proc = params.procedure.toLowerCase();
|
|
86
|
+
filtered = filtered.filter((e) => e.procedure.toLowerCase().includes(proc));
|
|
87
|
+
}
|
|
88
|
+
if (params.path) {
|
|
89
|
+
const path = params.path.toLowerCase();
|
|
90
|
+
filtered = filtered.filter((e) => e.procedure.toLowerCase().includes(path));
|
|
91
|
+
}
|
|
92
|
+
if (params.minDuration != null) {
|
|
93
|
+
const min = params.minDuration;
|
|
94
|
+
filtered = filtered.filter((e) => e.durationMs >= min);
|
|
95
|
+
}
|
|
96
|
+
if (params.maxDuration != null) {
|
|
97
|
+
const max = params.maxDuration;
|
|
98
|
+
filtered = filtered.filter((e) => e.durationMs <= max);
|
|
99
|
+
}
|
|
100
|
+
if (params.search) {
|
|
101
|
+
const term = params.search.toLowerCase();
|
|
102
|
+
filtered = filtered.filter((e) => e.procedure.toLowerCase().includes(term) || e.error.toLowerCase().includes(term) || e.code.toLowerCase().includes(term) || e.requestId.includes(term));
|
|
103
|
+
}
|
|
104
|
+
const sortField = params.sort ?? "timestamp";
|
|
105
|
+
const desc = (params.order ?? "desc") === "desc";
|
|
106
|
+
filtered = sortEntries(filtered, sortField, desc);
|
|
107
|
+
return paginate(filtered, params);
|
|
108
|
+
}
|
|
109
|
+
function queryTasks(entries, params) {
|
|
110
|
+
let filtered = entries;
|
|
111
|
+
if (params.status) {
|
|
112
|
+
const status = params.status;
|
|
113
|
+
filtered = filtered.filter((t) => status === "error" ? t.status === "error" : t.status === "success");
|
|
114
|
+
}
|
|
115
|
+
if (params.search) {
|
|
116
|
+
const term = params.search.toLowerCase();
|
|
117
|
+
filtered = filtered.filter((t) => t.taskName.toLowerCase().includes(term) || (t.error?.toLowerCase().includes(term) ?? false));
|
|
118
|
+
}
|
|
119
|
+
if (params.minDuration != null) {
|
|
120
|
+
const min = params.minDuration;
|
|
121
|
+
filtered = filtered.filter((t) => t.durationMs >= min);
|
|
122
|
+
}
|
|
123
|
+
const sortField = params.sort ?? "timestamp";
|
|
124
|
+
const desc = (params.order ?? "desc") === "desc";
|
|
125
|
+
filtered = sortEntries(filtered, sortField, desc);
|
|
126
|
+
return paginate(filtered, params);
|
|
127
|
+
}
|
|
128
|
+
function sortEntries(entries, field, desc) {
|
|
129
|
+
const sorted = [...entries];
|
|
130
|
+
sorted.sort((a, b) => {
|
|
131
|
+
const va = a[field];
|
|
132
|
+
const vb = b[field];
|
|
133
|
+
if (va == null && vb == null) return 0;
|
|
134
|
+
if (va == null) return 1;
|
|
135
|
+
if (vb == null) return -1;
|
|
136
|
+
if (typeof va === "number" && typeof vb === "number") return desc ? vb - va : va - vb;
|
|
137
|
+
if (typeof va === "string" && typeof vb === "string") return desc ? vb.localeCompare(va) : va.localeCompare(vb);
|
|
138
|
+
return 0;
|
|
139
|
+
});
|
|
140
|
+
return sorted;
|
|
141
|
+
}
|
|
142
|
+
function paginate(entries, params) {
|
|
143
|
+
const limit = params.limit ?? 50;
|
|
144
|
+
const total = entries.length;
|
|
145
|
+
let start = 0;
|
|
146
|
+
if (params.cursor != null) {
|
|
147
|
+
const idx = entries.findIndex((e) => e.id === params.cursor);
|
|
148
|
+
start = idx === -1 ? 0 : idx + 1;
|
|
149
|
+
} else if (params.before != null) {
|
|
150
|
+
const idx = entries.findIndex((e) => e.id === params.before);
|
|
151
|
+
start = idx === -1 ? 0 : Math.max(0, idx - limit);
|
|
152
|
+
}
|
|
153
|
+
const data = entries.slice(start, start + limit);
|
|
154
|
+
const hasMore = start + limit < total;
|
|
155
|
+
return {
|
|
156
|
+
data,
|
|
157
|
+
total,
|
|
158
|
+
hasMore,
|
|
159
|
+
nextCursor: hasMore && data.length > 0 ? data[data.length - 1].id : null,
|
|
160
|
+
prevCursor: start > 0 && data.length > 0 ? data[0].id : null
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//#endregion
|
|
164
|
+
export { parseQueryParams, queryErrors, queryRequests, queryTasks };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/plugins/analytics/request-id.ts
|
|
2
|
+
/**
|
|
3
|
+
* Snowflake-style request ID generator.
|
|
4
|
+
*
|
|
5
|
+
* Layout: 42-bit timestamp (ms) | 12-bit counter | 10-bit random
|
|
6
|
+
* - 42 bits timestamp → ~139 years from epoch
|
|
7
|
+
* - 12 bits counter → 4096 IDs per ms (supports 4M req/sec)
|
|
8
|
+
* - 10 bits random → collision resistance across processes
|
|
9
|
+
*
|
|
10
|
+
* Encoded as Base36 → 13 characters, lexicographically time-sorted
|
|
11
|
+
* Speed: ~50ns (Date.now + Math.random, no crypto)
|
|
12
|
+
*
|
|
13
|
+
* References:
|
|
14
|
+
* - Twitter Snowflake (2010): 41-bit ts | 10-bit machine | 12-bit seq
|
|
15
|
+
* - RFC 9562 UUID v7: 48-bit ts | 74-bit random
|
|
16
|
+
* - arXiv:2509.08969 — ULID vs UUID v7 comparative analysis
|
|
17
|
+
*/
|
|
18
|
+
let _lastTime = 0;
|
|
19
|
+
let _counter = 0;
|
|
20
|
+
function generateRequestId() {
|
|
21
|
+
let now = Date.now();
|
|
22
|
+
if (now === _lastTime) {
|
|
23
|
+
_counter = _counter + 1 & 4095;
|
|
24
|
+
if (_counter === 0) while (now === _lastTime) now = Date.now();
|
|
25
|
+
} else {
|
|
26
|
+
_counter = 0;
|
|
27
|
+
_lastTime = now;
|
|
28
|
+
}
|
|
29
|
+
const high = Math.floor(now / 1024);
|
|
30
|
+
const low = (now & 1023) << 22 | _counter << 10 | Math.random() * 1024 >>> 0;
|
|
31
|
+
return high.toString(36) + low.toString(36).padStart(7, "0");
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { generateRequestId };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnalyticsCollector } from "./collector.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/analytics/routes.d.ts
|
|
4
|
+
declare function analyticsHTML(): string;
|
|
5
|
+
declare function checkAnalyticsAuth(request: Request, auth: string | ((req: Request) => boolean | Promise<boolean>)): boolean | Promise<boolean>;
|
|
6
|
+
/** Return auth-failure response for analytics routes. */
|
|
7
|
+
declare function analyticsAuthResponse(pathname: string): Response;
|
|
8
|
+
/** Serve analytics dashboard and API routes. */
|
|
9
|
+
declare function serveAnalyticsRoute(pathname: string, request: Request, collector: AnalyticsCollector, dashboardHtml: string | undefined): Promise<Response>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { analyticsAuthResponse, analyticsHTML, checkAnalyticsAuth, serveAnalyticsRoute };
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { errorToMarkdown, requestToMarkdown } from "./export.mjs";
|
|
2
|
+
import { parseQueryParams, queryErrors, queryRequests, queryTasks } from "./query.mjs";
|
|
3
|
+
import { parse } from "cookie-es";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
//#region src/plugins/analytics/routes.ts
|
|
8
|
+
/**
|
|
9
|
+
* Analytics HTTP routing — dashboard, API endpoints, auth.
|
|
10
|
+
*/
|
|
11
|
+
const __analytics_dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
let _dashboardCache;
|
|
13
|
+
function analyticsHTML() {
|
|
14
|
+
if (_dashboardCache) return _dashboardCache;
|
|
15
|
+
const candidates = [
|
|
16
|
+
resolve(__analytics_dirname, "../../lib/dashboard/index.html"),
|
|
17
|
+
resolve(__analytics_dirname, "../lib/dashboard/index.html"),
|
|
18
|
+
resolve(__analytics_dirname, "../../../lib/dashboard/index.html")
|
|
19
|
+
];
|
|
20
|
+
for (const p of candidates) try {
|
|
21
|
+
_dashboardCache = readFileSync(p, "utf-8");
|
|
22
|
+
return _dashboardCache;
|
|
23
|
+
} catch {}
|
|
24
|
+
return FALLBACK_HTML;
|
|
25
|
+
}
|
|
26
|
+
const FALLBACK_HTML = `<!DOCTYPE html>
|
|
27
|
+
<html lang="en"><head><meta charset="utf-8"><title>Silgi Analytics</title>
|
|
28
|
+
<style>body{font-family:monospace;background:#0a0a0a;color:#e4e4e7;display:flex;align-items:center;justify-content:center;height:100vh;margin:0}
|
|
29
|
+
.msg{text-align:center}.msg h1{color:#edc462;margin-bottom:8px}.msg p{color:#71717a;font-size:14px}</style></head>
|
|
30
|
+
<body><div class="msg"><h1>silgi analytics</h1><p>Dashboard not built. Run <code>pnpm build:dashboard</code></p></div></body></html>`;
|
|
31
|
+
function checkAnalyticsAuth(request, auth) {
|
|
32
|
+
if (typeof auth === "function") return auth(request);
|
|
33
|
+
const cookie = request.headers.get("cookie");
|
|
34
|
+
if (cookie) {
|
|
35
|
+
if (parse(cookie)["silgi-auth"] === auth) return true;
|
|
36
|
+
}
|
|
37
|
+
if (request.headers.get("authorization") === `Bearer ${auth}`) return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const analyticsLoginHTML = `<!doctype html>
|
|
41
|
+
<html lang="en">
|
|
42
|
+
<head>
|
|
43
|
+
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
44
|
+
<title>Silgi Analytics</title>
|
|
45
|
+
<style>
|
|
46
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
47
|
+
body{font-family:system-ui,-apple-system,sans-serif;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#0a0a0a;color:#e5e5e5}
|
|
48
|
+
.c{width:100%;max-width:360px;padding:0 24px}
|
|
49
|
+
.logo{display:flex;align-items:center;gap:8px;margin-bottom:20px}
|
|
50
|
+
.logo svg{width:20px;height:20px;color:#c2822a}
|
|
51
|
+
.logo span{font-size:14px;font-weight:600;letter-spacing:-.01em}
|
|
52
|
+
p{font-size:13px;color:#737373;margin-bottom:16px;line-height:1.5}
|
|
53
|
+
input{width:100%;height:40px;padding:0 12px;background:#171717;border:1px solid #262626;border-radius:6px;color:#e5e5e5;font-size:13px;outline:none}
|
|
54
|
+
input:focus{border-color:#c2822a}
|
|
55
|
+
input::placeholder{color:#525252}
|
|
56
|
+
button{width:100%;height:36px;margin-top:10px;background:#c2822a;color:#0a0a0a;border:none;border-radius:6px;font-size:13px;font-weight:500;cursor:pointer}
|
|
57
|
+
button:hover{background:#d4943b}
|
|
58
|
+
.err{color:#ef4444;font-size:12px;margin-top:8px;display:none}
|
|
59
|
+
</style>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<div class="c">
|
|
63
|
+
<div class="logo"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg><span>Silgi Analytics</span></div>
|
|
64
|
+
<p>Enter your access token to view the dashboard.</p>
|
|
65
|
+
<form id="f"><input id="t" type="password" placeholder="Access token" autofocus><div class="err" id="e">Invalid token</div><button type="submit">Authenticate</button></form>
|
|
66
|
+
</div>
|
|
67
|
+
<script>
|
|
68
|
+
document.getElementById('f').onsubmit=function(e){
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
var t=document.getElementById('t').value.trim();
|
|
71
|
+
if(!t)return;
|
|
72
|
+
document.cookie='silgi-auth='+encodeURIComponent(t)+';path=/api/analytics;samesite=strict';
|
|
73
|
+
fetch('/api/analytics/stats',{headers:{'cookie':'silgi-auth='+encodeURIComponent(t)}}).then(function(){
|
|
74
|
+
location.reload();
|
|
75
|
+
}).catch(function(){location.reload()});
|
|
76
|
+
};
|
|
77
|
+
<\/script>
|
|
78
|
+
</body>
|
|
79
|
+
</html>`;
|
|
80
|
+
/** Return auth-failure response for analytics routes. */
|
|
81
|
+
function analyticsAuthResponse(pathname) {
|
|
82
|
+
const jsonHeaders = { "content-type": "application/json" };
|
|
83
|
+
if (pathname !== "api/analytics" && pathname !== "api/analytics/") return new Response(JSON.stringify({
|
|
84
|
+
code: "UNAUTHORIZED",
|
|
85
|
+
status: 401,
|
|
86
|
+
message: "Invalid token"
|
|
87
|
+
}), {
|
|
88
|
+
status: 401,
|
|
89
|
+
headers: jsonHeaders
|
|
90
|
+
});
|
|
91
|
+
return new Response(analyticsLoginHTML, {
|
|
92
|
+
status: 401,
|
|
93
|
+
headers: { "content-type": "text/html" }
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function parseAnalyticsDetailPath(pathname, prefix) {
|
|
97
|
+
if (!pathname.startsWith(prefix)) return null;
|
|
98
|
+
const rawId = pathname.slice(prefix.length);
|
|
99
|
+
if (!rawId || rawId.includes("/")) return null;
|
|
100
|
+
const id = Number(rawId);
|
|
101
|
+
return {
|
|
102
|
+
id: Number.isFinite(id) ? id : null,
|
|
103
|
+
rawId: decodeURIComponent(rawId)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function jsonResponse(data, headers) {
|
|
107
|
+
return new Response(JSON.stringify(data), { headers });
|
|
108
|
+
}
|
|
109
|
+
/** Serve analytics dashboard and API routes. */
|
|
110
|
+
async function serveAnalyticsRoute(pathname, request, collector, dashboardHtml) {
|
|
111
|
+
const jsonCacheHeaders = {
|
|
112
|
+
"content-type": "application/json",
|
|
113
|
+
"cache-control": "no-cache"
|
|
114
|
+
};
|
|
115
|
+
const mdHeaders = {
|
|
116
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
117
|
+
"cache-control": "no-cache"
|
|
118
|
+
};
|
|
119
|
+
const url = new URL(request.url);
|
|
120
|
+
if (pathname === "api/analytics" || pathname === "api/analytics/") return new Response(dashboardHtml, { headers: { "content-type": "text/html" } });
|
|
121
|
+
if (pathname === "api/analytics/stats") return jsonResponse(collector.toJSON(), jsonCacheHeaders);
|
|
122
|
+
if (pathname === "api/analytics/hidden") {
|
|
123
|
+
if (request.method === "GET") return jsonResponse(collector.getHiddenPaths(), jsonCacheHeaders);
|
|
124
|
+
if (request.method === "POST") {
|
|
125
|
+
const body = await request.json();
|
|
126
|
+
if (typeof body.path !== "string") return new Response("{\"error\":\"path required\"}", {
|
|
127
|
+
status: 400,
|
|
128
|
+
headers: jsonCacheHeaders
|
|
129
|
+
});
|
|
130
|
+
collector.addHiddenPath(body.path);
|
|
131
|
+
return jsonResponse(collector.getHiddenPaths(), jsonCacheHeaders);
|
|
132
|
+
}
|
|
133
|
+
if (request.method === "DELETE") {
|
|
134
|
+
const body = await request.json();
|
|
135
|
+
if (typeof body.path !== "string") return new Response("{\"error\":\"path required\"}", {
|
|
136
|
+
status: 400,
|
|
137
|
+
headers: jsonCacheHeaders
|
|
138
|
+
});
|
|
139
|
+
collector.removeHiddenPath(body.path);
|
|
140
|
+
return jsonResponse(collector.getHiddenPaths(), jsonCacheHeaders);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (pathname === "api/analytics/errors") return jsonResponse(queryErrors((await collector.getErrors()).filter((e) => !collector.isHidden(e.procedure)), parseQueryParams(url.searchParams)), jsonCacheHeaders);
|
|
144
|
+
if (pathname === "api/analytics/requests") return jsonResponse(queryRequests((await collector.getRequests()).filter((r) => !collector.isHidden(r.path)), parseQueryParams(url.searchParams)), jsonCacheHeaders);
|
|
145
|
+
if (pathname === "api/analytics/tasks") return jsonResponse(queryTasks(await collector.getTaskExecutions(), parseQueryParams(url.searchParams)), jsonCacheHeaders);
|
|
146
|
+
if (pathname === "api/analytics/scheduled") {
|
|
147
|
+
const { getScheduledTasks } = await import("../../core/task.mjs");
|
|
148
|
+
return jsonResponse(getScheduledTasks(), jsonCacheHeaders);
|
|
149
|
+
}
|
|
150
|
+
if (pathname === "api/analytics/stream") {
|
|
151
|
+
const stream = collector.sseHub.createStream();
|
|
152
|
+
return new Response(stream, { headers: {
|
|
153
|
+
"content-type": "text/event-stream",
|
|
154
|
+
"cache-control": "no-cache",
|
|
155
|
+
connection: "keep-alive"
|
|
156
|
+
} });
|
|
157
|
+
}
|
|
158
|
+
if (pathname === "api/analytics/timeseries") {
|
|
159
|
+
const range = url.searchParams.get("range") || "1h";
|
|
160
|
+
return jsonResponse(collector.timeseries.query(range), jsonCacheHeaders);
|
|
161
|
+
}
|
|
162
|
+
if (pathname === "api/analytics/alerts") return jsonResponse({
|
|
163
|
+
history: collector.alertEngine?.getHistory() ?? [],
|
|
164
|
+
states: collector.alertEngine?.getStates() ?? {}
|
|
165
|
+
}, jsonCacheHeaders);
|
|
166
|
+
if (pathname === "api/analytics/cost") return jsonResponse(collector.costTracker.getSummary(), jsonCacheHeaders);
|
|
167
|
+
if (pathname.startsWith("api/analytics/traces/")) {
|
|
168
|
+
const traceId = decodeURIComponent(pathname.slice(21));
|
|
169
|
+
if (traceId) return jsonResponse((await collector.getRequests()).filter((r) => r.traceId === traceId), jsonCacheHeaders);
|
|
170
|
+
}
|
|
171
|
+
if (pathname.startsWith("api/analytics/requests/") && pathname.endsWith("/md")) {
|
|
172
|
+
const rawId = pathname.slice(23, -3);
|
|
173
|
+
const parsedId = Number(rawId);
|
|
174
|
+
const requestId = decodeURIComponent(rawId);
|
|
175
|
+
const entry = (await collector.getRequests()).find((r) => r.id === parsedId || r.requestId === requestId);
|
|
176
|
+
if (entry) return new Response(requestToMarkdown(entry), { headers: mdHeaders });
|
|
177
|
+
return new Response("not found", { status: 404 });
|
|
178
|
+
}
|
|
179
|
+
const requestDetail = parseAnalyticsDetailPath(pathname, "api/analytics/requests/");
|
|
180
|
+
if (requestDetail) {
|
|
181
|
+
const entry = (await collector.getRequests()).find((r) => r.id === requestDetail.id || r.requestId === requestDetail.rawId);
|
|
182
|
+
return entry ? jsonResponse(entry, jsonCacheHeaders) : new Response("not found", { status: 404 });
|
|
183
|
+
}
|
|
184
|
+
if (pathname.startsWith("api/analytics/errors/") && pathname.endsWith("/md")) {
|
|
185
|
+
const rawId = pathname.slice(21, -3);
|
|
186
|
+
const id = Number(rawId);
|
|
187
|
+
const entry = (await collector.getErrors()).find((e) => e.id === id);
|
|
188
|
+
if (entry) return new Response(errorToMarkdown(entry), { headers: mdHeaders });
|
|
189
|
+
return new Response("not found", { status: 404 });
|
|
190
|
+
}
|
|
191
|
+
const errorDetail = parseAnalyticsDetailPath(pathname, "api/analytics/errors/");
|
|
192
|
+
if (errorDetail) {
|
|
193
|
+
const entry = (await collector.getErrors()).find((e) => e.id === errorDetail.id);
|
|
194
|
+
return entry ? jsonResponse(entry, jsonCacheHeaders) : new Response("not found", { status: 404 });
|
|
195
|
+
}
|
|
196
|
+
if (pathname === "api/analytics/errors/md") {
|
|
197
|
+
const errors = await collector.getErrors();
|
|
198
|
+
const md = errors.length === 0 ? "No errors.\n" : `# Errors (${errors.length})\n\n` + errors.map((e) => errorToMarkdown(e)).join("\n\n---\n\n");
|
|
199
|
+
return new Response(md, { headers: mdHeaders });
|
|
200
|
+
}
|
|
201
|
+
return new Response(JSON.stringify({
|
|
202
|
+
code: "NOT_FOUND",
|
|
203
|
+
status: 404,
|
|
204
|
+
message: "Analytics route not found"
|
|
205
|
+
}), {
|
|
206
|
+
status: 404,
|
|
207
|
+
headers: jsonCacheHeaders
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
export { analyticsAuthResponse, analyticsHTML, checkAnalyticsAuth, serveAnalyticsRoute };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ErrorEntry, RequestEntry, TaskExecution } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/analytics/sse.d.ts
|
|
4
|
+
type AnalyticsEvent = {
|
|
5
|
+
type: 'request';
|
|
6
|
+
data: RequestEntry;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'error';
|
|
9
|
+
data: ErrorEntry;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'task';
|
|
12
|
+
data: TaskExecution;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'stats';
|
|
15
|
+
data: unknown;
|
|
16
|
+
};
|
|
17
|
+
declare class AnalyticsSSEHub {
|
|
18
|
+
#private;
|
|
19
|
+
constructor();
|
|
20
|
+
/** Start periodic stats broadcast. */
|
|
21
|
+
startStatsBroadcast(getStats: () => unknown, intervalMs?: number): void;
|
|
22
|
+
/** Broadcast an event to all connected clients. */
|
|
23
|
+
broadcast(event: AnalyticsEvent): void;
|
|
24
|
+
/** Create an SSE ReadableStream for a new client connection. */
|
|
25
|
+
createStream(): ReadableStream<Uint8Array>;
|
|
26
|
+
/** Number of connected clients. */
|
|
27
|
+
get clientCount(): number;
|
|
28
|
+
dispose(): void;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { AnalyticsSSEHub };
|