pi-feats 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +24 -1
  2. package/THIRD_PARTY_NOTICES.md +12 -0
  3. package/assets/pi-feats-preview.png +0 -0
  4. package/extensions/api-server/application-log-store.ts +31 -0
  5. package/extensions/api-server/application-runtime.ts +80 -18
  6. package/extensions/api-server/application-store.ts +6 -2
  7. package/extensions/api-server/profile-store.ts +47 -20
  8. package/extensions/api-server/server.ts +182 -47
  9. package/extensions/browser-harness/cdp/commands.ts +260 -0
  10. package/extensions/browser-harness/cdp/console-buffer.ts +188 -0
  11. package/extensions/browser-harness/cdp/discovery.ts +198 -0
  12. package/extensions/browser-harness/cdp/errors.ts +23 -0
  13. package/extensions/browser-harness/cdp/events.ts +170 -0
  14. package/extensions/browser-harness/cdp/network-buffer.ts +146 -0
  15. package/extensions/browser-harness/cdp/ownership.ts +73 -0
  16. package/extensions/browser-harness/cdp/record-store.ts +61 -0
  17. package/extensions/browser-harness/cdp/session.ts +403 -0
  18. package/extensions/browser-harness/cdp/steel-transport.ts +151 -0
  19. package/extensions/browser-harness/cdp/target-factory.ts +153 -0
  20. package/extensions/browser-harness/cdp/types.ts +82 -0
  21. package/extensions/browser-harness/client.ts +366 -0
  22. package/extensions/browser-harness/daemon/bridge.ts +531 -0
  23. package/extensions/browser-harness/daemon/index.ts +86 -0
  24. package/extensions/browser-harness/daemon/protocol.ts +110 -0
  25. package/extensions/browser-harness/daemon/queue.ts +85 -0
  26. package/extensions/browser-harness/daemon/server.ts +170 -0
  27. package/extensions/browser-harness/daemon/spawn.ts +124 -0
  28. package/extensions/browser-harness/daemon/transport.ts +178 -0
  29. package/extensions/browser-harness/domains/ax-tree.ts +179 -0
  30. package/extensions/browser-harness/domains/box.ts +51 -0
  31. package/extensions/browser-harness/domains/cdp-call.ts +55 -0
  32. package/extensions/browser-harness/domains/click.ts +97 -0
  33. package/extensions/browser-harness/domains/console.ts +219 -0
  34. package/extensions/browser-harness/domains/dialog.ts +34 -0
  35. package/extensions/browser-harness/domains/drag.ts +67 -0
  36. package/extensions/browser-harness/domains/element-call.ts +117 -0
  37. package/extensions/browser-harness/domains/files.ts +219 -0
  38. package/extensions/browser-harness/domains/fill-engine.ts +80 -0
  39. package/extensions/browser-harness/domains/form-batch.ts +65 -0
  40. package/extensions/browser-harness/domains/form.ts +283 -0
  41. package/extensions/browser-harness/domains/headers.ts +89 -0
  42. package/extensions/browser-harness/domains/history.ts +80 -0
  43. package/extensions/browser-harness/domains/isolated-tab.ts +91 -0
  44. package/extensions/browser-harness/domains/js.ts +241 -0
  45. package/extensions/browser-harness/domains/keyboard.ts +197 -0
  46. package/extensions/browser-harness/domains/navigate.ts +161 -0
  47. package/extensions/browser-harness/domains/network.ts +301 -0
  48. package/extensions/browser-harness/domains/page.ts +154 -0
  49. package/extensions/browser-harness/domains/readpage/read-page.ts +174 -0
  50. package/extensions/browser-harness/domains/readpage/readability.ts +65 -0
  51. package/extensions/browser-harness/domains/ref-resolve.ts +118 -0
  52. package/extensions/browser-harness/domains/render.ts +43 -0
  53. package/extensions/browser-harness/domains/screenshot-capture.ts +80 -0
  54. package/extensions/browser-harness/domains/screenshot.ts +76 -0
  55. package/extensions/browser-harness/domains/scroll.ts +59 -0
  56. package/extensions/browser-harness/domains/search/google-serp.ts +85 -0
  57. package/extensions/browser-harness/domains/search/web-search.ts +144 -0
  58. package/extensions/browser-harness/domains/setup.ts +35 -0
  59. package/extensions/browser-harness/domains/snapshot.ts +256 -0
  60. package/extensions/browser-harness/domains/tabs.ts +202 -0
  61. package/extensions/browser-harness/domains/target.ts +35 -0
  62. package/extensions/browser-harness/domains/viewport.ts +42 -0
  63. package/extensions/browser-harness/index.ts +88 -0
  64. package/extensions/browser-harness/profile/bind.ts +90 -0
  65. package/extensions/browser-harness/profile/browser-process.ts +320 -0
  66. package/extensions/browser-harness/profile/command.ts +189 -0
  67. package/extensions/browser-harness/profile/launch.ts +80 -0
  68. package/extensions/browser-harness/profile/list.ts +131 -0
  69. package/extensions/browser-harness/profile/paths.ts +103 -0
  70. package/extensions/browser-harness/profile/store.ts +84 -0
  71. package/extensions/browser-harness/prompt.ts +16 -0
  72. package/extensions/browser-harness/registry.ts +80 -0
  73. package/extensions/browser-harness/schemas/common.ts +11 -0
  74. package/extensions/browser-harness/schemas/parse.ts +23 -0
  75. package/extensions/browser-harness/setup.ts +47 -0
  76. package/extensions/browser-harness/state.ts +51 -0
  77. package/extensions/browser-harness/steel.ts +215 -0
  78. package/extensions/browser-harness/util/debug.ts +8 -0
  79. package/extensions/browser-harness/util/guards.ts +30 -0
  80. package/extensions/browser-harness/util/js-template.ts +12 -0
  81. package/extensions/browser-harness/util/mutex.ts +20 -0
  82. package/extensions/browser-harness/util/paths.ts +31 -0
  83. package/extensions/browser-harness/util/result.ts +9 -0
  84. package/extensions/browser-harness/util/sharp-shim.ts +42 -0
  85. package/extensions/browser-harness/util/tool.ts +185 -0
  86. package/extensions/browser-harness/util/truncate.ts +41 -0
  87. package/extensions/cli-resources.ts +35 -16
  88. package/extensions/composio/index.ts +163 -0
  89. package/extensions/context-memory/index.ts +58 -0
  90. package/extensions/lib/application-context.ts +22 -0
  91. package/extensions/lib/application-handler-templates.ts +17 -1
  92. package/extensions/lib/context-memory.ts +165 -0
  93. package/extensions/lib/profile-sandbox.ts +3 -0
  94. package/extensions/lib/workflow-harness.ts +238 -0
  95. package/extensions/pi-console-webui/app/[section]/page.tsx +6 -1
  96. package/extensions/pi-console-webui/app/applications/[slug]/page.tsx +15 -0
  97. package/extensions/pi-console-webui/app/layout.tsx +6 -1
  98. package/extensions/pi-console-webui/app/login/page.tsx +5 -9
  99. package/extensions/pi-console-webui/app/not-found.tsx +5 -0
  100. package/extensions/pi-console-webui/app/page.tsx +6 -0
  101. package/extensions/pi-console-webui/app/terminal/page.tsx +3 -0
  102. package/extensions/pi-console-webui/components/application-handler-editor.tsx +4 -4
  103. package/extensions/pi-console-webui/components/application-logs.tsx +12 -8
  104. package/extensions/pi-console-webui/components/application-settings.tsx +5 -1
  105. package/extensions/pi-console-webui/components/chat-workspace.tsx +7 -4
  106. package/extensions/pi-console-webui/components/console-page.tsx +3 -1
  107. package/extensions/pi-console-webui/components/console.tsx +53 -7
  108. package/extensions/pi-console-webui/components/login-form.tsx +14 -0
  109. package/extensions/pi-console-webui/components/pulse-resources.tsx +10 -6
  110. package/extensions/pi-console-webui/components/skill-resources.tsx +3 -3
  111. package/extensions/pi-console-webui/lib/page-metadata.ts +33 -0
  112. package/extensions/profiles.ts +18 -7
  113. package/extensions/pulse/store.ts +5 -2
  114. package/extensions/sequential-workflow.ts +340 -256
  115. package/extensions/skill-sources/store.ts +24 -3
  116. package/licenses/pi-browser-harness-MIT.txt +21 -0
  117. package/package.json +25 -4
  118. package/schemas/sequential-workflow-template.schema.json +62 -0
  119. package/skills/browser-harness/SKILL.md +33 -0
  120. package/skills/composio-connections/SKILL.md +75 -0
  121. package/skills/sequential-workflow/SKILL.md +70 -0
  122. package/skills/sequential-workflow-template/SKILL.md +44 -0
