From 89b4e41c4846cf1c837fd98d83726d11fedf3f3c Mon Sep 17 00:00:00 2001 From: Bruce Arctor <5032356+brucearctor@users.noreply.github.com> Date: Sun, 12 Jul 2026 21:04:26 -0700 Subject: [PATCH 1/2] =?UTF-8?q?chore:=20modernize=20toolchain=20=E2=80=94?= =?UTF-8?q?=20ESLint=2010,=20Node=2020+,=20pnpm=2010,=20Actions=20v4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Upgrade eslint 9 → 10, @eslint/js 9 → 10, typescript-eslint 7 → 8 - Upgrade prettier 3.6 → 3.9, typescript 5.8 → 5.9 - Drop Node 18 (EOL April 2025) from CI matrix - Add Node 24 (Active LTS) and 26 (Current) to CI matrix - Upgrade GitHub Actions: checkout v3→v4, setup-node v3→v4 - Pin pnpm 10.34.5 via packageManager field (pnpm 11 requires Node >= 22.13) - Remove explicit pnpm version from CI (reads from packageManager field) - Update engine requirements: node >= 20, npm >= 10 Closes #137 Closes #115 --- .github/workflows/userale_ci.yml | 20 ++++----- lefthook.yml | 42 +++++++++++++++++++ package.json | 3 +- products/userale/eslint.config.js | 1 + products/userale/package.json | 10 ++--- .../packages/flagon-userale/package.json | 4 +- products/userale/pnpm-workspace.yaml | 10 ++++- 7 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 lefthook.yml diff --git a/.github/workflows/userale_ci.yml b/.github/workflows/userale_ci.yml index 4e6ff62..c4a0021 100644 --- a/.github/workflows/userale_ci.yml +++ b/.github/workflows/userale_ci.yml @@ -42,19 +42,17 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18.x] + node-version: [22.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Node v${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - - name: Setup pnpm v10 + - name: Setup pnpm uses: pnpm/action-setup@v4 - with: - version: 10 - name: Install dependencies run: pnpm i @@ -69,21 +67,19 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18.x, 20.x, 22.x] + node-version: [20.x, 22.x, 24.x, 26.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ # See active and security support for Node.js at https://endoflife.date/nodejs steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Node v${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - - name: Setup pnpm v10 + - name: Setup pnpm uses: pnpm/action-setup@v4 - with: - version: 10 - name: Install dependencies run: pnpm i diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..f6f019e --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,42 @@ +# EXAMPLE USAGE: +# +# Refer for explanation to following link: +# https://lefthook.dev/configuration/ +# +# pre-push: +# jobs: +# - name: packages audit +# tags: +# - frontend +# - security +# run: yarn audit +# +# - name: gems audit +# tags: +# - backend +# - security +# run: bundle audit +# +# pre-commit: +# parallel: true +# jobs: +# - run: yarn eslint {staged_files} +# glob: "*.{js,ts,jsx,tsx}" +# +# - name: rubocop +# glob: "*.rb" +# exclude: +# - config/application.rb +# - config/routes.rb +# run: bundle exec rubocop --force-exclusion -- {all_files} +# +# - name: govet +# files: git ls-files -m +# glob: "*.go" +# run: go vet -- {files} +# +# - script: "hello.js" +# runner: node +# +# - script: "hello.go" +# runner: go run diff --git a/package.json b/package.json index 4bfa92b..2d7c155 100644 --- a/package.json +++ b/package.json @@ -19,5 +19,6 @@ "hooks": { "pre-commit": "npm run lint" } - } + }, + "packageManager": "pnpm@10.34.5" } diff --git a/products/userale/eslint.config.js b/products/userale/eslint.config.js index 6c1cf32..860881b 100644 --- a/products/userale/eslint.config.js +++ b/products/userale/eslint.config.js @@ -43,6 +43,7 @@ module.exports = [ 'no-cond-assign': 'warn', 'no-constant-condition': 'warn', 'no-unused-vars': 'warn', + 'no-useless-assignment': 'warn', '@typescript-eslint/no-unused-vars': 'warn', '@typescript-eslint/no-explicit-any': 'warn', }, diff --git a/products/userale/package.json b/products/userale/package.json index 6615771..e1c5b9c 100644 --- a/products/userale/package.json +++ b/products/userale/package.json @@ -12,21 +12,21 @@ "example:watch": "nodemon -w ./example/server example/server/server.js" }, "devDependencies": { - "@eslint/js": "^9.29.0", + "@eslint/js": "^10.0.1", "@ianvs/prettier-plugin-sort-imports": "4.1.1", "@playwright/test": "^1.52.0", "@types/node": "^22.15.30", "body-parser": "^1.20.2", - "eslint": "9.29.0", + "eslint": "^10.7.0", "eslint-plugin-jest": "^29.0.1", "express": "^4.18.2", "flagon-userale": "workspace:flagon-userale", "jsonschema": "^1.4.1", "nodemon": "^3.0.2", "pnpm": "^10.0.0", - "prettier": "3.9.5", - "typescript": "^5.8.3", - "typescript-eslint": "^7.8.0", + "prettier": "^3.9.5", + "typescript": "^5.9.3", + "typescript-eslint": "^8.63.0", "ws": "^8.18.0" } } \ No newline at end of file diff --git a/products/userale/packages/flagon-userale/package.json b/products/userale/packages/flagon-userale/package.json index e31609f..312beaa 100644 --- a/products/userale/packages/flagon-userale/package.json +++ b/products/userale/packages/flagon-userale/package.json @@ -49,8 +49,8 @@ }, "homepage": "https://flagon.apache.org/", "engines": { - "node": ">= 18.x", - "npm": ">= 9.x" + "node": ">= 20.x", + "npm": ">= 10.x" }, "devDependencies": { "@babel/preset-typescript": "^7.27.1", diff --git a/products/userale/pnpm-workspace.yaml b/products/userale/pnpm-workspace.yaml index 23d7944..01e7208 100644 --- a/products/userale/pnpm-workspace.yaml +++ b/products/userale/pnpm-workspace.yaml @@ -17,4 +17,12 @@ packages: # all packages in direct subdirs of packages/ - - 'packages/*' \ No newline at end of file + - 'packages/*' +allowBuilds: + '@parcel/watcher': true + '@swc/core': true + cypress: true + esbuild: true + lmdb: true + msgpackr-extract: true + sharp: true From 165ad6aa857b8f29665c0cb475225220dd5f8f67 Mon Sep 17 00:00:00 2001 From: Bruce Arctor <5032356+brucearctor@users.noreply.github.com> Date: Mon, 13 Jul 2026 18:21:05 -0700 Subject: [PATCH 2/2] feat(schema): add protobuf schema for UserALE log types Define the authoritative log schema in Protocol Buffers, addressing the long-standing TODO in types.d.ts to switch from untyped JSONObject to structured types. Schema (proto/apache/flagon/userale/v1/log.proto): - LogMetadata: shared fields across all log types (page context, identity, tool metadata) - RawLog: single DOM events (click, keydown, drag, etc.) - IntervalLog: aggregated event sequences (scroll, repeated clicks) - CustomLog: application-defined events via public API - UserALELog: discriminated union wrapping all three variants - LogBatch: transmission envelope Buf configuration: - buf.yaml: module config with STANDARD lint + FILE breaking detection - buf.gen.yaml: TypeScript codegen via buf.build/bufbuild/es Generated TypeScript types are checked in at src/gen/apache/flagon/userale/v1/log_pb.ts so consumers don't need buf installed. Note: This PR defines the schema and generates types but does NOT wire them into packageLogs.ts. Integration will follow in a separate PR as part of the LogExporter interface refactor. Closes #105 --- buf.gen.yaml | 30 ++ buf.yaml | 29 ++ .../gen/apache/flagon/userale/v1/log_pb.ts | 478 ++++++++++++++++++ proto/apache/flagon/userale/v1/log.proto | 154 ++++++ 4 files changed, 691 insertions(+) create mode 100644 buf.gen.yaml create mode 100644 buf.yaml create mode 100644 products/userale/packages/flagon-userale/src/gen/apache/flagon/userale/v1/log_pb.ts create mode 100644 proto/apache/flagon/userale/v1/log.proto diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 0000000..8708a06 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +version: v2 +managed: + enabled: true +plugins: + # TypeScript generation for UserALE.js + - remote: buf.build/bufbuild/es + out: products/userale/packages/flagon-userale/src/gen + opt: + - target=ts + + # Python generation for Distill (future) + # - remote: buf.build/protocolbuffers/python + # out: products/distill/flagon_distill/gen diff --git a/buf.yaml b/buf.yaml new file mode 100644 index 0000000..3c8cb4a --- /dev/null +++ b/buf.yaml @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +version: v2 +modules: + - path: proto + name: buf.build/apache/flagon +lint: + use: + - STANDARD + except: + - PACKAGE_VERSION_SUFFIX +breaking: + use: + - FILE diff --git a/products/userale/packages/flagon-userale/src/gen/apache/flagon/userale/v1/log_pb.ts b/products/userale/packages/flagon-userale/src/gen/apache/flagon/userale/v1/log_pb.ts new file mode 100644 index 0000000..387509d --- /dev/null +++ b/products/userale/packages/flagon-userale/src/gen/apache/flagon/userale/v1/log_pb.ts @@ -0,0 +1,478 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +// @generated by protoc-gen-es v2.12.1 with parameter "target=ts" +// @generated from file apache/flagon/userale/v1/log.proto (package apache.flagon.userale.v1, syntax proto3) +/* eslint-disable */ + +import type { GenEnum, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2"; +import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2"; +import { file_google_protobuf_struct } from "@bufbuild/protobuf/wkt"; +import type { JsonObject, Message } from "@bufbuild/protobuf"; + +/** + * Describes the file apache/flagon/userale/v1/log.proto. + */ +export const file_apache_flagon_userale_v1_log: GenFile = /*@__PURE__*/ + fileDesc("CiJhcGFjaGUvZmxhZ29uL3VzZXJhbGUvdjEvbG9nLnByb3RvEhhhcGFjaGUuZmxhZ29uLnVzZXJhbGUudjEiMQoQU2NyZWVuUmVzb2x1dGlvbhINCgV3aWR0aBgBIAEoBRIOCgZoZWlnaHQYAiABKAUiNgoITG9jYXRpb24SDgoBeBgBIAEoAUgAiAEBEg4KAXkYAiABKAFIAYgBAUIECgJfeEIECgJfeSLyAwoLTG9nTWV0YWRhdGESEAoIcGFnZV91cmwYASABKAkSEgoKcGFnZV90aXRsZRgCIAEoCRIVCg1wYWdlX3JlZmVycmVyGAMgASgJEhIKCnVzZXJfYWdlbnQYBCABKAkSEwoLY2xpZW50X3RpbWUYBSABKAMSRQoRc2NyZWVuX3Jlc29sdXRpb24YBiABKAsyKi5hcGFjaGUuZmxhZ29uLnVzZXJhbGUudjEuU2NyZWVuUmVzb2x1dGlvbhIUCgd1c2VyX2lkGAcgASgJSACIAQESFwoKc2Vzc2lvbl9pZBgIIAEoCUgBiAEBEhwKD2h0dHBfc2Vzc2lvbl9pZBgJIAEoCUgCiAEBEh8KEmJyb3dzZXJfc2Vzc2lvbl9pZBgKIAEoCUgDiAEBEhYKCXRvb2xfbmFtZRgLIAEoCUgEiAEBEhkKDHRvb2xfdmVyc2lvbhgMIAEoCUgFiAEBEhwKD3VzZXJhbGVfdmVyc2lvbhgNIAEoCUgGiAEBQgoKCF91c2VyX2lkQg0KC19zZXNzaW9uX2lkQhIKEF9odHRwX3Nlc3Npb25faWRCFQoTX2Jyb3dzZXJfc2Vzc2lvbl9pZEIMCgpfdG9vbF9uYW1lQg8KDV90b29sX3ZlcnNpb25CEgoQX3VzZXJhbGVfdmVyc2lvbiLlAgoGUmF3TG9nEjcKCG1ldGFkYXRhGAEgASgLMiUuYXBhY2hlLmZsYWdvbi51c2VyYWxlLnYxLkxvZ01ldGFkYXRhEg4KBnRhcmdldBgCIAEoCRIMCgRwYXRoGAMgAygJEhIKCmV2ZW50X3R5cGUYBCABKAkSNAoIbG9jYXRpb24YBSABKAsyIi5hcGFjaGUuZmxhZ29uLnVzZXJhbGUudjEuTG9jYXRpb24SFwoKbWljcm9fdGltZRgGIAEoAUgAiAEBEhMKC3VzZXJfYWN0aW9uGAcgASgIEigKB2RldGFpbHMYCCABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EisKCmF0dHJpYnV0ZXMYCSABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0EiYKBXN0eWxlGAogASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdEINCgtfbWljcm9fdGltZSKAAgoLSW50ZXJ2YWxMb2cSNwoIbWV0YWRhdGEYASABKAsyJS5hcGFjaGUuZmxhZ29uLnVzZXJhbGUudjEuTG9nTWV0YWRhdGESDgoGdGFyZ2V0GAIgASgJEgwKBHBhdGgYAyADKAkSEgoKZXZlbnRfdHlwZRgEIAEoCRINCgVjb3VudBgFIAEoBRIQCghkdXJhdGlvbhgGIAEoAxISCgpzdGFydF90aW1lGAcgASgDEhAKCGVuZF90aW1lGAggASgDEhUKDXRhcmdldF9jaGFuZ2UYCSABKAgSEwoLdHlwZV9jaGFuZ2UYCiABKAgSEwoLdXNlcl9hY3Rpb24YCyABKAgiswEKCUN1c3RvbUxvZxI3CghtZXRhZGF0YRgBIAEoCzIlLmFwYWNoZS5mbGFnb24udXNlcmFsZS52MS5Mb2dNZXRhZGF0YRITCgt1c2VyX2FjdGlvbhgCIAEoCBIoCgdkZXRhaWxzGAMgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdBIuCg1jdXN0b21fZmllbGRzGAQgASgLMhcuZ29vZ2xlLnByb3RvYnVmLlN0cnVjdCLrAQoKVXNlckFMRUxvZxIzCghsb2dfdHlwZRgBIAEoDjIhLmFwYWNoZS5mbGFnb24udXNlcmFsZS52MS5Mb2dUeXBlEi8KA3JhdxgCIAEoCzIgLmFwYWNoZS5mbGFnb24udXNlcmFsZS52MS5SYXdMb2dIABI5CghpbnRlcnZhbBgDIAEoCzIlLmFwYWNoZS5mbGFnb24udXNlcmFsZS52MS5JbnRlcnZhbExvZ0gAEjUKBmN1c3RvbRgEIAEoCzIjLmFwYWNoZS5mbGFnb24udXNlcmFsZS52MS5DdXN0b21Mb2dIAEIFCgNsb2ciPgoITG9nQmF0Y2gSMgoEbG9ncxgBIAMoCzIkLmFwYWNoZS5mbGFnb24udXNlcmFsZS52MS5Vc2VyQUxFTG9nKmEKB0xvZ1R5cGUSGAoUTE9HX1RZUEVfVU5TUEVDSUZJRUQQABIQCgxMT0dfVFlQRV9SQVcQARIVChFMT0dfVFlQRV9JTlRFUlZBTBACEhMKD0xPR19UWVBFX0NVU1RPTRADQqsBChxjb20uYXBhY2hlLmZsYWdvbi51c2VyYWxlLnYxQghMb2dQcm90b1ABogIDQUZVqgIYQXBhY2hlLkZsYWdvbi5Vc2VyYWxlLlYxygIYQXBhY2hlXEZsYWdvblxVc2VyYWxlXFYx4gIkQXBhY2hlXEZsYWdvblxVc2VyYWxlXFYxXEdQQk1ldGFkYXRh6gIbQXBhY2hlOjpGbGFnb246OlVzZXJhbGU6OlYxYgZwcm90bzM", [file_google_protobuf_struct]); + +/** + * ScreenResolution captures the viewport dimensions at log time. + * + * @generated from message apache.flagon.userale.v1.ScreenResolution + */ +export type ScreenResolution = Message<"apache.flagon.userale.v1.ScreenResolution"> & { + /** + * @generated from field: int32 width = 1; + */ + width: number; + + /** + * @generated from field: int32 height = 2; + */ + height: number; +}; + +/** + * Describes the message apache.flagon.userale.v1.ScreenResolution. + * Use `create(ScreenResolutionSchema)` to create a new message. + */ +export const ScreenResolutionSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_apache_flagon_userale_v1_log, 0); + +/** + * Location captures pointer coordinates, nullable for non-mouse events. + * + * @generated from message apache.flagon.userale.v1.Location + */ +export type Location = Message<"apache.flagon.userale.v1.Location"> & { + /** + * @generated from field: optional double x = 1; + */ + x?: number | undefined; + + /** + * @generated from field: optional double y = 2; + */ + y?: number | undefined; +}; + +/** + * Describes the message apache.flagon.userale.v1.Location. + * Use `create(LocationSchema)` to create a new message. + */ +export const LocationSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_apache_flagon_userale_v1_log, 1); + +/** + * Common metadata present on every log entry. + * These fields correspond to the shared fields across raw, interval, + * and custom logs in packageLogs.ts. + * + * @generated from message apache.flagon.userale.v1.LogMetadata + */ +export type LogMetadata = Message<"apache.flagon.userale.v1.LogMetadata"> & { + /** + * Page context + * + * @generated from field: string page_url = 1; + */ + pageUrl: string; + + /** + * @generated from field: string page_title = 2; + */ + pageTitle: string; + + /** + * @generated from field: string page_referrer = 3; + */ + pageReferrer: string; + + /** + * Browser / client info + * + * @generated from field: string user_agent = 4; + */ + userAgent: string; + + /** + * Unix epoch milliseconds + * + * @generated from field: int64 client_time = 5; + */ + clientTime: bigint; + + /** + * @generated from field: apache.flagon.userale.v1.ScreenResolution screen_resolution = 6; + */ + screenResolution?: ScreenResolution | undefined; + + /** + * Identity — all optional, set via configuration + * + * @generated from field: optional string user_id = 7; + */ + userId?: string | undefined; + + /** + * @generated from field: optional string session_id = 8; + */ + sessionId?: string | undefined; + + /** + * @generated from field: optional string http_session_id = 9; + */ + httpSessionId?: string | undefined; + + /** + * @generated from field: optional string browser_session_id = 10; + */ + browserSessionId?: string | undefined; + + /** + * Tool metadata + * + * @generated from field: optional string tool_name = 11; + */ + toolName?: string | undefined; + + /** + * @generated from field: optional string tool_version = 12; + */ + toolVersion?: string | undefined; + + /** + * @generated from field: optional string userale_version = 13; + */ + useraleVersion?: string | undefined; +}; + +/** + * Describes the message apache.flagon.userale.v1.LogMetadata. + * Use `create(LogMetadataSchema)` to create a new message. + */ +export const LogMetadataSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_apache_flagon_userale_v1_log, 2); + +/** + * RawLog captures a single DOM event (click, keydown, drag, etc.). + * Created by packageLog() in packageLogs.ts. + * + * @generated from message apache.flagon.userale.v1.RawLog + */ +export type RawLog = Message<"apache.flagon.userale.v1.RawLog"> & { + /** + * @generated from field: apache.flagon.userale.v1.LogMetadata metadata = 1; + */ + metadata?: LogMetadata | undefined; + + /** + * Event target + * + * CSS selector of event target + * + * @generated from field: string target = 2; + */ + target: string; + + /** + * DOM path from target to root + * + * @generated from field: repeated string path = 3; + */ + path: string[]; + + /** + * DOM event type (click, keydown, etc.) + * + * @generated from field: string event_type = 4; + */ + eventType: string; + + /** + * Pointer position + * + * @generated from field: apache.flagon.userale.v1.Location location = 5; + */ + location?: Location | undefined; + + /** + * Sub-millisecond timing + * + * @generated from field: optional double micro_time = 6; + */ + microTime?: number | undefined; + + /** + * Whether this represents direct user action + * + * @generated from field: bool user_action = 7; + */ + userAction: boolean; + + /** + * Dynamic detail extracted by detailFcn + * + * @generated from field: google.protobuf.Struct details = 8; + */ + details?: JsonObject | undefined; + + /** + * Element attributes (excluding style) + * + * @generated from field: google.protobuf.Struct attributes = 9; + */ + attributes?: JsonObject | undefined; + + /** + * Inline CSS properties of the target element + * + * @generated from field: google.protobuf.Struct style = 10; + */ + style?: JsonObject | undefined; +}; + +/** + * Describes the message apache.flagon.userale.v1.RawLog. + * Use `create(RawLogSchema)` to create a new message. + */ +export const RawLogSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_apache_flagon_userale_v1_log, 3); + +/** + * IntervalLog captures an aggregated sequence of repeated events + * (e.g., sustained scrolling, repeated clicks on same target). + * Created by packageIntervalLog() in packageLogs.ts. + * + * @generated from message apache.flagon.userale.v1.IntervalLog + */ +export type IntervalLog = Message<"apache.flagon.userale.v1.IntervalLog"> & { + /** + * @generated from field: apache.flagon.userale.v1.LogMetadata metadata = 1; + */ + metadata?: LogMetadata | undefined; + + /** + * Event target + * + * @generated from field: string target = 2; + */ + target: string; + + /** + * @generated from field: repeated string path = 3; + */ + path: string[]; + + /** + * @generated from field: string event_type = 4; + */ + eventType: string; + + /** + * Aggregation fields + * + * Number of events in the interval + * + * @generated from field: int32 count = 5; + */ + count: number; + + /** + * Duration in milliseconds + * + * @generated from field: int64 duration = 6; + */ + duration: bigint; + + /** + * Interval start (epoch ms) + * + * @generated from field: int64 start_time = 7; + */ + startTime: bigint; + + /** + * Interval end (epoch ms) + * + * @generated from field: int64 end_time = 8; + */ + endTime: bigint; + + /** + * Transition flags — why the interval ended + * + * @generated from field: bool target_change = 9; + */ + targetChange: boolean; + + /** + * @generated from field: bool type_change = 10; + */ + typeChange: boolean; + + /** + * @generated from field: bool user_action = 11; + */ + userAction: boolean; +}; + +/** + * Describes the message apache.flagon.userale.v1.IntervalLog. + * Use `create(IntervalLogSchema)` to create a new message. + */ +export const IntervalLogSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_apache_flagon_userale_v1_log, 4); + +/** + * CustomLog captures application-defined events logged via the public API. + * Created by packageCustomLog() in packageLogs.ts. + * + * @generated from message apache.flagon.userale.v1.CustomLog + */ +export type CustomLog = Message<"apache.flagon.userale.v1.CustomLog"> & { + /** + * @generated from field: apache.flagon.userale.v1.LogMetadata metadata = 1; + */ + metadata?: LogMetadata | undefined; + + /** + * @generated from field: bool user_action = 2; + */ + userAction: boolean; + + /** + * Detail function output + * + * @generated from field: google.protobuf.Struct details = 3; + */ + details?: JsonObject | undefined; + + /** + * Arbitrary fields merged from the user-provided customLog object. + * This preserves backward compatibility with the current Object.assign() + * pattern in packageCustomLog(). + * + * @generated from field: google.protobuf.Struct custom_fields = 4; + */ + customFields?: JsonObject | undefined; +}; + +/** + * Describes the message apache.flagon.userale.v1.CustomLog. + * Use `create(CustomLogSchema)` to create a new message. + */ +export const CustomLogSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_apache_flagon_userale_v1_log, 5); + +/** + * UserALELog is the top-level discriminated union wrapper. + * Every log produced by UserALE is one of the three variants. + * + * @generated from message apache.flagon.userale.v1.UserALELog + */ +export type UserALELog = Message<"apache.flagon.userale.v1.UserALELog"> & { + /** + * @generated from field: apache.flagon.userale.v1.LogType log_type = 1; + */ + logType: LogType; + + /** + * @generated from oneof apache.flagon.userale.v1.UserALELog.log + */ + log: { + /** + * @generated from field: apache.flagon.userale.v1.RawLog raw = 2; + */ + value: RawLog; + case: "raw"; + } | { + /** + * @generated from field: apache.flagon.userale.v1.IntervalLog interval = 3; + */ + value: IntervalLog; + case: "interval"; + } | { + /** + * @generated from field: apache.flagon.userale.v1.CustomLog custom = 4; + */ + value: CustomLog; + case: "custom"; + } | { case: undefined; value?: undefined }; +}; + +/** + * Describes the message apache.flagon.userale.v1.UserALELog. + * Use `create(UserALELogSchema)` to create a new message. + */ +export const UserALELogSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_apache_flagon_userale_v1_log, 6); + +/** + * LogBatch is the transmission envelope — a collection of logs + * to be sent in a single HTTP POST or WebSocket message. + * + * @generated from message apache.flagon.userale.v1.LogBatch + */ +export type LogBatch = Message<"apache.flagon.userale.v1.LogBatch"> & { + /** + * @generated from field: repeated apache.flagon.userale.v1.UserALELog logs = 1; + */ + logs: UserALELog[]; +}; + +/** + * Describes the message apache.flagon.userale.v1.LogBatch. + * Use `create(LogBatchSchema)` to create a new message. + */ +export const LogBatchSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_apache_flagon_userale_v1_log, 7); + +/** + * LogType discriminates the three categories of UserALE log entries. + * + * @generated from enum apache.flagon.userale.v1.LogType + */ +export enum LogType { + /** + * @generated from enum value: LOG_TYPE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: LOG_TYPE_RAW = 1; + */ + RAW = 1, + + /** + * @generated from enum value: LOG_TYPE_INTERVAL = 2; + */ + INTERVAL = 2, + + /** + * @generated from enum value: LOG_TYPE_CUSTOM = 3; + */ + CUSTOM = 3, +} + +/** + * Describes the enum apache.flagon.userale.v1.LogType. + */ +export const LogTypeSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_apache_flagon_userale_v1_log, 0); + diff --git a/proto/apache/flagon/userale/v1/log.proto b/proto/apache/flagon/userale/v1/log.proto new file mode 100644 index 0000000..c04b7bb --- /dev/null +++ b/proto/apache/flagon/userale/v1/log.proto @@ -0,0 +1,154 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +syntax = "proto3"; + +package apache.flagon.userale.v1; + +import "google/protobuf/struct.proto"; + +// LogType discriminates the three categories of UserALE log entries. +enum LogType { + LOG_TYPE_UNSPECIFIED = 0; + LOG_TYPE_RAW = 1; + LOG_TYPE_INTERVAL = 2; + LOG_TYPE_CUSTOM = 3; +} + +// ScreenResolution captures the viewport dimensions at log time. +message ScreenResolution { + int32 width = 1; + int32 height = 2; +} + +// Location captures pointer coordinates, nullable for non-mouse events. +message Location { + optional double x = 1; + optional double y = 2; +} + +// Common metadata present on every log entry. +// These fields correspond to the shared fields across raw, interval, +// and custom logs in packageLogs.ts. +message LogMetadata { + // Page context + string page_url = 1; + string page_title = 2; + string page_referrer = 3; + + // Browser / client info + string user_agent = 4; + int64 client_time = 5; // Unix epoch milliseconds + ScreenResolution screen_resolution = 6; + + // Identity — all optional, set via configuration + optional string user_id = 7; + optional string session_id = 8; + optional string http_session_id = 9; + optional string browser_session_id = 10; + + // Tool metadata + optional string tool_name = 11; + optional string tool_version = 12; + optional string userale_version = 13; +} + +// RawLog captures a single DOM event (click, keydown, drag, etc.). +// Created by packageLog() in packageLogs.ts. +message RawLog { + LogMetadata metadata = 1; + + // Event target + string target = 2; // CSS selector of event target + repeated string path = 3; // DOM path from target to root + string event_type = 4; // DOM event type (click, keydown, etc.) + + // Pointer position + Location location = 5; + + // Sub-millisecond timing + optional double micro_time = 6; + + // Whether this represents direct user action + bool user_action = 7; + + // Dynamic detail extracted by detailFcn + google.protobuf.Struct details = 8; + + // Element attributes (excluding style) + google.protobuf.Struct attributes = 9; + + // Inline CSS properties of the target element + google.protobuf.Struct style = 10; +} + +// IntervalLog captures an aggregated sequence of repeated events +// (e.g., sustained scrolling, repeated clicks on same target). +// Created by packageIntervalLog() in packageLogs.ts. +message IntervalLog { + LogMetadata metadata = 1; + + // Event target + string target = 2; + repeated string path = 3; + string event_type = 4; + + // Aggregation fields + int32 count = 5; // Number of events in the interval + int64 duration = 6; // Duration in milliseconds + int64 start_time = 7; // Interval start (epoch ms) + int64 end_time = 8; // Interval end (epoch ms) + + // Transition flags — why the interval ended + bool target_change = 9; + bool type_change = 10; + + bool user_action = 11; +} + +// CustomLog captures application-defined events logged via the public API. +// Created by packageCustomLog() in packageLogs.ts. +message CustomLog { + LogMetadata metadata = 1; + + bool user_action = 2; + + // Detail function output + google.protobuf.Struct details = 3; + + // Arbitrary fields merged from the user-provided customLog object. + // This preserves backward compatibility with the current Object.assign() + // pattern in packageCustomLog(). + google.protobuf.Struct custom_fields = 4; +} + +// UserALELog is the top-level discriminated union wrapper. +// Every log produced by UserALE is one of the three variants. +message UserALELog { + LogType log_type = 1; + oneof log { + RawLog raw = 2; + IntervalLog interval = 3; + CustomLog custom = 4; + } +} + +// LogBatch is the transmission envelope — a collection of logs +// to be sent in a single HTTP POST or WebSocket message. +message LogBatch { + repeated UserALELog logs = 1; +}