effect-browser 0.3.0-beta.7 → 0.3.0-beta.9

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 (64) hide show
  1. package/README.md +114 -19
  2. package/dist/{Browser-CNwK0r0q.mjs → Browser-Bc_LIqTC.mjs} +184 -16
  3. package/dist/Browser-Bc_LIqTC.mjs.map +1 -0
  4. package/dist/Browser.d.mts +16 -4
  5. package/dist/Browser.mjs +2 -2
  6. package/dist/{BrowserError-DXXIA6Rk.d.mts → BrowserError-Coy7EW1N.d.mts} +10 -5
  7. package/dist/BrowserError.d.mts +2 -2
  8. package/dist/BrowserError.mjs +10 -1
  9. package/dist/BrowserError.mjs.map +1 -1
  10. package/dist/Cdp.d.mts +1 -1
  11. package/dist/Cdp.mjs +3 -3
  12. package/dist/Chromium.d.mts +1 -1
  13. package/dist/Chromium.mjs +2 -2
  14. package/dist/Expect.d.mts +2 -2
  15. package/dist/Expect.mjs +2 -2
  16. package/dist/Moment.d.mts +1 -1
  17. package/dist/Moment.mjs +1 -1
  18. package/dist/{Page-D4281dIi.mjs → Page-B5cjaUp5.mjs} +2 -2
  19. package/dist/{Page-D4281dIi.mjs.map → Page-B5cjaUp5.mjs.map} +1 -1
  20. package/dist/{Page-C30aG2RQ.d.mts → Page-BlPjfibv.d.mts} +2 -2
  21. package/dist/Page.d.mts +1 -1
  22. package/dist/Page.mjs +1 -1
  23. package/dist/{Plan-BvCS9qAf.d.mts → Plan-BI8XGvDu.d.mts} +3 -3
  24. package/dist/{Plan-CyQNv49C.mjs → Plan-D1wrJVs8.mjs} +3 -3
  25. package/dist/{Plan-CyQNv49C.mjs.map → Plan-D1wrJVs8.mjs.map} +1 -1
  26. package/dist/Plan.d.mts +1 -1
  27. package/dist/Plan.mjs +1 -1
  28. package/dist/Policy.d.mts +1 -1
  29. package/dist/Policy.mjs +1 -1
  30. package/dist/Presentation.d.mts +1 -1
  31. package/dist/Presentation.mjs +1 -1
  32. package/dist/Stage.d.mts +2 -2
  33. package/dist/Stage.mjs +2 -2
  34. package/dist/{Supervisor-CLJaT7rG.d.mts → Supervisor-CYWFK3vM.d.mts} +105 -55
  35. package/dist/Supervisor-TNKNOVzu.mjs +599 -0
  36. package/dist/Supervisor-TNKNOVzu.mjs.map +1 -0
  37. package/dist/Supervisor.d.mts +2 -2
  38. package/dist/Supervisor.mjs +2 -2
  39. package/dist/{context-DAYjATgC.mjs → context-B6xr8nVi.mjs} +134 -10
  40. package/dist/context-B6xr8nVi.mjs.map +1 -0
  41. package/dist/index.d.mts +4 -4
  42. package/dist/index.mjs +4 -4
  43. package/dist/{page-DHeYWEs-.mjs → page-D-OedyBw.mjs} +59 -126
  44. package/dist/page-D-OedyBw.mjs.map +1 -0
  45. package/dist/{url-CcL0K7S0.mjs → url-Cd04Okid.mjs} +6 -4
  46. package/dist/url-Cd04Okid.mjs.map +1 -0
  47. package/package.json +1 -1
  48. package/src/Browser.ts +57 -16
  49. package/src/BrowserError.ts +9 -0
  50. package/src/Supervisor.ts +384 -138
  51. package/src/internal/input/gate.ts +224 -0
  52. package/src/internal/input/guard.ts +3 -2
  53. package/src/internal/input/perform.ts +84 -32
  54. package/src/internal/input/replies.ts +52 -16
  55. package/src/internal/page/context.ts +21 -11
  56. package/src/internal/page/lane.ts +20 -10
  57. package/src/internal/supervisor/lifecycle.ts +291 -140
  58. package/src/internal/timeline/events.ts +1 -0
  59. package/dist/Browser-CNwK0r0q.mjs.map +0 -1
  60. package/dist/Supervisor-BtEG93gR.mjs +0 -420
  61. package/dist/Supervisor-BtEG93gR.mjs.map +0 -1
  62. package/dist/context-DAYjATgC.mjs.map +0 -1
  63. package/dist/page-DHeYWEs-.mjs.map +0 -1
  64. package/dist/url-CcL0K7S0.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"url-CcL0K7S0.mjs","names":[],"sources":["../src/internal/page/lane.ts","../src/internal/page/url.ts"],"sourcesContent":["/**\n * A page's admission: the one lane every operation on the page takes its turn in, so a page waits\n * only for itself. A write, an action that sends input or navigates, holds the lane alone, in the\n * order writes asked; reads share it, after the write in flight and every write asked before them,\n * so a read describes the page an action left, never one an action is still changing. Each write\n * starts a new epoch as it asks. A turn not given in time fails `Busy`, never `Timeout`, and a\n * caller under `FailFast` gets it at once.\n *\n * Reads keep their work. An identical read asked in the same epoch and document joins the one in\n * flight, which runs in the page's scope under the action timeout whoever gives up; one that ends\n * after all its callers gave up serves the next to ask the same, within an action timeout. A write\n * stops the reads nobody awaits, since no caller after it could use them.\n *\n * Effect's `Semaphore` is not fair to a writer that needs every permit, so the rule is this\n * module's own: one state, changed by `step` alone, which the model test drives.\n */\nimport { Context, Deferred, Duration, Effect, Exit, type Fiber, type Scope } from \"effect\";\n\nimport { BrowserError, Busy } from \"../../BrowserError.ts\";\n\nexport type Kind = \"read\" | \"write\";\n\nexport interface Ticket {\n readonly id: number;\n readonly kind: Kind;\n}\n\n/** Who holds the lane: no one, reads together, or one write. */\nexport type Turn =\n | { readonly _tag: \"Free\" }\n | { readonly _tag: \"Reading\"; readonly count: number }\n | { readonly _tag: \"Writing\" };\n\nexport interface State {\n readonly turn: Turn;\n /** The tickets waiting, in the order they asked. */\n readonly queue: ReadonlyArray<Ticket>;\n /** The writes asked so far: two reads in one epoch follow the same writes. */\n readonly epoch: number;\n}\n\nexport type Input =\n | { readonly _tag: \"Ask\"; readonly ticket: Ticket }\n /** The ticket gave up waiting, or ended its turn. */\n | { readonly _tag: \"Leave\"; readonly ticket: Ticket };\n\nexport const initial: State = { turn: { _tag: \"Free\" }, queue: [], epoch: 0 };\n\nconst holders = (turn: Turn) =>\n turn._tag === \"Reading\" ? turn.count : turn._tag === \"Writing\" ? 1 : 0;\n\n/** Whether a ticket of `kind` asking now would hold the lane at once. */\nexport const admitsNow = ({ turn, queue }: State, kind: Kind) =>\n queue.length === 0 && (kind === \"read\" ? turn._tag !== \"Writing\" : turn._tag === \"Free\");\n\n/**\n * The operations ahead of a waiting ticket: those holding the lane and those asked before it, or\n * all that are queued for a ticket not in the queue.\n */\nexport const ahead = ({ turn, queue }: State, id?: number) => {\n const at = queue.findIndex((ticket) => ticket.id === id);\n\n return holders(turn) + (at === -1 ? queue.length : at);\n};\n\n/**\n * The lane after `input`, and the tickets it lets in. Tickets go in from the head of the queue\n * only: a write once the lane is free, reads while no write holds it, so reads asked before a\n * write go before it, and reads asked after it wait for it.\n */\nexport const step = (\n state: State,\n input: Input,\n): { readonly state: State; readonly admitted: ReadonlyArray<Ticket> } => {\n let { turn, queue, epoch } = state;\n\n if (input._tag === \"Ask\") {\n queue = [...queue, input.ticket];\n if (input.ticket.kind === \"write\") epoch += 1;\n } else {\n const at = queue.findIndex((ticket) => ticket.id === input.ticket.id);\n\n if (at !== -1) queue = queue.toSpliced(at, 1);\n else\n turn =\n turn._tag === \"Reading\" && turn.count > 1\n ? { _tag: \"Reading\", count: turn.count - 1 }\n : { _tag: \"Free\" };\n }\n\n const admitted: Array<Ticket> = [];\n\n for (const ticket of queue) {\n if (ticket.kind === \"write\" ? turn._tag !== \"Free\" : turn._tag === \"Writing\") break;\n admitted.push(ticket);\n turn =\n ticket.kind === \"write\" ? { _tag: \"Writing\" } : { _tag: \"Reading\", count: holders(turn) + 1 };\n }\n\n return { state: { turn, queue: queue.slice(admitted.length), epoch }, admitted };\n};\n\n/** Whether operations on a busy page fail `Busy` at once rather than wait their turn. */\nexport const FailFast = Context.Reference<boolean>(\"effect-browser/internal/page/FailFast\", {\n defaultValue: () => false,\n});\n\n/** The id a caller gives the actions it asks for, which each records as its `correlation`. */\nexport const Correlation = Context.Reference<string | undefined>(\n \"effect-browser/internal/page/Correlation\",\n { defaultValue: () => undefined },\n);\n\n/** A shared read in flight: its epoch, its result once it ends, and how many callers await it. */\ninterface Flight<A> {\n readonly epoch: number;\n readonly result: Deferred.Deferred<A, BrowserError>;\n waiting: number;\n fiber: Fiber.Fiber<A, BrowserError> | undefined;\n}\n\nexport const make = (options: {\n readonly now: () => number;\n readonly actionTimeout: Duration.Duration;\n /** When the page's current document began: a read is shared only within one. */\n readonly documentAt: () => number;\n /** The failure of a read still awaited as the page closes. */\n readonly gone: (operation: string) => BrowserError;\n /** The page's scope, which shared reads run in. */\n readonly scope: Scope.Scope;\n}) => {\n const { now, actionTimeout } = options;\n let state = initial;\n let tickets = 0;\n const admissions = new Map<number, Deferred.Deferred<void>>();\n // Each shared read's sweep, which a write runs as it asks.\n const sweeps: Array<() => void> = [];\n\n const apply = (input: Input) => {\n const next = step(state, input);\n\n state = next.state;\n if (input._tag === \"Leave\") admissions.delete(input.ticket.id);\n for (const ticket of next.admitted) {\n const admitted = admissions.get(ticket.id);\n\n admissions.delete(ticket.id);\n if (admitted !== undefined) Deferred.doneUnsafe(admitted, Exit.void);\n }\n if (input._tag === \"Ask\" && input.ticket.kind === \"write\") for (const sweep of sweeps) sweep();\n };\n\n const busy = (operation: string, askedAt: number, id?: number) =>\n new BrowserError({\n operation,\n reason: new Busy({ waitedMillis: Math.round(now() - askedAt), ahead: ahead(state, id) }),\n dispatched: false,\n });\n\n /**\n * Run `effect` in a turn of `kind`, waiting at most `wait` for it, or failing `Busy`. The turn\n * ends with `effect`, however it ends.\n */\n const turn =\n (kind: Kind, operation: string, wait: Duration.Duration) =>\n <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | BrowserError, R> =>\n Effect.uninterruptibleMask((restore) =>\n Effect.gen(function* () {\n const ticket: Ticket = { id: ++tickets, kind };\n const askedAt = now();\n\n if ((yield* FailFast) && !admitsNow(state, kind)) return yield* busy(operation, askedAt);\n const admitted = Deferred.makeUnsafe<void>();\n\n admissions.set(ticket.id, admitted);\n apply({ _tag: \"Ask\", ticket });\n\n const given = yield* Effect.exit(\n restore(\n Deferred.await(admitted).pipe(\n Effect.timeoutOrElse({\n duration: wait,\n orElse: () =>\n Deferred.isDoneUnsafe(admitted)\n ? Effect.void\n : Effect.fail(busy(operation, askedAt, ticket.id)),\n }),\n ),\n ),\n );\n\n if (Exit.isFailure(given)) {\n apply({ _tag: \"Leave\", ticket });\n\n return yield* Effect.failCause(given.cause);\n }\n\n return yield* restore(effect).pipe(\n Effect.ensuring(Effect.sync(() => apply({ _tag: \"Leave\", ticket }))),\n );\n }),\n );\n\n /**\n * A read whose identical calls share their work: `work` runs once per epoch and document while\n * calls await it, and with `keep` its result serves the next call after all of them gave up,\n * within an action timeout of its end. Pictures, whose callers say how old they may be, only\n * join.\n */\n const shared = <A>(operation: string, keep: boolean) => {\n const flights = new Map<string, Flight<A>>();\n const kept = new Map<string, { readonly value: A; readonly until: number }>();\n\n sweeps.push(() => {\n kept.clear();\n for (const flight of flights.values())\n if (flight.waiting === 0) flight.fiber?.interruptUnsafe();\n });\n\n // A read in flight, its first caller waiting. However its fiber ends, even before it began,\n // as when the page closes, its callers hear.\n const start = (id: string, work: Effect.Effect<A, BrowserError>) =>\n Effect.gen(function* () {\n const flight: Flight<A> = {\n epoch: state.epoch,\n result: Deferred.makeUnsafe(),\n waiting: 1,\n fiber: undefined,\n };\n\n flights.set(id, flight);\n flight.fiber = yield* turn(\n \"read\",\n operation,\n actionTimeout,\n )(work).pipe(\n // The caller chose whether to wait; the work it started serves others too.\n Effect.provideService(FailFast, false),\n Effect.forkIn(options.scope),\n );\n flight.fiber.addObserver((exit) => {\n flights.delete(id);\n if (keep && Exit.isSuccess(exit) && flight.waiting === 0 && flight.epoch === state.epoch)\n kept.set(id, { value: exit.value, until: now() + Duration.toMillis(actionTimeout) });\n Deferred.doneUnsafe(\n flight.result,\n Exit.hasInterrupts(exit) ? Effect.fail(options.gone(operation)) : exit,\n );\n });\n\n return flight;\n });\n\n const join = (id: string, work: Effect.Effect<A, BrowserError>) =>\n Effect.acquireUseRelease(\n Effect.suspend(() => {\n const flying = flights.get(id);\n\n if (flying === undefined) return start(id, work);\n flying.waiting += 1;\n\n return Effect.as(Effect.annotateCurrentSpan(\"shared\", \"joined\"), flying);\n }),\n (flight) => Deferred.await(flight.result),\n (flight) =>\n Effect.sync(() => {\n flight.waiting -= 1;\n if (flight.waiting === 0 && flight.epoch < state.epoch) flight.fiber?.interruptUnsafe();\n }),\n );\n\n return (key: string, work: Effect.Effect<A, BrowserError>): Effect.Effect<A, BrowserError> =>\n Effect.gen(function* () {\n const id = `${state.epoch} ${options.documentAt()} ${key}`;\n const at = now();\n\n for (const [old, { until }] of kept) if (until < at) kept.delete(old);\n const hit = kept.get(id);\n\n if (hit !== undefined) {\n kept.delete(id);\n yield* Effect.annotateCurrentSpan(\"shared\", \"kept\");\n\n return hit.value;\n }\n if ((yield* FailFast) && !admitsNow(state, \"read\")) return yield* busy(operation, at);\n\n return yield* join(id, work);\n });\n };\n\n return {\n /** A turn alone, for an action: `wait` bounds the wait for it. */\n write: (operation: string, wait: Duration.Duration) => turn(\"write\", operation, wait),\n /** A turn beside other reads, waited for within the action timeout. */\n read: (operation: string) => turn(\"read\", operation, actionTimeout),\n shared,\n };\n};\n\nexport type Lane = ReturnType<typeof make>;\n","/**\n * Addresses: reading one the way a person types it, for `Page.goto` and the browser tools alike,\n * and reporting one without the values that are credentials, by one rule that the page script runs\n * too, for the outline's links.\n */\n\nconst scheme = /^[a-z][a-z0-9+.-]*:/i;\n\n// `localhost:3000` and `example.com:8080/a` look like a scheme to the URL parser; a port decides.\nconst hostAndPort = /^[^\\s/?#@:]+:\\d+(?:[/?#]|$)/;\n\nconst loopback = /^(?:localhost|127(?:\\.\\d+){3}|\\[::1\\])(?:[:/?#]|$)/i;\n\n/** The URL `input` names. Without a scheme it is a web address: HTTPS, or HTTP on loopback. */\nexport const parse = (input: string): URL | null => {\n const text = input.trim();\n\n if (scheme.test(text) && !hostAndPort.test(text)) return URL.parse(text);\n\n return URL.parse(`${loopback.test(text) ? \"http\" : \"https\"}://${text}`);\n};\n\n/**\n * The rule that reports an address without its credentials. The page script runs it too, so it\n * stays self-contained, as `names.inpage.ts` says a page-side part must.\n */\nexport const addresses = () => {\n // What a credential's value reads as, as a secret field's text does (`Page.redacted`).\n const withheld = \"••••••••\" as const;\n\n // A parameter's name, compared in lowercase without separators, says it is a credential: a token,\n // secret, password, signature, assertion, session id or one-time code, or a code or key of a kind\n // that signs someone in or signs a request, such as `verification_code` or `api_key`.\n const credential =\n /token|secret|passw|passcode|passphrase|signature|credential|assertion|verifier|bearer|jwt|hmac|apikey|accesskey|privatekey|sess(?:ion)?id|saml(?:response|art)|(?:sig|otp)$|(?:auth|api|access|private|secret|signing|client|encryption|licen[cs]e|session|master|app|device|verification|verify|confirmation|confirm|activation|activate|reset|recovery|login|security|magic|onetime|mfa|2fa|sms|email|otp|oob)(?:code|key)$|^(?:auth|authorization|pwd|pass)$/;\n\n // These names as often say what an address is about, such as a stock code, a support ticket or a\n // conference session. Under them a value is a credential when it looks generated, at least 16\n // characters with letters and digits, as tokens, session ids and authorization codes do.\n const ambiguous = /^(?:code|key|session|sid|ticket)$/;\n\n const secret = (name: string, value: string) => {\n const bare = name.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n\n return (\n value !== \"\" &&\n (credential.test(bare) ||\n (ambiguous.test(bare) && value.length >= 16 && /\\d/.test(value) && /[a-z]/i.test(value)))\n );\n };\n\n // Parameters as written, each credential's value withheld: a query's, a fragment's written as a\n // query, or a path's segments', as a Java session id is.\n const masked = (parameters: string, separator: string) =>\n parameters\n .split(separator)\n .map((parameter) => {\n const [name = \"\", value = \"\"] = [...new URLSearchParams(parameter)][0] ?? [];\n\n return secret(name, value)\n ? `${parameter.slice(0, parameter.indexOf(\"=\") + 1)}${withheld}`\n : parameter;\n })\n .join(separator);\n\n /**\n * `url` as the library reports it: without userinfo, and with each credential's value withheld,\n * so the rest keeps its identity, such as a chart's `?ticker=ETH`. An address without a host,\n * such as `data:` or `about:blank`, is content or a fixed name, and stays as it is.\n */\n const redact = (url: string): string => {\n const parsed = URL.parse(url);\n\n if (parsed === null || parsed.host === \"\") return url;\n parsed.username = \"\";\n parsed.password = \"\";\n parsed.pathname = masked(parsed.pathname, \";\");\n parsed.search = masked(parsed.search.slice(1), \"&\");\n if (parsed.hash.includes(\"=\")) {\n const fragment = parsed.hash.slice(1);\n const question = fragment.indexOf(\"?\");\n // A route before the parameters, as in `#/inbox?token=…`, stays.\n const start = question >= 0 && question < fragment.indexOf(\"=\") ? question + 1 : 0;\n\n parsed.hash = fragment.slice(0, start) + masked(fragment.slice(start), \"&\");\n }\n\n return parsed.href.replaceAll(encodeURIComponent(withheld), withheld);\n };\n\n return { withheld, redact };\n};\n\nexport const { withheld, redact } = addresses();\n\n/** An address inside text, as a failure's message quotes one. */\nexport const quoted = /[a-z][a-z\\d+.-]*:\\/\\/[^\\s\"'<>]+/gi;\n\n/** `text` with each address in it redacted. */\nexport const redactWithin = (text: string) => text.replace(quoted, (url) => redact(url));\n"],"mappings":"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"}