@@ -0,0 +1,170 @@
1
+ import { Type, type Static, type TSchema } from "typebox";
2
+ import { Compile } from "typebox/compile";
3
+ import { type Result, err, ok } from "../util/result";
4
+ import { type CdpError, cdpError } from "./errors";
5
+
6
+ const ev = <P extends TSchema>(params: P) => ({ params, validate: Compile(params) });
7
+
8
+ const open = { additionalProperties: true } as const;
9
+
10
+ const Anything = Type.Object({}, open);
11
+
12
+ const StackTrace = Type.Object(
13
+ {
14
+ callFrames: Type.Optional(
15
+ Type.Array(
16
+ Type.Object(
17
+ {
18
+ url: Type.Optional(Type.String()),
19
+ lineNumber: Type.Optional(Type.Number()),
20
+ functionName: Type.Optional(Type.String()),
21
+ },
22
+ open,
23
+ ),
24
+ ),
25
+ ),
26
+ },
27
+ open,
28
+ );
29
+
30
+ const ConsoleArg = Type.Object(
31
+ {
32
+ type: Type.Optional(Type.String()),
33
+ value: Type.Optional(Type.Unknown()),
34
+ description: Type.Optional(Type.String()),
35
+ unserializableValue: Type.Optional(Type.String()),
36
+ },
37
+ open,
38
+ );
39
+
40
+ export const EVENTS = {
41
+ "Inspector.detached": ev(Anything),
42
+
43
+ "Page.javascriptDialogOpening": ev(
44
+ Type.Object(
45
+ {
46
+ type: Type.String(),
47
+ message: Type.String(),
48
+ defaultPrompt: Type.Optional(Type.String()),
49
+ },
50
+ open,
51
+ ),
52
+ ),
53
+ "Page.loadEventFired": ev(Anything),
54
+ "Page.frameNavigated": ev(Anything),
55
+
56
+ "Runtime.consoleAPICalled": ev(
57
+ Type.Object(
58
+ {
59
+ type: Type.Optional(Type.String()),
60
+ args: Type.Optional(Type.Array(ConsoleArg)),
61
+ stackTrace: Type.Optional(StackTrace),
62
+ },
63
+ open,
64
+ ),
65
+ ),
66
+
67
+ "Log.entryAdded": ev(
68
+ Type.Object(
69
+ {
70
+ entry: Type.Object(
71
+ {
72
+ level: Type.Optional(Type.String()),
73
+ text: Type.Optional(Type.String()),
74
+ url: Type.Optional(Type.String()),
75
+ lineNumber: Type.Optional(Type.Number()),
76
+ stackTrace: Type.Optional(StackTrace),
77
+ },
78
+ open,
79
+ ),
80
+ },
81
+ open,
82
+ ),
83
+ ),
84
+
85
+ "Network.requestWillBeSent": ev(
86
+ Type.Object(
87
+ {
88
+ requestId: Type.String(),
89
+ request: Type.Object(
90
+ {
91
+ url: Type.String(),
92
+ method: Type.String(),
93
+ postData: Type.Optional(Type.String()),
94
+ },
95
+ open,
96
+ ),
97
+ type: Type.Optional(Type.String()),
98
+ },
99
+ open,
100
+ ),
101
+ ),
102
+ "Network.responseReceived": ev(
103
+ Type.Object(
104
+ {
105
+ requestId: Type.String(),
106
+ response: Type.Optional(
107
+ Type.Object(
108
+ {
109
+ status: Type.Optional(Type.Number()),
110
+ statusText: Type.Optional(Type.String()),
111
+ mimeType: Type.Optional(Type.String()),
112
+ },
113
+ open,
114
+ ),
115
+ ),
116
+ type: Type.Optional(Type.String()),
117
+ },
118
+ open,
119
+ ),
120
+ ),
121
+ "Network.loadingFinished": ev(
122
+ Type.Object(
123
+ { requestId: Type.String(), encodedDataLength: Type.Optional(Type.Number()) },
124
+ open,
125
+ ),
126
+ ),
127
+ "Network.loadingFailed": ev(
128
+ Type.Object(
129
+ { requestId: Type.String(), errorText: Type.Optional(Type.String()) },
130
+ open,
131
+ ),
132
+ ),
133
+
134
+ "Target.targetCreated": ev(
135
+ Type.Object(
136
+ {
137
+ targetInfo: Type.Object(
138
+ {
139
+ targetId: Type.String(),
140
+ type: Type.String(),
141
+ openerId: Type.Optional(Type.String()),
142
+ },
143
+ open,
144
+ ),
145
+ },
146
+ open,
147
+ ),
148
+ ),
149
+ "Target.targetDestroyed": ev(Type.Object({ targetId: Type.String() }, open)),
150
+ };
151
+
152
+ export type CdpEventName = keyof typeof EVENTS;
153
+ export type EventParamsOf<E extends CdpEventName> = Static<(typeof EVENTS)[E]["params"]>;
154
+
155
+ export const isKnownEvent = (name: string): name is CdpEventName => Object.hasOwn(EVENTS, name);
156
+
157
+ export const decodeEvent = <E extends CdpEventName>(
158
+ name: E,
159
+ raw: unknown,
160
+ ): Result<EventParamsOf<E>, CdpError> => {
161
+ const spec = EVENTS[name];
162
+ if (spec === undefined) {
163
+ return err(cdpError("invalid_response", "unknown CDP event", name));
164
+ }
165
+ if (!spec.validate.Check(raw)) {
166
+ const why = spec.validate.Errors(raw).map((e) => e.message).join("; ");
167
+ return err(cdpError("invalid_response", why, name));
168
+ }
169
+ return ok(raw as EventParamsOf<E>);
170
+ };
@@ -0,0 +1,146 @@
1
+ import { decodeEvent, type EventParamsOf } from "./events";
2
+ import { createRecordStore } from "./record-store";
3
+
4
+ export type NetworkRecord = {
5
+ requestId: string;
6
+ method: string;
7
+ url: string;
8
+ status?: number;
9
+ statusText?: string;
10
+ type: string;
11
+ mimeType?: string;
12
+ requestStartedMs: number;
13
+ durationMs?: number;
14
+ requestBodySize: number;
15
+ responseBodySize?: number;
16
+ failed?: boolean;
17
+ errorText?: string;
18
+ body?: string | null;
19
+ };
20
+
21
+ export type NetworkFilter = {
22
+ urlPattern?: string;
23
+ methodFilter?: string[];
24
+ statusFilter?: { min?: number; max?: number };
25
+ resourceTypes?: string[];
26
+ sinceMs?: number;
27
+ limit?: number;
28
+ };
29
+
30
+ export type DrainResult = {
31
+ readonly records: NetworkRecord[];
32
+ readonly total: number;
33
+ readonly bufferOverflowed: boolean;
34
+ };
35
+
36
+ export type NetworkBuffer = {
37
+ ingestRequestWillBeSent(p: unknown): void;
38
+ ingestResponseReceived(p: unknown): void;
39
+ ingestLoadingFinished(p: unknown): void;
40
+ ingestLoadingFailed(p: unknown): void;
41
+ drain(filter: NetworkFilter): DrainResult;
42
+ clear(): void;
43
+ };
44
+
45
+ const compileUrlMatcher = (pattern: string): ((url: string) => boolean) => {
46
+ if (pattern.length >= 2 && pattern.startsWith("/") && pattern.endsWith("/")) {
47
+ try {
48
+ const re = new RegExp(pattern.slice(1, -1));
49
+ return (url) => re.test(url);
50
+ } catch {}
51
+ }
52
+ return (url) => url.includes(pattern);
53
+ };
54
+
55
+ type UpdateEvent = "Network.responseReceived" | "Network.loadingFinished" | "Network.loadingFailed";
56
+
57
+ export const createNetworkBuffer = (capacity = 500): NetworkBuffer => {
58
+ const records = createRecordStore<string, NetworkRecord>(capacity);
59
+
60
+ // All three follow-up events say the same thing first: decode, find the request they belong to, give up quietly if it is gone.
61
+ const update = <E extends UpdateEvent>(
62
+ method: E,
63
+ p: unknown,
64
+ apply: (r: NetworkRecord, params: EventParamsOf<E>) => void,
65
+ ): void => {
66
+ const decoded = decodeEvent(method, p);
67
+ if (!decoded.success) return;
68
+ const id = decoded.data.requestId;
69
+ if (!id) return;
70
+ const r = records.get(id);
71
+ if (!r) return;
72
+ apply(r, decoded.data);
73
+ };
74
+
75
+ return {
76
+ ingestRequestWillBeSent(p) {
77
+ const decoded = decodeEvent("Network.requestWillBeSent", p);
78
+ const params = decoded.success ? decoded.data : undefined;
79
+ const id = params?.requestId;
80
+ const url = params?.request.url;
81
+ const method = params?.request.method;
82
+ if (!id || !url || !method) return;
83
+ records.delete(id);
84
+ const postData = params.request.postData;
85
+ records.set(id, {
86
+ requestId: id,
87
+ method,
88
+ url,
89
+ type: params.type ?? "Other",
90
+ requestStartedMs: Date.now(),
91
+ requestBodySize: postData ? Buffer.byteLength(postData, "utf8") : 0,
92
+ });
93
+ },
94
+
95
+ ingestResponseReceived(p) {
96
+ update("Network.responseReceived", p, (r, params) => {
97
+ if (params.response?.status !== undefined) r.status = params.response.status;
98
+ if (params.response?.statusText !== undefined && params.response.statusText !== "") r.statusText = params.response.statusText;
99
+ if (params.response?.mimeType !== undefined) r.mimeType = params.response.mimeType;
100
+ // type is more accurate on responseReceived (CDP sometimes refines it)
101
+ if (params.type !== undefined) r.type = params.type;
102
+ });
103
+ },
104
+
105
+ ingestLoadingFinished(p) {
106
+ update("Network.loadingFinished", p, (r, params) => {
107
+ if (params.encodedDataLength !== undefined) r.responseBodySize = params.encodedDataLength;
108
+ r.durationMs = Date.now() - r.requestStartedMs;
109
+ });
110
+ },
111
+
112
+ ingestLoadingFailed(p) {
113
+ update("Network.loadingFailed", p, (r, params) => {
114
+ r.failed = true;
115
+ if (params.errorText !== undefined) r.errorText = params.errorText;
116
+ r.durationMs = Date.now() - r.requestStartedMs;
117
+ });
118
+ },
119
+
120
+ drain(filter) {
121
+ const matchUrl = filter.urlPattern !== undefined ? compileUrlMatcher(filter.urlPattern) : undefined;
122
+ const methods = filter.methodFilter ? new Set(filter.methodFilter.map((m) => m.toUpperCase())) : undefined;
123
+ const types = filter.resourceTypes ? new Set(filter.resourceTypes.map((t) => t.toLowerCase())) : undefined;
124
+ const minStatus = filter.statusFilter?.min;
125
+ const maxStatus = filter.statusFilter?.max;
126
+ const cutoff = filter.sinceMs !== undefined ? Date.now() - filter.sinceMs : undefined;
127
+
128
+ const matched: NetworkRecord[] = [];
129
+ for (const r of records.values()) {
130
+ if (matchUrl && !matchUrl(r.url)) continue;
131
+ if (methods && !methods.has(r.method.toUpperCase())) continue;
132
+ if (types && !types.has(r.type.toLowerCase())) continue;
133
+ if (cutoff !== undefined && r.requestStartedMs < cutoff) continue;
134
+ if (minStatus !== undefined && (r.status === undefined || r.status < minStatus)) continue;
135
+ if (maxStatus !== undefined && (r.status === undefined || r.status > maxStatus)) continue;
136
+ matched.push({ ...r });
137
+ }
138
+
139
+ return records.page(matched, filter.limit);
140
+ },
141
+
142
+ clear() {
143
+ records.clear();
144
+ },
145
+ };
146
+ };
@@ -0,0 +1,73 @@
1
+ export type OwnershipRegistry = {
2
+ add(targetId: string): void;
3
+ remove(targetId: string): void;
4
+ has(targetId: string): boolean;
5
+ list(): ReadonlyArray<string>;
6
+ replaceAll(ids: ReadonlyArray<string>): void;
7
+ setHarnessWindow(targetId: string | undefined): void;
8
+ harnessWindow(): string | undefined;
9
+ setHarnessWindowId(windowId: number | undefined): void;
10
+ harnessWindowId(): number | undefined;
11
+ onChange(cb: () => void): void;
12
+ };
13
+
14
+ export const createOwnershipRegistry = (
15
+ initial?: {
16
+ readonly ownedTargetIds?: ReadonlyArray<string>;
17
+ readonly harnessWindowTargetId?: string;
18
+ readonly harnessWindowId?: number;
19
+ },
20
+ ): OwnershipRegistry => {
21
+ const owned = new Set<string>(initial?.ownedTargetIds ?? []);
22
+ let harnessWindow: string | undefined = initial?.harnessWindowTargetId;
23
+ let harnessWindowId: number | undefined = initial?.harnessWindowId;
24
+ let listener: (() => void) | null = null;
25
+
26
+ const notify = (): void => {
27
+ if (listener) listener();
28
+ };
29
+
30
+ return {
31
+ add(targetId) {
32
+ if (owned.has(targetId)) return;
33
+ owned.add(targetId);
34
+ notify();
35
+ },
36
+ remove(targetId) {
37
+ if (!owned.has(targetId) && harnessWindow !== targetId) return;
38
+ owned.delete(targetId);
39
+ if (harnessWindow === targetId) harnessWindow = undefined;
40
+ notify();
41
+ },
42
+ has(targetId) {
43
+ return owned.has(targetId);
44
+ },
45
+ list() {
46
+ return [...owned];
47
+ },
48
+ replaceAll(ids) {
49
+ owned.clear();
50
+ for (const id of ids) owned.add(id);
51
+ notify();
52
+ },
53
+ setHarnessWindow(targetId) {
54
+ if (harnessWindow === targetId) return;
55
+ harnessWindow = targetId;
56
+ notify();
57
+ },
58
+ harnessWindow() {
59
+ return harnessWindow;
60
+ },
61
+ setHarnessWindowId(windowId) {
62
+ if (harnessWindowId === windowId) return;
63
+ harnessWindowId = windowId;
64
+ notify();
65
+ },
66
+ harnessWindowId() {
67
+ return harnessWindowId;
68
+ },
69
+ onChange(cb) {
70
+ listener = cb;
71
+ },
72
+ };
73
+ };
@@ -0,0 +1,61 @@
1
+ export type DrainPage<T> = {
2
+ readonly records: T[];
3
+ readonly total: number;
4
+ readonly bufferOverflowed: boolean;
5
+ };
6
+
7
+ export type RecordStore<K, T> = {
8
+ set(key: K, rec: T): void;
9
+ get(key: K): T | undefined;
10
+ delete(key: K): void;
11
+ values(): IterableIterator<T>;
12
+ // Takes the overflow flag as it pages, so each drain reports only the loss since the previous one.
13
+ page(matched: T[], limit: number | undefined): DrainPage<T>;
14
+ clear(): void;
15
+ };
16
+
17
+ const MAX_LIMIT = 500;
18
+ const DEFAULT_LIMIT = 50;
19
+
20
+ export const createRecordStore = <K, T>(capacity: number): RecordStore<K, T> => {
21
+ const records = new Map<K, T>();
22
+ let overflowed = false;
23
+
24
+ const evictOldestIfFull = (): void => {
25
+ while (records.size >= capacity) {
26
+ const oldest = records.keys().next();
27
+ if (oldest.done) return;
28
+ records.delete(oldest.value);
29
+ overflowed = true;
30
+ }
31
+ };
32
+
33
+ return {
34
+ set(key, rec) {
35
+ evictOldestIfFull();
36
+ records.set(key, rec);
37
+ },
38
+ get(key) {
39
+ return records.get(key);
40
+ },
41
+ delete(key) {
42
+ records.delete(key);
43
+ },
44
+ values() {
45
+ return records.values();
46
+ },
47
+ page(matched, limit) {
48
+ const bufferOverflowed = overflowed;
49
+ overflowed = false;
50
+ return {
51
+ records: matched.slice(-Math.min(limit ?? DEFAULT_LIMIT, MAX_LIMIT)),
52
+ total: matched.length,
53
+ bufferOverflowed,
54
+ };
55
+ },
56
+ clear() {
57
+ records.clear();
58
+ overflowed = false;
59
+ },
60
+ };
61
+ };