@yolk-sdk/emulators 0.1.0-canary.96 → 0.1.0-canary.97

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 (60) hide show
  1. package/README.md +72 -42
  2. package/dist/dropbox/state.mjs +4 -4
  3. package/dist/dropbox/state.mjs.map +1 -1
  4. package/dist/github/state.d.mts.map +1 -1
  5. package/dist/github/state.mjs +8 -8
  6. package/dist/github/state.mjs.map +1 -1
  7. package/dist/google/state.mjs +4 -4
  8. package/dist/google/state.mjs.map +1 -1
  9. package/dist/linkedin-search/state.d.mts.map +1 -1
  10. package/dist/linkedin-search/state.mjs +3 -3
  11. package/dist/linkedin-search/state.mjs.map +1 -1
  12. package/dist/mcp/afloat-recordings.d.mts +8 -0
  13. package/dist/mcp/afloat-recordings.d.mts.map +1 -0
  14. package/dist/mcp/afloat-recordings.mjs +918 -0
  15. package/dist/mcp/afloat-recordings.mjs.map +1 -0
  16. package/dist/mcp/api.d.mts +3 -2
  17. package/dist/mcp/api.d.mts.map +1 -1
  18. package/dist/mcp/api.mjs +77 -25
  19. package/dist/mcp/api.mjs.map +1 -1
  20. package/dist/mcp/state.d.mts +17 -2
  21. package/dist/mcp/state.d.mts.map +1 -1
  22. package/dist/mcp/state.mjs +17 -2
  23. package/dist/mcp/state.mjs.map +1 -1
  24. package/dist/mcp.d.mts +3 -2
  25. package/dist/mcp.d.mts.map +1 -1
  26. package/dist/mcp.mjs +81 -58
  27. package/dist/mcp.mjs.map +1 -1
  28. package/dist/microsoft/state.d.mts.map +1 -1
  29. package/dist/microsoft/state.mjs +1 -1
  30. package/dist/microsoft/state.mjs.map +1 -1
  31. package/dist/notion/state.d.mts.map +1 -1
  32. package/dist/notion/state.mjs +1 -1
  33. package/dist/notion/state.mjs.map +1 -1
  34. package/dist/r2-guard.d.mts.map +1 -1
  35. package/dist/r2-guard.mjs +1 -0
  36. package/dist/r2-guard.mjs.map +1 -1
  37. package/dist/router.d.mts +1 -1
  38. package/dist/router.mjs +1 -1
  39. package/dist/router.mjs.map +1 -1
  40. package/dist/stateful-emulator.d.mts +13 -0
  41. package/dist/stateful-emulator.d.mts.map +1 -1
  42. package/dist/stateful-emulator.mjs +25 -5
  43. package/dist/stateful-emulator.mjs.map +1 -1
  44. package/dist/telegram/state.mjs +1 -1
  45. package/dist/telegram/state.mjs.map +1 -1
  46. package/package.json +7 -7
  47. package/src/dropbox/state.ts +4 -4
  48. package/src/github/state.ts +8 -8
  49. package/src/google/state.ts +4 -4
  50. package/src/linkedin-search/state.ts +3 -3
  51. package/src/mcp/afloat-recordings.ts +1040 -0
  52. package/src/mcp/api.ts +135 -25
  53. package/src/mcp/state.ts +20 -1
  54. package/src/mcp.ts +101 -56
  55. package/src/microsoft/state.ts +1 -1
  56. package/src/notion/state.ts +1 -1
  57. package/src/r2-guard.ts +1 -0
  58. package/src/router.ts +1 -1
  59. package/src/stateful-emulator.ts +54 -5
  60. package/src/telegram/state.ts +1 -1
package/README.md CHANGED
@@ -21,15 +21,15 @@ conformance cases use. The Dropbox, Notion, Todoist, Telegram, GitHub, Google, L
21
21
  MCP emulators are stateful, fixture-only stand-ins for the Dropbox RPC and upload routes, the Notion
22
22
  `/v1` routes, the Todoist API v1 routes, the Telegram Bot API routes, the GitHub REST routes, the
23
23
  Gmail, Calendar, and Drive routes, the Exa and Enrich Layer routes, and the two synthetic MCP
24
- servers their conformance cases use: they answer only what the fixtures show and refuse everything
25
- else with a 400 not-emulated.
24
+ servers and the Afloat MCP endpoint their conformance cases use: they answer only what the fixtures
25
+ show and refuse everything else with a 400 not-emulated.
26
26
 
27
27
  Canary APIs are unstable. Keep all `@yolk-sdk/*` packages on the same version.
28
28
 
29
29
  ## Install
30
30
 
31
31
  ```bash
32
- pnpm add -D @yolk-sdk/emulators@canary effect@4.0.0-rc.115
32
+ pnpm add -D @yolk-sdk/emulators@canary effect@4.0.0
33
33
  ```
34
34
 
35
35
  ## Subpaths
@@ -57,7 +57,7 @@ There is no root export. Import an explicit subpath:
57
57
  | `@yolk-sdk/emulators/github` | `makeGithubEmulator`, `githubEmulatorRoutes`, seed and fault schemas (Node only) |
58
58
  | `@yolk-sdk/emulators/google` | `makeGoogleEmulator`, `googleEmulatorRoutes`, seed and fault schemas (Gmail, Calendar, Drive; Node only) |
59
59
  | `@yolk-sdk/emulators/linkedin-search` | `makeLinkedInSearchEmulator`, `linkedInSearchEmulatorRoutes`, seed and fault schemas (Exa, Enrich Layer; Node only) |
60
- | `@yolk-sdk/emulators/mcp` | `makeMcpEmulator`, `mcpEmulatorRoutes`, seed and fault schemas (synthetic MCP servers; Node only) |
60
+ | `@yolk-sdk/emulators/mcp` | `makeMcpEmulator`, `mcpEmulatorRoutes`, seed and fault schemas (synthetic and Afloat MCP servers; Node only) |
61
61
 
62
62
  ## Routing
63
63
 
@@ -72,7 +72,7 @@ Pick a transport by swapping `HttpClient` layers. Code under test keeps calling
72
72
 
73
73
  ```ts
74
74
  import { Effect, Layer } from 'effect'
75
- import { FetchHttpClient } from 'effect/unstable/http'
75
+ import { FetchHttpClient } from 'effect/http'
76
76
  import { makeGatewayEmulator } from '@yolk-sdk/emulators/gateway'
77
77
  import { serveFetchHandler } from '@yolk-sdk/emulators/node'
78
78
  import { EmulatedHttpClient, EmulatorRoute, InProcessHttpClient } from '@yolk-sdk/emulators/router'
@@ -1932,11 +1932,20 @@ exactly one LinkedIn search case, only to prove that case catches it.
1932
1932
  `{ fetch, fetchOn, ledger, faults, reset, seed, snapshot, coverage, close }`. Each call has its own
1933
1933
  state and session counter; `await close()` when done. It emulates the two synthetic servers of the
1934
1934
  `@yolk-sdk/mcp/conformance` fixtures, so `@yolk-sdk/mcp/client` and the MCP conformance cases run
1935
- unchanged against it: profile `synthetic-modern` on `https://mcp.example.test/modern/mcp`
1936
- (stateless `2026-07-28`, JSON answers) and profile `synthetic-legacy` on
1937
- `https://mcp.example.test/legacy/mcp` (an `initialize` handshake, sessions, SSE answers). Both
1938
- answer only on that origin (`mcpEmulatorOrigin`); behind a loopback rewrite, serve
1939
- `fetchOn(mcpEmulatorOrigin)`:
1935
+ unchanged against it: profile `synthetic-modern` on `https://mcp.example.test/modern/mcp` (stateless
1936
+ `2026-07-28`, JSON answers) and profile `synthetic-legacy` on `https://mcp.example.test/legacy/mcp`
1937
+ (an `initialize` handshake, sessions, SSE answers). Both answer only on that origin
1938
+ (`mcpEmulatorOrigin`); behind a loopback rewrite, serve `fetchOn(mcpEmulatorOrigin)`. A third
1939
+ profile, `afloat`, answers on the provider endpoint `https://useafloat.com/mcp`
1940
+ (`mcpEmulatorAfloatOrigin` plus `mcpEmulatorAfloatPath`; stateless `2026-07-28`, JSON answers, no
1941
+ session, one listing page) from the eight `@yolk-sdk/connectors/afloat/conformance` fixtures
1942
+ (`mcpEmulatorAfloatFixtures`; derived from the provider's source, not recorded live, unverified):
1943
+ the published nine-tool subset, the `list-invoices` read call, its `VALIDATION_ERROR` tool error,
1944
+ the absent tool's JSON-RPC error (HTTP 200), and the 401. Answering the two derived `tools/call`
1945
+ fixtures, rather than only recorded calls, is in scope by the owner's decision; they stay unverified
1946
+ until a live call is recorded. Route `https://useafloat.com` to it (or serve
1947
+ `fetchOn(mcpEmulatorAfloatOrigin)`), and send an Afloat-shaped synthetic key (see the credential
1948
+ rule below):
1940
1949
 
1941
1950
  ```ts
1942
1951
  import { makeMcpEmulator, mcpEmulatorOrigin } from '@yolk-sdk/emulators/mcp'
@@ -1967,12 +1976,16 @@ each profile, plus the legacy `GET` row; every row is a read, and every request
1967
1976
  | `/legacy/mcp#tools/call` | The three recorded SSE call answers, on a ready session |
1968
1977
  | `GET /legacy/mcp` | 405, no body, on a ready session |
1969
1978
  | `/{modern,legacy}/mcp#server/discover` | With the reserved invalid credential: the recorded 401, byte for byte |
1979
+ | `useafloat.com/mcp#server/discover` | The Afloat discover result; with `afloat_yolkconformanceinvalid0000`, the 401 |
1980
+ | `useafloat.com/mcp#tools/list` | The Afloat listing (the published tool subset, one page) |
1981
+ | `useafloat.com/mcp#tools/call` | The `list-invoices` result, its tool error, or the absent tool's error |
1970
1982
 
1971
1983
  Every answer comes from a fixture, byte for byte (the copies live in `mcpEmulatorFixtures`), with
1972
1984
  exactly three request-derived or minted substitutions:
1973
1985
 
1974
- - **The request id**, at exactly the recorded place: the top-level `id` of a JSON answer, or the
1975
- `id` of the SSE response event's payload. Notification events and SSE `id:` lines stay byte for
1986
+ - **The request id**, at exactly the recorded place: the top-level `id` of a JSON answer (the Afloat
1987
+ answers carry it last, in the server SDK's member order), or the `id` of the SSE response event's
1988
+ payload. Notification events and SSE `id:` lines stay byte for
1976
1989
  byte, and an answer that does not carry the recorded request id (the legacy era probe's
1977
1990
  `id: null` error, the 401) is unchanged.
1978
1991
  - **The session id.** `initialize` mints `yolk-emu-session-<n>`, `n` from a counter that never
@@ -2010,35 +2023,51 @@ which they compare only with the digest of the public reserved invalid credentia
2010
2023
  `yolk-conformance-invalid-credential-0000` (`mcpEmulatorReservedInvalidCredential`, itself a
2011
2024
  recognisable bearer) to answer the recorded 401 on the era probe.
2012
2025
 
2026
+ **The Afloat credential rule.** An Afloat key is `afloat_` (`mcpEmulatorAfloatKeyPrefix`) and a
2027
+ remainder, and `a` is a hex digit, so the key fails the shared first-character rule. On
2028
+ `https://useafloat.com` the emulator (the wrapper's opt-in `bearerPrefixes`, as the Telegram
2029
+ emulator guards a bot token's secret part) recognises a bearer only as `afloat_<remainder>` whose
2030
+ remainder is a recognisable bearer, and guards the remainder: it is what every repeat check, the
2031
+ output guard, and the digest take, and it is never stored, ledgered, or echoed. Use a synthetic key
2032
+ such as `afloat_synthetic-key-0001`; a real-format key whose remainder starts with a hex digit is
2033
+ not emulated, nor is a bearer without `afloat_` there or an `afloat_` key on the synthetic origin.
2034
+ The public reserved invalid key `afloat_yolkconformanceinvalid0000`
2035
+ (`mcpEmulatorAfloatReservedInvalidCredential`) answers the recorded 401 (`WWW-Authenticate: Bearer`)
2036
+ on the Afloat era probe.
2037
+
2013
2038
  - **Request-shape latitude (`/mcp`, the only accepted deviations).** Any bearer value in the RFC
2014
2039
  6750 `b64token` syntax (`[A-Za-z0-9\-._~+/]+=*`) of at least 8 characters, starting with a
2015
2040
  character in `[G-Zg-z\-._~+/]` other than `n`, `r`, `t`, `u`, with at least one outside
2016
- `[0-9.eE+-]`, that occurs nowhere else in the request (any header name or value included) and in
2017
- no answer or value the request would store (never stored or ledgered; only its digest is compared,
2018
- with the digest of the public reserved invalid credential
2019
- `yolk-conformance-invalid-credential-0000`, which answers the recorded 401 on the era probe);
2020
- extra request headers, except `mcp-*` headers other than `mcp-method`, `mcp-name`,
2021
- `mcp-protocol-version`, and `mcp-session-id`; a recorded header value sent as several headers that
2022
- the HTTP layer joins into the recorded value; JSON key order; any JSON-RPC request id that is an
2023
- integer from 0 to 2^53 - 1 or 1 to 64 printable ASCII characters where the recording has an id;
2024
- any non-empty `name` and `version` (and no other key) in the `_meta` client info
2025
- (`io.modelcontextprotocol/clientInfo`) of a modern request; a session id this emulator minted
2026
- since the last reset or seed where the recording sends `mcp-session-id` (initializing for
2027
- `notifications/initialized`, ready otherwise); and, with the seed's `two-pages` listing, the
2028
- cursor this emulator issued in the current generation on the second page. `Authorization` must be
2029
- exactly `Bearer <token>` (that spelling, one space). Everything else (another origin or path, any
2030
- query, other HTTP methods such as `DELETE` or a `GET` on the modern profile, JSON-RPC methods no
2031
- fixture of the profile records such as `ping`, `resources/*`, or `prompts/*`, batches and
2032
- client-sent responses, other members, a JSON body repeating a key (compared after unescaping), a
2033
- `null`, negative, or fractional id, other params (other tools, arguments, protocol versions, or
2034
- capabilities, extra client-info keys, and a legacy `initialize` client info other than the
2035
- recorded one), the MCP headers `accept`, `content-type`, `mcp-method`, `mcp-protocol-version`,
2036
- `mcp-name`, and `last-event-id` other than the recorded values or present where none is recorded,
2037
- any other `mcp-*` header (such as `mcp-param-*`), `mcp-session-id` missing where recorded or
2038
- present where not, an unknown session or one in the wrong phase, a cursor not issued in the
2039
- current generation, the reserved invalid credential on anything but the era probe, a bearer
2040
- repeated anywhere in the request, and a bearer an answer or a minted session id or cursor would
2041
- repeat) is not emulated.
2041
+ `[0-9.eE+-]` (on the Afloat profile, `afloat_` followed by such a value: an Afloat key starts with
2042
+ the hex digit `a`, so its remainder after `afloat_` is the value checked, guarded, and digested),
2043
+ that occurs nowhere else in the request (any header name or value included) and in no answer or
2044
+ value the request would store (never stored or ledgered; only its digest is compared, with the
2045
+ digest of the public reserved invalid credential `yolk-conformance-invalid-credential-0000`, or on
2046
+ the Afloat profile of the remainder of `afloat_yolkconformanceinvalid0000`, each answering the
2047
+ recorded 401 on its profile's era probe); extra request headers, except `mcp-*` headers other than
2048
+ `mcp-method`, `mcp-name`, `mcp-protocol-version`, and `mcp-session-id`; a recorded header value
2049
+ sent as several headers that the HTTP layer joins into the recorded value; JSON key order; any
2050
+ JSON-RPC request id that is an integer from 0 to 2^53 - 1 or 1 to 64 printable ASCII characters
2051
+ where the recording has an id; any non-empty `name` and `version` (and no other key) in the
2052
+ `_meta` client info (`io.modelcontextprotocol/clientInfo`) of a modern request; a session id this
2053
+ emulator minted since the last reset or seed where the recording sends `mcp-session-id`
2054
+ (initializing for `notifications/initialized`, ready otherwise); and, with the seed's `two-pages`
2055
+ listing, the cursor this emulator issued in the current generation on the second page.
2056
+ `Authorization` must be exactly `Bearer <token>` (that spelling, one space). Everything else
2057
+ (another origin or path, any query, other HTTP methods such as `DELETE` or a `GET` on the modern
2058
+ or Afloat profile, a bearer without `afloat_` on the Afloat profile or with it on the synthetic
2059
+ profiles, an Afloat key whose remainder fails the rule above (such as one starting with a hex
2060
+ digit), JSON-RPC methods no fixture of the profile records such as `ping`, `resources/*`, or
2061
+ `prompts/*`, batches and client-sent responses, other members, a JSON body repeating a key
2062
+ (compared after unescaping), a `null`, negative, or fractional id, other params (other tools,
2063
+ arguments, protocol versions, or capabilities, extra client-info keys, a cursor on the Afloat
2064
+ listing, and a legacy `initialize` client info other than the recorded one), the MCP headers
2065
+ `accept`, `content-type`, `mcp-method`, `mcp-protocol-version`, `mcp-name`, and `last-event-id`
2066
+ other than the recorded values or present where none is recorded, any other `mcp-*` header (such
2067
+ as `mcp-param-*`), `mcp-session-id` missing where recorded or present where not, an unknown
2068
+ session or one in the wrong phase, a cursor not issued in the current generation, a reserved
2069
+ invalid credential on anything but its profile's era probe, a bearer repeated anywhere in the
2070
+ request, and a bearer an answer or a minted session id or cursor would repeat) is not emulated.
2042
2071
 
2043
2072
  Not emulated (a constant-text 400 that writes nothing and uses up no fault): `DELETE` (the client
2044
2073
  never sends it), `ping`, `resources/*`, `prompts/*`, `logging/*`, `completion/*`, `tasks/*`,
@@ -2068,8 +2097,9 @@ plane behave as in the Dropbox emulator; `/_emulate/state` also reports `nextSes
2068
2097
  **Drill knobs (tests only).** `drills: { discoverCarriesErrorResponse, discoverWithoutResultType,
2069
2098
  sessionIdNotVisibleAscii, discoverAnsweredTwice, writeToolMarkedReadOnly, readCallAnswersToolError,
2070
2099
  invalidCallAnswersRpcError, absentCallAnswersResult, unauthorizedWithoutChallenge }` (booleans) each
2071
- make the emulator disagree with exactly one MCP conformance case, only to prove that case catches
2072
- it.
2100
+ make the emulator disagree with exactly one MCP conformance case, on every profile whose answers
2101
+ they change (the Afloat profile included, except the legacy-only session knob), only to prove that
2102
+ case catches it.
2073
2103
 
2074
2104
  ## Evidence
2075
2105
 
@@ -2105,8 +2135,8 @@ implementation, verifies it.
2105
2135
  All Fortnox, Microsoft, Dropbox, Notion, Todoist, Telegram, GitHub, Google, LinkedIn search, and
2106
2136
  MCP routes are currently `unverified` (no live recording yet), including four Fortnox, eleven
2107
2137
  Microsoft, five Dropbox, two Notion, five Todoist, one Telegram, six GitHub, and fifteen Google
2108
- connector write routes (the three LinkedIn search routes and the nine MCP rows are reads, so none of
2109
- them needs an entry). Until an
2138
+ connector write routes (the three LinkedIn search routes and the twelve MCP rows are reads, so none
2139
+ of them needs an entry). Until an
2110
2140
  owner-approved live run verifies them, the repository lists them in a visible, time-bounded
2111
2141
  allowlist (`scripts/emulator-evidence-pending.json`, which holds each entry's expiry date): the
2112
2142
  check reports them as PENDING warnings until that date and fails again after it.
@@ -18,11 +18,11 @@ import * as Schema from "effect/Schema";
18
18
  * @experimental
19
19
  */
20
20
  /** A Dropbox revision: lower-case hex, at least nine digits (what the connector accepts). */
21
- const Rev = Schema.String.check(Schema.isPattern(/^[0-9a-f]{9,}$/));
21
+ const Rev = Schema.String.check(Schema.isPattern(/^[0-9a-f]{9,}$/u));
22
22
  /** A Dropbox file or folder id (`id:` form). */
23
- const EntryId = Schema.String.check(Schema.isPattern(/^id:\S+$/));
23
+ const EntryId = Schema.String.check(Schema.isPattern(/^id:\S+$/u));
24
24
  /** A Dropbox timestamp as the fixtures write it (`2026-09-20T10:00:00Z`). */
25
- const Timestamp = Schema.String.check(Schema.isPattern(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/));
25
+ const Timestamp = Schema.String.check(Schema.isPattern(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/u));
26
26
  /** One path component: non-empty, no `/`, not `.` or `..`. */
27
27
  const EntryName = Schema.String.check(Schema.makeFilter((name) => name.length > 0 && !name.includes("/") && name !== "." && name !== ".." ? true : "an entry name is one non-empty path component"));
28
28
  /** File fields (absent on folders). */
@@ -71,7 +71,7 @@ const DropboxEmulatorStateSchema = Schema.Struct({
71
71
  counters: Counters
72
72
  });
73
73
  /** An absolute path in display casing: `/`-separated non-empty components, no trailing `/`. */
74
- const SeedPath = Schema.String.check(Schema.isPattern(/^(?:\/[^/]+)+$/));
74
+ const SeedPath = Schema.String.check(Schema.isPattern(/^(?:\/[^/]+)+$/u));
75
75
  /**
76
76
  * A seeded entry, addressed by its display path (its parent folder must be seeded too). File
77
77
  * fields default to synthetic values; a folder takes none.
@@ -1 +1 @@
1
- {"version":3,"file":"state.mjs","names":[],"sources":["../../src/dropbox/state.ts"],"sourcesContent":["/**\n * Dropbox emulator state: the typed entries, deleted-entry records, the seed input, the default\n * seed, and the profiles (internal; re-exported by `src/dropbox.ts`).\n *\n * Entry shapes and the default entries follow the synthetic Dropbox conformance fixtures, copied\n * as data (the same paths, ids, revs, sizes, content hashes, and timestamps as the fixtures and\n * `dropboxConformanceFixtureSeeds`), never imported from SDK code. The parent folders the seeded\n * paths need (`/Conformance`, `/Conformance/Paging`, `/Conformance/Search`, `/Conformance/Work`)\n * are `implied`: no fixture shows their metadata, so they hold paths together but any answer that\n * would render one is not emulated.\n *\n * Minted values never repeat seeded ones: the id and rev counters start above the highest seeded\n * id (`id:SyntheticEntryNNNNNNNN`) and rev (`a1b2c3d4e5f6NNNN`) in the minted form.\n *\n * @experimental\n */\nimport { Predicate, Result } from 'effect'\nimport * as Schema from 'effect/Schema'\n\n/** A Dropbox revision: lower-case hex, at least nine digits (what the connector accepts). */\nconst Rev = Schema.String.check(Schema.isPattern(/^[0-9a-f]{9,}$/))\n\n/** A Dropbox file or folder id (`id:` form). */\nconst EntryId = Schema.String.check(Schema.isPattern(/^id:\\S+$/))\n\n/** A Dropbox timestamp as the fixtures write it (`2026-09-20T10:00:00Z`). */\nconst Timestamp = Schema.String.check(Schema.isPattern(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/))\n\n/** One path component: non-empty, no `/`, not `.` or `..`. */\nconst EntryName = Schema.String.check(\n Schema.makeFilter(name =>\n name.length > 0 && !name.includes('/') && name !== '.' && name !== '..'\n ? true\n : 'an entry name is one non-empty path component'\n )\n)\n\n/** File fields (absent on folders). */\nexport const DropboxEmulatorFile = Schema.Struct({\n rev: Rev,\n size: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n contentHash: Schema.String,\n clientModified: Timestamp,\n serverModified: Timestamp\n})\n\nexport type DropboxEmulatorFile = typeof DropboxEmulatorFile.Type\n\n/** A stored file or folder. Its path is its parents' names and its own, in stored casing. */\nexport const DropboxEmulatorEntry = Schema.Struct({\n id: EntryId,\n /** Parent folder id; `null` in the root folder. */\n parentId: Schema.NullOr(EntryId),\n name: EntryName,\n /** `null` for a folder. */\n file: Schema.NullOr(DropboxEmulatorFile),\n /**\n * `true` for an entry no fixture shows, held only because a seeded path needs it: lookups pass\n * through it, but an answer that would render it is not emulated.\n */\n implied: Schema.Boolean\n})\n\nexport type DropboxEmulatorEntry = typeof DropboxEmulatorEntry.Type\n\n/**\n * What Dropbox keeps of a deleted entry (`include_deleted` lookups answer it): its name and paths\n * as they were. `delete_v2` records one only for an empty folder, the only delete whose\n * `include_deleted` answer a fixture records.\n */\nexport const DropboxEmulatorDeleted = Schema.Struct({\n name: EntryName,\n pathLower: Schema.String,\n pathDisplay: Schema.String\n})\n\nexport type DropboxEmulatorDeleted = typeof DropboxEmulatorDeleted.Type\n\nconst Counter = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))\n\nconst Counters = Schema.Struct({\n /** Next number in created entry ids (`id:SyntheticEntry00000001`). */\n nextIdNumber: Counter,\n /** Next number in minted revs (`a1b2c3d4e5f60101`). */\n nextRevNumber: Counter\n})\n\n/** The whole emulator state (JSON-compatible; what `snapshot()` returns). */\nexport const DropboxEmulatorStateSchema = Schema.Struct({\n entries: Schema.Array(DropboxEmulatorEntry),\n deleted: Schema.Array(DropboxEmulatorDeleted),\n counters: Counters\n})\n\n/**\n * The emulator state. The container is mutable (routes replace whole lists); every entity is\n * replaced, never edited in place.\n */\nexport type DropboxEmulatorState = {\n entries: ReadonlyArray<DropboxEmulatorEntry>\n deleted: ReadonlyArray<DropboxEmulatorDeleted>\n counters: typeof Counters.Type\n}\n\n/** An absolute path in display casing: `/`-separated non-empty components, no trailing `/`. */\nconst SeedPath = Schema.String.check(Schema.isPattern(/^(?:\\/[^/]+)+$/))\n\n/**\n * A seeded entry, addressed by its display path (its parent folder must be seeded too). File\n * fields default to synthetic values; a folder takes none.\n */\nexport const DropboxEmulatorEntrySeed = Schema.Struct({\n path: SeedPath,\n id: EntryId,\n kind: Schema.Literals(['file', 'folder']),\n rev: Schema.optionalKey(Rev),\n size: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))),\n contentHash: Schema.optionalKey(Schema.String),\n clientModified: Schema.optionalKey(Timestamp),\n serverModified: Schema.optionalKey(Timestamp),\n /** An entry no fixture shows (default `false`); see `DropboxEmulatorEntry.implied`. */\n implied: Schema.optionalKey(Schema.Boolean)\n})\n\nexport type DropboxEmulatorEntrySeed = typeof DropboxEmulatorEntrySeed.Type\n\n/** Account-variance profiles for the default seed. */\nexport const DropboxEmulatorProfile = Schema.Literals(['default', 'empty'])\n\nexport type DropboxEmulatorProfile = typeof DropboxEmulatorProfile.Type\n\n/**\n * A typed seed. Start from `profile` (default `'default'`, the fixture entries); `entries` and\n * `deleted`, when given, replace that part of the profile.\n */\nexport const DropboxEmulatorSeed = Schema.Struct({\n profile: Schema.optionalKey(DropboxEmulatorProfile),\n entries: Schema.optionalKey(Schema.Array(DropboxEmulatorEntrySeed)),\n deleted: Schema.optionalKey(Schema.Array(DropboxEmulatorDeleted))\n})\n\nexport type DropboxEmulatorSeed = typeof DropboxEmulatorSeed.Type\n\nconst strict = { onExcessProperty: 'error' } as const\n\nconst decodeSeedInput = Schema.decodeUnknownResult(DropboxEmulatorSeed, strict)\n\nconst decodeStateInput = Schema.decodeUnknownResult(DropboxEmulatorStateSchema, strict)\n\nconst issueMessage = (issue: Schema.SchemaError['issue']): string =>\n new Schema.SchemaError(issue).message\n\n/** A synthetic 64-digit content hash ending in `suffix`, as the fixtures write them. */\nexport const syntheticContentHash = (suffix: string): string => suffix.padStart(64, '0')\n\n// Default entries. Fixture-derived: every file, the `paging-two` folder, and every path, id, rev,\n// size, content hash, and timestamp of them. Implied (never rendered): the `/Conformance`,\n// `/Conformance/Paging`, `/Conformance/Search`, and `/Conformance/Work` folders.\n\nconst file = (\n path: string,\n id: string,\n revSuffix: string,\n size: number,\n hashSuffix: string,\n clientModified: string,\n serverModified: string = clientModified\n): DropboxEmulatorEntrySeed => ({\n path,\n id,\n kind: 'file',\n rev: `a1b2c3d4e5f6${revSuffix}`,\n size,\n contentHash: syntheticContentHash(hashSuffix),\n clientModified,\n serverModified\n})\n\nconst folder = (path: string, id: string): DropboxEmulatorEntrySeed => ({\n path,\n id,\n kind: 'folder'\n})\n\n/** A parent folder no fixture shows. */\nconst impliedFolder = (path: string, id: string): DropboxEmulatorEntrySeed => ({\n ...folder(path, id),\n implied: true\n})\n\nconst defaultEntries: ReadonlyArray<DropboxEmulatorEntrySeed> = [\n impliedFolder('/Conformance', 'id:SyntheticConformanceFolder'),\n impliedFolder('/Conformance/Paging', 'id:SyntheticPagingFolder0000'),\n file(\n '/Conformance/Paging/paging-one.txt',\n 'id:SyntheticPagingFile0001',\n '0001',\n 12,\n '1',\n '2026-09-20T10:00:00Z'\n ),\n folder('/Conformance/Paging/paging-two', 'id:SyntheticPagingFolder0002'),\n file(\n '/Conformance/Paging/paging-three.txt',\n 'id:SyntheticPagingFile0003',\n '0003',\n 14,\n '3',\n '2026-09-20T10:05:00Z'\n ),\n file(\n '/Conformance/Mixed Case Notes.txt',\n 'id:SyntheticMixedCaseFile01',\n '0010',\n 20,\n '10',\n '2026-09-20T11:00:00Z'\n ),\n impliedFolder('/Conformance/Search', 'id:SyntheticSearchFolder0000'),\n file(\n '/Conformance/Search/yolk-search-probe-1.txt',\n 'id:SyntheticSearchFile0001',\n '0021',\n 16,\n '21',\n '2026-09-20T12:00:00Z'\n ),\n file(\n '/Conformance/Search/yolk-search-probe-2.txt',\n 'id:SyntheticSearchFile0002',\n '0022',\n 16,\n '22',\n '2026-09-20T12:00:00Z'\n ),\n impliedFolder('/Conformance/Work', 'id:SyntheticWorkFolder00000'),\n file(\n '/Conformance/copy-source.txt',\n 'id:SyntheticCopySource001',\n '0030',\n 42,\n '42',\n '2026-09-20T13:00:00Z',\n '2026-09-29T13:00:00Z'\n )\n]\n\nconst profileEntries = (\n profile: DropboxEmulatorProfile\n): ReadonlyArray<DropboxEmulatorEntrySeed> => (profile === 'default' ? defaultEntries : [])\n\nconst defaultTimestamp = '2026-09-20T10:00:00Z'\n\n/** The form of minted ids (`id:SyntheticEntry00000001`) and revs (`a1b2c3d4e5f60101`). */\nconst mintedIdPattern = /^id:SyntheticEntry(\\d+)$/\n\nconst mintedRevPattern = /^a1b2c3d4e5f6(\\d+)$/\n\n/** The highest number among `values` in a minted form (0 when none is). */\nconst highestMinted = (values: ReadonlyArray<string>, pattern: RegExp): number =>\n Math.max(0, ...values.map(value => Number(pattern.exec(value)?.[1] ?? 0)))\n\nconst duplicate = (values: ReadonlyArray<string>): string | undefined =>\n values.find((value, index) => values.indexOf(value) !== index)\n\nconst parentPath = (path: string): string => path.slice(0, path.lastIndexOf('/'))\n\nconst lastName = (path: string): string => path.slice(path.lastIndexOf('/') + 1)\n\n/** Build the emulator state for a decoded seed; a string is an integrity problem. */\nconst stateFromSeed = (seed: DropboxEmulatorSeed): DropboxEmulatorState | string => {\n const seeded = seed.entries ?? profileEntries(seed.profile ?? 'default')\n\n const duplicates: ReadonlyArray<readonly [string, string | undefined]> = [\n ['entry id', duplicate(seeded.map(entry => entry.id))],\n ['entry path', duplicate(seeded.map(entry => entry.path.toLowerCase()))]\n ]\n\n for (const [label, value] of duplicates) {\n if (value !== undefined) return `duplicate ${label} ${value}`\n }\n\n const byPath = new Map(seeded.map(entry => [entry.path.toLowerCase(), entry]))\n const entries: Array<DropboxEmulatorEntry> = []\n\n for (const entry of seeded) {\n const name = lastName(entry.path)\n\n if (name === '.' || name === '..') return `entry ${entry.id} has an invalid path`\n\n const parent = parentPath(entry.path)\n const parentEntry = parent === '' ? undefined : byPath.get(parent.toLowerCase())\n\n if (parent !== '' && (parentEntry === undefined || parentEntry.kind !== 'folder')) {\n return `entry ${entry.path} needs a seeded parent folder ${parent}`\n }\n\n const hasFileFields = [\n entry.rev,\n entry.size,\n entry.contentHash,\n entry.clientModified,\n entry.serverModified\n ].some(Predicate.isNotUndefined)\n\n if (entry.kind === 'folder' && hasFileFields) {\n return `folder ${entry.path} cannot take file fields`\n }\n\n const clientModified = entry.clientModified ?? defaultTimestamp\n\n entries.push({\n id: entry.id,\n parentId: parentEntry?.id ?? null,\n name,\n implied: entry.implied ?? false,\n file:\n entry.kind === 'folder'\n ? null\n : {\n rev: entry.rev ?? 'a1b2c3d4e5f60000',\n size: entry.size ?? 0,\n contentHash: entry.contentHash ?? syntheticContentHash('0'),\n clientModified,\n serverModified: entry.serverModified ?? clientModified\n }\n })\n }\n\n return {\n entries,\n deleted: seed.deleted ?? [],\n counters: {\n nextIdNumber:\n highestMinted(\n entries.map(entry => entry.id),\n mintedIdPattern\n ) + 1,\n nextRevNumber: Math.max(\n 101,\n highestMinted(\n entries.flatMap(entry => entry.file?.rev ?? []),\n mintedRevPattern\n ) + 1\n )\n }\n }\n}\n\n/** Decode and build a seed; a string is the reason it is invalid. */\nexport const buildSeedState = (input: unknown): DropboxEmulatorState | string => {\n const decoded = decodeSeedInput(input)\n\n return Result.isFailure(decoded)\n ? issueMessage(decoded.failure.issue)\n : stateFromSeed(decoded.success)\n}\n\n/** Decode a full state (a restored snapshot); a string is the reason it is invalid. */\nexport const decodeState = (input: unknown): DropboxEmulatorState | string => {\n const decoded = decodeStateInput(input)\n\n return Result.isFailure(decoded) ? issueMessage(decoded.failure.issue) : { ...decoded.success }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"state.mjs","names":[],"sources":["../../src/dropbox/state.ts"],"sourcesContent":["/**\n * Dropbox emulator state: the typed entries, deleted-entry records, the seed input, the default\n * seed, and the profiles (internal; re-exported by `src/dropbox.ts`).\n *\n * Entry shapes and the default entries follow the synthetic Dropbox conformance fixtures, copied\n * as data (the same paths, ids, revs, sizes, content hashes, and timestamps as the fixtures and\n * `dropboxConformanceFixtureSeeds`), never imported from SDK code. The parent folders the seeded\n * paths need (`/Conformance`, `/Conformance/Paging`, `/Conformance/Search`, `/Conformance/Work`)\n * are `implied`: no fixture shows their metadata, so they hold paths together but any answer that\n * would render one is not emulated.\n *\n * Minted values never repeat seeded ones: the id and rev counters start above the highest seeded\n * id (`id:SyntheticEntryNNNNNNNN`) and rev (`a1b2c3d4e5f6NNNN`) in the minted form.\n *\n * @experimental\n */\nimport { Predicate, Result } from 'effect'\nimport * as Schema from 'effect/Schema'\n\n/** A Dropbox revision: lower-case hex, at least nine digits (what the connector accepts). */\nconst Rev = Schema.String.check(Schema.isPattern(/^[0-9a-f]{9,}$/u))\n\n/** A Dropbox file or folder id (`id:` form). */\nconst EntryId = Schema.String.check(Schema.isPattern(/^id:\\S+$/u))\n\n/** A Dropbox timestamp as the fixtures write it (`2026-09-20T10:00:00Z`). */\nconst Timestamp = Schema.String.check(Schema.isPattern(/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/u))\n\n/** One path component: non-empty, no `/`, not `.` or `..`. */\nconst EntryName = Schema.String.check(\n Schema.makeFilter(name =>\n name.length > 0 && !name.includes('/') && name !== '.' && name !== '..'\n ? true\n : 'an entry name is one non-empty path component'\n )\n)\n\n/** File fields (absent on folders). */\nexport const DropboxEmulatorFile = Schema.Struct({\n rev: Rev,\n size: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n contentHash: Schema.String,\n clientModified: Timestamp,\n serverModified: Timestamp\n})\n\nexport type DropboxEmulatorFile = typeof DropboxEmulatorFile.Type\n\n/** A stored file or folder. Its path is its parents' names and its own, in stored casing. */\nexport const DropboxEmulatorEntry = Schema.Struct({\n id: EntryId,\n /** Parent folder id; `null` in the root folder. */\n parentId: Schema.NullOr(EntryId),\n name: EntryName,\n /** `null` for a folder. */\n file: Schema.NullOr(DropboxEmulatorFile),\n /**\n * `true` for an entry no fixture shows, held only because a seeded path needs it: lookups pass\n * through it, but an answer that would render it is not emulated.\n */\n implied: Schema.Boolean\n})\n\nexport type DropboxEmulatorEntry = typeof DropboxEmulatorEntry.Type\n\n/**\n * What Dropbox keeps of a deleted entry (`include_deleted` lookups answer it): its name and paths\n * as they were. `delete_v2` records one only for an empty folder, the only delete whose\n * `include_deleted` answer a fixture records.\n */\nexport const DropboxEmulatorDeleted = Schema.Struct({\n name: EntryName,\n pathLower: Schema.String,\n pathDisplay: Schema.String\n})\n\nexport type DropboxEmulatorDeleted = typeof DropboxEmulatorDeleted.Type\n\nconst Counter = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))\n\nconst Counters = Schema.Struct({\n /** Next number in created entry ids (`id:SyntheticEntry00000001`). */\n nextIdNumber: Counter,\n /** Next number in minted revs (`a1b2c3d4e5f60101`). */\n nextRevNumber: Counter\n})\n\n/** The whole emulator state (JSON-compatible; what `snapshot()` returns). */\nexport const DropboxEmulatorStateSchema = Schema.Struct({\n entries: Schema.Array(DropboxEmulatorEntry),\n deleted: Schema.Array(DropboxEmulatorDeleted),\n counters: Counters\n})\n\n/**\n * The emulator state. The container is mutable (routes replace whole lists); every entity is\n * replaced, never edited in place.\n */\nexport type DropboxEmulatorState = {\n entries: ReadonlyArray<DropboxEmulatorEntry>\n deleted: ReadonlyArray<DropboxEmulatorDeleted>\n counters: typeof Counters.Type\n}\n\n/** An absolute path in display casing: `/`-separated non-empty components, no trailing `/`. */\nconst SeedPath = Schema.String.check(Schema.isPattern(/^(?:\\/[^/]+)+$/u))\n\n/**\n * A seeded entry, addressed by its display path (its parent folder must be seeded too). File\n * fields default to synthetic values; a folder takes none.\n */\nexport const DropboxEmulatorEntrySeed = Schema.Struct({\n path: SeedPath,\n id: EntryId,\n kind: Schema.Literals(['file', 'folder']),\n rev: Schema.optionalKey(Rev),\n size: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))),\n contentHash: Schema.optionalKey(Schema.String),\n clientModified: Schema.optionalKey(Timestamp),\n serverModified: Schema.optionalKey(Timestamp),\n /** An entry no fixture shows (default `false`); see `DropboxEmulatorEntry.implied`. */\n implied: Schema.optionalKey(Schema.Boolean)\n})\n\nexport type DropboxEmulatorEntrySeed = typeof DropboxEmulatorEntrySeed.Type\n\n/** Account-variance profiles for the default seed. */\nexport const DropboxEmulatorProfile = Schema.Literals(['default', 'empty'])\n\nexport type DropboxEmulatorProfile = typeof DropboxEmulatorProfile.Type\n\n/**\n * A typed seed. Start from `profile` (default `'default'`, the fixture entries); `entries` and\n * `deleted`, when given, replace that part of the profile.\n */\nexport const DropboxEmulatorSeed = Schema.Struct({\n profile: Schema.optionalKey(DropboxEmulatorProfile),\n entries: Schema.optionalKey(Schema.Array(DropboxEmulatorEntrySeed)),\n deleted: Schema.optionalKey(Schema.Array(DropboxEmulatorDeleted))\n})\n\nexport type DropboxEmulatorSeed = typeof DropboxEmulatorSeed.Type\n\nconst strict = { onExcessProperty: 'error' } as const\n\nconst decodeSeedInput = Schema.decodeUnknownResult(DropboxEmulatorSeed, strict)\n\nconst decodeStateInput = Schema.decodeUnknownResult(DropboxEmulatorStateSchema, strict)\n\nconst issueMessage = (issue: Schema.SchemaError['issue']): string =>\n new Schema.SchemaError(issue).message\n\n/** A synthetic 64-digit content hash ending in `suffix`, as the fixtures write them. */\nexport const syntheticContentHash = (suffix: string): string => suffix.padStart(64, '0')\n\n// Default entries. Fixture-derived: every file, the `paging-two` folder, and every path, id, rev,\n// size, content hash, and timestamp of them. Implied (never rendered): the `/Conformance`,\n// `/Conformance/Paging`, `/Conformance/Search`, and `/Conformance/Work` folders.\n\nconst file = (\n path: string,\n id: string,\n revSuffix: string,\n size: number,\n hashSuffix: string,\n clientModified: string,\n serverModified: string = clientModified\n): DropboxEmulatorEntrySeed => ({\n path,\n id,\n kind: 'file',\n rev: `a1b2c3d4e5f6${revSuffix}`,\n size,\n contentHash: syntheticContentHash(hashSuffix),\n clientModified,\n serverModified\n})\n\nconst folder = (path: string, id: string): DropboxEmulatorEntrySeed => ({\n path,\n id,\n kind: 'folder'\n})\n\n/** A parent folder no fixture shows. */\nconst impliedFolder = (path: string, id: string): DropboxEmulatorEntrySeed => ({\n ...folder(path, id),\n implied: true\n})\n\nconst defaultEntries: ReadonlyArray<DropboxEmulatorEntrySeed> = [\n impliedFolder('/Conformance', 'id:SyntheticConformanceFolder'),\n impliedFolder('/Conformance/Paging', 'id:SyntheticPagingFolder0000'),\n file(\n '/Conformance/Paging/paging-one.txt',\n 'id:SyntheticPagingFile0001',\n '0001',\n 12,\n '1',\n '2026-09-20T10:00:00Z'\n ),\n folder('/Conformance/Paging/paging-two', 'id:SyntheticPagingFolder0002'),\n file(\n '/Conformance/Paging/paging-three.txt',\n 'id:SyntheticPagingFile0003',\n '0003',\n 14,\n '3',\n '2026-09-20T10:05:00Z'\n ),\n file(\n '/Conformance/Mixed Case Notes.txt',\n 'id:SyntheticMixedCaseFile01',\n '0010',\n 20,\n '10',\n '2026-09-20T11:00:00Z'\n ),\n impliedFolder('/Conformance/Search', 'id:SyntheticSearchFolder0000'),\n file(\n '/Conformance/Search/yolk-search-probe-1.txt',\n 'id:SyntheticSearchFile0001',\n '0021',\n 16,\n '21',\n '2026-09-20T12:00:00Z'\n ),\n file(\n '/Conformance/Search/yolk-search-probe-2.txt',\n 'id:SyntheticSearchFile0002',\n '0022',\n 16,\n '22',\n '2026-09-20T12:00:00Z'\n ),\n impliedFolder('/Conformance/Work', 'id:SyntheticWorkFolder00000'),\n file(\n '/Conformance/copy-source.txt',\n 'id:SyntheticCopySource001',\n '0030',\n 42,\n '42',\n '2026-09-20T13:00:00Z',\n '2026-09-29T13:00:00Z'\n )\n]\n\nconst profileEntries = (\n profile: DropboxEmulatorProfile\n): ReadonlyArray<DropboxEmulatorEntrySeed> => (profile === 'default' ? defaultEntries : [])\n\nconst defaultTimestamp = '2026-09-20T10:00:00Z'\n\n/** The form of minted ids (`id:SyntheticEntry00000001`) and revs (`a1b2c3d4e5f60101`). */\nconst mintedIdPattern = /^id:SyntheticEntry(\\d+)$/\n\nconst mintedRevPattern = /^a1b2c3d4e5f6(\\d+)$/\n\n/** The highest number among `values` in a minted form (0 when none is). */\nconst highestMinted = (values: ReadonlyArray<string>, pattern: RegExp): number =>\n Math.max(0, ...values.map(value => Number(pattern.exec(value)?.[1] ?? 0)))\n\nconst duplicate = (values: ReadonlyArray<string>): string | undefined =>\n values.find((value, index) => values.indexOf(value) !== index)\n\nconst parentPath = (path: string): string => path.slice(0, path.lastIndexOf('/'))\n\nconst lastName = (path: string): string => path.slice(path.lastIndexOf('/') + 1)\n\n/** Build the emulator state for a decoded seed; a string is an integrity problem. */\nconst stateFromSeed = (seed: DropboxEmulatorSeed): DropboxEmulatorState | string => {\n const seeded = seed.entries ?? profileEntries(seed.profile ?? 'default')\n\n const duplicates: ReadonlyArray<readonly [string, string | undefined]> = [\n ['entry id', duplicate(seeded.map(entry => entry.id))],\n ['entry path', duplicate(seeded.map(entry => entry.path.toLowerCase()))]\n ]\n\n for (const [label, value] of duplicates) {\n if (value !== undefined) return `duplicate ${label} ${value}`\n }\n\n const byPath = new Map(seeded.map(entry => [entry.path.toLowerCase(), entry]))\n const entries: Array<DropboxEmulatorEntry> = []\n\n for (const entry of seeded) {\n const name = lastName(entry.path)\n\n if (name === '.' || name === '..') return `entry ${entry.id} has an invalid path`\n\n const parent = parentPath(entry.path)\n const parentEntry = parent === '' ? undefined : byPath.get(parent.toLowerCase())\n\n if (parent !== '' && (parentEntry === undefined || parentEntry.kind !== 'folder')) {\n return `entry ${entry.path} needs a seeded parent folder ${parent}`\n }\n\n const hasFileFields = [\n entry.rev,\n entry.size,\n entry.contentHash,\n entry.clientModified,\n entry.serverModified\n ].some(Predicate.isNotUndefined)\n\n if (entry.kind === 'folder' && hasFileFields) {\n return `folder ${entry.path} cannot take file fields`\n }\n\n const clientModified = entry.clientModified ?? defaultTimestamp\n\n entries.push({\n id: entry.id,\n parentId: parentEntry?.id ?? null,\n name,\n implied: entry.implied ?? false,\n file:\n entry.kind === 'folder'\n ? null\n : {\n rev: entry.rev ?? 'a1b2c3d4e5f60000',\n size: entry.size ?? 0,\n contentHash: entry.contentHash ?? syntheticContentHash('0'),\n clientModified,\n serverModified: entry.serverModified ?? clientModified\n }\n })\n }\n\n return {\n entries,\n deleted: seed.deleted ?? [],\n counters: {\n nextIdNumber:\n highestMinted(\n entries.map(entry => entry.id),\n mintedIdPattern\n ) + 1,\n nextRevNumber: Math.max(\n 101,\n highestMinted(\n entries.flatMap(entry => entry.file?.rev ?? []),\n mintedRevPattern\n ) + 1\n )\n }\n }\n}\n\n/** Decode and build a seed; a string is the reason it is invalid. */\nexport const buildSeedState = (input: unknown): DropboxEmulatorState | string => {\n const decoded = decodeSeedInput(input)\n\n return Result.isFailure(decoded)\n ? issueMessage(decoded.failure.issue)\n : stateFromSeed(decoded.success)\n}\n\n/** Decode a full state (a restored snapshot); a string is the reason it is invalid. */\nexport const decodeState = (input: unknown): DropboxEmulatorState | string => {\n const decoded = decodeStateInput(input)\n\n return Result.isFailure(decoded) ? issueMessage(decoded.failure.issue) : { ...decoded.success }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.mts","names":[],"sources":["../../src/github/state.ts"],"mappings":";;;;cA8Ba,kBAAA,EAAkB,MAAwD;AAAvF;AAAA,cAGa,iBAAA,EAAiB,MAA4B;;cAG7C,sBAAA,EAAsB,MAAsC;AANc;AAGvF;;;AAHuF,cAY1E,oBAAA;AAT6C;AAAA,cAY7C,qBAAA,EAAqB,MAA0C;;cAG/D,sBAAA,EAAsB,MAA2C;;cAOjE,oBAAA;AAbb;AAAA,cAkBa,kBAAA;;cAOA,kBAAA,EAAkB,MAAA,CAAA,MAAA;EAAA;;;;;KAOnB,kBAAA,UAA4B,kBAAA,CAAmB,IAAI;AA1B/D;AAAA,cA6Ba,wBAAA,EAAwB,MAAA,CAAA,MAAA;EAAA;gCA7ByC;EAAA;;;KA4ClE,wBAAA,UAAkC,wBAAA,CAAyB,IAAI;AArC1C;AAAA,cAwCpB,mBAAA,EAAmB,MAAA,CAAA,MAAA;EAAA;;gCAnCD;EAAA;;;;KA6CnB,mBAAA,UAA6B,mBAAA,CAAoB,IAAI;;cAGpD,uBAAA,EAAuB,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;;;;KAgBxB,uBAAA,UAAiC,uBAAA,CAAwB,IAAI;;cAG5D,mBAAA,EAAmB,MAAA,CAAA,MAAA;EArDQ;;;;;;;;;;;;;;;;;;;;KA2D5B,mBAAA,UAA6B,mBAAA,CAAoB,IAAI;;cAGpD,qBAAA,EAAqB,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;KAUtB,qBAAA,UAA+B,qBAAA,CAAsB,IAAI;;cAGxD,kBAAA,EAAkB,MAAA,CAAA,MAAA;EAAA;;;;KAOnB,kBAAA,UAA4B,kBAAA,CAAmB,IAAI;AAAA,cAEzD,QAAA,EAAQ,MAAA,CAAA,MAAA;EA/DkB;;;;cAuEnB,yBAAA,EAAyB,MAAA,CAAA,MAAA;;;;;;;;;;;;;;;;kCA7DG;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8E7B,mBAAA;EACV,MAAA,EAAQ,kBAAA;EACR,UAAA,EAAY,wBAAA;EACZ,MAAA,EAAQ,aAAA,CAAc,mBAAA;EACtB,MAAA,EAAQ,aAAA,CAAc,mBAAA;EACtB,QAAA,EAAU,aAAA,CAAc,qBAAA;EACxB,eAAA,EAAiB,aAAA;EACjB,KAAA,EAAO,aAAA,CAAc,kBAAA;EACrB,QAAA,SAAiB,QAAA,CAAS,IAAA;AAAA;;cAIf,qBAAA,EAAqB,MAAA,CAAA,QAAA;AAAA,KAEtB,qBAAA,UAA+B,qBAAA,CAAsB,IAAI;;;;;;cAOxD,kBAAA,EAAkB,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;kCAhF0C;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;kCAGzC;IAAA;;;;;;KAwFpB,kBAAA,UAA4B,kBAAA,CAAmB,IAAI;;cAYlD,iBAAA;AAAA,cAEA,iBAAA,GAAqB,MAAc;AAAA,cAEnC,mBAAA,GAAuB,EAAU;;cAkMjC,cAAA,GAAkB,KAAA,cAAiB,mBAAmB;;cAStD,WAAA,GAAe,KAAA,cAAiB,mBAAmB"}
1
+ {"version":3,"file":"state.d.mts","names":[],"sources":["../../src/github/state.ts"],"mappings":";;;;cA8Ba,kBAAA,EAAkB,MAAyD;AAAxF;AAAA,cAGa,iBAAA,EAAiB,MAA6B;;cAG9C,sBAAA,EAAsB,MAAuC;AANc;AAGxF;;;AAHwF,cAY3E,oBAAA;AAT8C;AAAA,cAY9C,qBAAA,EAAqB,MAA+C;;cAGpE,sBAAA,EAAsB,MAA4C;;cAOlE,oBAAA;AAbb;AAAA,cAkBa,kBAAA;;cAOA,kBAAA,EAAkB,MAAA,CAAA,MAAA;EAAA;;;;;KAOnB,kBAAA,UAA4B,kBAAA,CAAmB,IAAI;AA1B/D;AAAA,cA6Ba,wBAAA,EAAwB,MAAA,CAAA,MAAA;EAAA;gCA7B0C;EAAA;;;KA4CnE,wBAAA,UAAkC,wBAAA,CAAyB,IAAI;AArC1C;AAAA,cAwCpB,mBAAA,EAAmB,MAAA,CAAA,MAAA;EAAA;;gCAnCD;EAAA;;;;KA6CnB,mBAAA,UAA6B,mBAAA,CAAoB,IAAI;;cAGpD,uBAAA,EAAuB,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;;;;KAgBxB,uBAAA,UAAiC,uBAAA,CAAwB,IAAI;;cAG5D,mBAAA,EAAmB,MAAA,CAAA,MAAA;EArDQ;;;;;;;;;;;;;;;;;;;;KA2D5B,mBAAA,UAA6B,mBAAA,CAAoB,IAAI;;cAGpD,qBAAA,EAAqB,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;KAUtB,qBAAA,UAA+B,qBAAA,CAAsB,IAAI;;cAGxD,kBAAA,EAAkB,MAAA,CAAA,MAAA;EAAA;;;;KAOnB,kBAAA,UAA4B,kBAAA,CAAmB,IAAI;AAAA,cAEzD,QAAA,EAAQ,MAAA,CAAA,MAAA;EA/DkB;;;;cAuEnB,yBAAA,EAAyB,MAAA,CAAA,MAAA;;;;;;;;;;;;;;;;kCA7DG;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8E7B,mBAAA;EACV,MAAA,EAAQ,kBAAA;EACR,UAAA,EAAY,wBAAA;EACZ,MAAA,EAAQ,aAAA,CAAc,mBAAA;EACtB,MAAA,EAAQ,aAAA,CAAc,mBAAA;EACtB,QAAA,EAAU,aAAA,CAAc,qBAAA;EACxB,eAAA,EAAiB,aAAA;EACjB,KAAA,EAAO,aAAA,CAAc,kBAAA;EACrB,QAAA,SAAiB,QAAA,CAAS,IAAA;AAAA;;cAIf,qBAAA,EAAqB,MAAA,CAAA,QAAA;AAAA,KAEtB,qBAAA,UAA+B,qBAAA,CAAsB,IAAI;;;;;;cAOxD,kBAAA,EAAkB,MAAA,CAAA,MAAA;EAAA;;;;;;;;;;;;;;;;kCAhF0C;IAAA;;;;;;;;;;;;;;;;;;;;;;;;;kCAGzC;IAAA;;;;;;KAwFpB,kBAAA,UAA4B,kBAAA,CAAmB,IAAI;;cAYlD,iBAAA;AAAA,cAEA,iBAAA,GAAqB,MAAc;AAAA,cAEnC,mBAAA,GAAuB,EAAU;;cAkMjC,cAAA,GAAkB,KAAA,cAAiB,mBAAmB;;cAStD,WAAA,GAAe,KAAA,cAAiB,mBAAmB"}
@@ -28,20 +28,20 @@ import * as Schema from "effect/Schema";
28
28
  * @experimental
29
29
  */
30
30
  /** A GitHub owner login (the connector's owner pattern). */
31
- const githubOwnerPattern = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/;
31
+ const githubOwnerPattern = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/u;
32
32
  /** A repository name in plain characters (no `.`/`..`, no `.git` suffix; checked below). */
33
- const githubRepoPattern = /^[A-Za-z0-9._-]{1,100}$/;
33
+ const githubRepoPattern = /^[A-Za-z0-9._-]{1,100}$/u;
34
34
  /** A label name in plain characters (the conformance seed pattern; never percent-encoded). */
35
- const githubLabelNamePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,49}$/;
35
+ const githubLabelNamePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,49}$/u;
36
36
  /**
37
37
  * The source of a relative file path whose segments never start with a dot (the conformance seed
38
38
  * pattern), unanchored, so the route's raw pattern can add its length bound explicitly.
39
39
  */
40
40
  const githubFilePathSource = "[A-Za-z0-9_-][A-Za-z0-9._-]*(?:/[A-Za-z0-9_-][A-Za-z0-9._-]*)*";
41
41
  /** A relative file path whose segments never start with a dot (the conformance seed pattern). */
42
- const githubFilePathPattern = new RegExp(`^${githubFilePathSource}$`);
42
+ const githubFilePathPattern = new RegExp(`^${githubFilePathSource}$`, "u");
43
43
  /** A GitHub timestamp as the fixtures write it: whole seconds, UTC. */
44
- const githubTimestampPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
44
+ const githubTimestampPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/u;
45
45
  const Timestamp = Schema.String.check(Schema.isPattern(githubTimestampPattern));
46
46
  const PositiveInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1));
47
47
  /** The largest issue number the emulator addresses (ten digits, the route pattern). */
@@ -64,7 +64,7 @@ const GithubEmulatorRepository = Schema.Struct({
64
64
  repo: Schema.String.check(Schema.isPattern(githubRepoPattern), Schema.makeFilter((repo) => repo !== "." && repo !== ".." && !repo.endsWith(".git") || "a repository name is not . or .. and does not end in .git")),
65
65
  /** The id the `Link` URLs name (`/repositories/<id>/labels`). */
66
66
  id: PositiveInt,
67
- defaultBranch: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9._-]{1,100}$/))
67
+ defaultBranch: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9._-]{1,100}$/u))
68
68
  });
69
69
  /** A repository label. */
70
70
  const GithubEmulatorLabel = Schema.Struct({
@@ -72,7 +72,7 @@ const GithubEmulatorLabel = Schema.Struct({
72
72
  nodeId: Schema.String,
73
73
  name: LabelName,
74
74
  /** Six hex digits, as the fixtures write colors. */
75
- color: Schema.String.check(Schema.isPattern(/^[0-9a-f]{6}$/)),
75
+ color: Schema.String.check(Schema.isPattern(/^[0-9a-f]{6}$/u)),
76
76
  default: Schema.Boolean,
77
77
  description: Schema.NullOr(Schema.String)
78
78
  });
@@ -112,7 +112,7 @@ const GithubEmulatorComment = Schema.Struct({
112
112
  const GithubEmulatorFile = Schema.Struct({
113
113
  path: Schema.String.check(Schema.isPattern(githubFilePathPattern), Schema.isMaxLength(200)),
114
114
  /** The blob sha (40 lower-case hex digits). */
115
- sha: Schema.String.check(Schema.isPattern(/^[0-9a-f]{40}$/)),
115
+ sha: Schema.String.check(Schema.isPattern(/^[0-9a-f]{40}$/u)),
116
116
  text: Schema.String
117
117
  });
118
118
  const Counters = Schema.Struct({
@@ -1 +1 @@
1
- {"version":3,"file":"state.mjs","names":[],"sources":["../../src/github/state.ts"],"sourcesContent":["/**\n * GitHub emulator state: the authenticated user, the practice repository, its labels, issues,\n * comments, and files, the record of deleted comments, the counters, the seed input, the default\n * seed, and the profiles (internal; re-exported by `src/github.ts`).\n *\n * Entity shapes and the default entities follow the synthetic GitHub conformance fixtures, copied\n * as data (the same owner, repository, labels, work issue, file, user, and ids as the fixtures and\n * `githubConformanceFixtureSeeds`), never imported from SDK code. The repository id is the one the\n * paging fixture's `Link` URLs name, and the default branch is the one the contents fixture's URLs\n * name.\n *\n * Issue numbers below `nextIssueNumber` that the state does not hold are implied (the repository\n * reached them, but no fixture shows them): an answer that would render one is not emulated.\n * Numbers at or above it are not reached yet and answer the not-found fixture's 404. Created issue\n * numbers and comment ids come from counters that only advance; the default seed starts them at the\n * fixtures' created values (issue 42, comment 9000000001), and a seed's counters must lie above\n * every seeded number. Created issue `id` and `node_id` values derive from the minted number in the\n * fixtures' form (`3000000000 + number`, `I_kwSynthetic<number>`), and created comment `node_id`\n * values from the minted id (`IC_kwSynthetic<id>`); a seed may not use those minted forms at or\n * above its counters.\n *\n * Comments exist only as created here (no fixture shows a seeded comment). A deleted comment is\n * kept as a record (`deletedComments`): deleting it again answers the comment fixture's 404.\n *\n * @experimental\n */\nimport { Result } from 'effect'\nimport * as Schema from 'effect/Schema'\n\n/** A GitHub owner login (the connector's owner pattern). */\nexport const githubOwnerPattern = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/\n\n/** A repository name in plain characters (no `.`/`..`, no `.git` suffix; checked below). */\nexport const githubRepoPattern = /^[A-Za-z0-9._-]{1,100}$/\n\n/** A label name in plain characters (the conformance seed pattern; never percent-encoded). */\nexport const githubLabelNamePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,49}$/\n\n/**\n * The source of a relative file path whose segments never start with a dot (the conformance seed\n * pattern), unanchored, so the route's raw pattern can add its length bound explicitly.\n */\nexport const githubFilePathSource = '[A-Za-z0-9_-][A-Za-z0-9._-]*(?:/[A-Za-z0-9_-][A-Za-z0-9._-]*)*'\n\n/** A relative file path whose segments never start with a dot (the conformance seed pattern). */\nexport const githubFilePathPattern = new RegExp(`^${githubFilePathSource}$`)\n\n/** A GitHub timestamp as the fixtures write it: whole seconds, UTC. */\nexport const githubTimestampPattern = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/\n\nconst Timestamp = Schema.String.check(Schema.isPattern(githubTimestampPattern))\n\nconst PositiveInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))\n\n/** The largest issue number the emulator addresses (ten digits, the route pattern). */\nexport const githubMaxIssueNumber = 9_999_999_999\n\nconst IssueNumber = PositiveInt.check(Schema.isLessThanOrEqualTo(githubMaxIssueNumber))\n\n/** The largest comment id the emulator addresses (fifteen digits, the delete route's pattern). */\nexport const githubMaxCommentId = 999_999_999_999_999\n\nconst CommentId = PositiveInt.check(Schema.isLessThanOrEqualTo(githubMaxCommentId))\n\nconst LabelName = Schema.String.check(Schema.isPattern(githubLabelNamePattern))\n\n/** A user as the fixtures render it (`login`, `id`, `type`, `site_admin`). */\nexport const GithubEmulatorUser = Schema.Struct({\n login: Schema.String.check(Schema.isPattern(githubOwnerPattern)),\n id: PositiveInt,\n type: Schema.String,\n siteAdmin: Schema.Boolean\n})\n\nexport type GithubEmulatorUser = typeof GithubEmulatorUser.Type\n\n/** The practice repository: its owner and name, its numeric id, and its default branch. */\nexport const GithubEmulatorRepository = Schema.Struct({\n owner: Schema.String.check(Schema.isPattern(githubOwnerPattern)),\n repo: Schema.String.check(\n Schema.isPattern(githubRepoPattern),\n Schema.makeFilter(\n (repo: string) =>\n (repo !== '.' && repo !== '..' && !repo.endsWith('.git')) ||\n 'a repository name is not . or .. and does not end in .git'\n )\n ),\n /** The id the `Link` URLs name (`/repositories/<id>/labels`). */\n id: PositiveInt,\n defaultBranch: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9._-]{1,100}$/))\n})\n\nexport type GithubEmulatorRepository = typeof GithubEmulatorRepository.Type\n\n/** A repository label. */\nexport const GithubEmulatorLabel = Schema.Struct({\n id: PositiveInt,\n nodeId: Schema.String,\n name: LabelName,\n /** Six hex digits, as the fixtures write colors. */\n color: Schema.String.check(Schema.isPattern(/^[0-9a-f]{6}$/)),\n default: Schema.Boolean,\n description: Schema.NullOr(Schema.String)\n})\n\nexport type GithubEmulatorLabel = typeof GithubEmulatorLabel.Type\n\n/** A seeded issue (its labels by name; never a pull request, never locked). */\nexport const GithubEmulatorSeedIssue = Schema.Struct({\n number: IssueNumber,\n id: PositiveInt,\n nodeId: Schema.String,\n title: Schema.String.check(Schema.isMinLength(1)),\n body: Schema.NullOr(Schema.String),\n state: Schema.Literals(['open', 'closed']),\n stateReason: Schema.NullOr(Schema.String),\n labels: Schema.Array(LabelName),\n user: GithubEmulatorUser,\n authorAssociation: Schema.String,\n createdAt: Timestamp,\n updatedAt: Timestamp,\n closedAt: Schema.NullOr(Timestamp)\n})\n\nexport type GithubEmulatorSeedIssue = typeof GithubEmulatorSeedIssue.Type\n\n/** A stored issue: a seeded one, or one created through the recorded create flow. */\nexport const GithubEmulatorIssue = Schema.Struct({\n ...GithubEmulatorSeedIssue.fields,\n /** Created here (only such issues are renamed or closed). */\n createdHere: Schema.Boolean\n})\n\nexport type GithubEmulatorIssue = typeof GithubEmulatorIssue.Type\n\n/** A comment created here on an issue. */\nexport const GithubEmulatorComment = Schema.Struct({\n id: CommentId,\n issueNumber: IssueNumber,\n body: Schema.String,\n user: GithubEmulatorUser,\n authorAssociation: Schema.String,\n createdAt: Timestamp,\n updatedAt: Timestamp\n})\n\nexport type GithubEmulatorComment = typeof GithubEmulatorComment.Type\n\n/** A UTF-8 text file in the default branch. */\nexport const GithubEmulatorFile = Schema.Struct({\n path: Schema.String.check(Schema.isPattern(githubFilePathPattern), Schema.isMaxLength(200)),\n /** The blob sha (40 lower-case hex digits). */\n sha: Schema.String.check(Schema.isPattern(/^[0-9a-f]{40}$/)),\n text: Schema.String\n})\n\nexport type GithubEmulatorFile = typeof GithubEmulatorFile.Type\n\nconst Counters = Schema.Struct({\n /** The number the next created issue takes (one past the maximum when exhausted). */\n nextIssueNumber: PositiveInt.check(Schema.isLessThanOrEqualTo(githubMaxIssueNumber + 1)),\n /** The id the next created comment takes (one past the maximum when exhausted). */\n nextCommentId: PositiveInt.check(Schema.isLessThanOrEqualTo(githubMaxCommentId + 1))\n})\n\n/** The whole emulator state (JSON-compatible; what `snapshot()` returns). */\nexport const GithubEmulatorStateSchema = Schema.Struct({\n /** The authenticated user: the author of everything created here. */\n viewer: GithubEmulatorUser,\n repository: GithubEmulatorRepository,\n labels: Schema.Array(GithubEmulatorLabel),\n issues: Schema.Array(GithubEmulatorIssue),\n comments: Schema.Array(GithubEmulatorComment),\n /** Ids of comments deleted here (a second delete answers the recorded 404). */\n deletedComments: Schema.Array(CommentId),\n files: Schema.Array(GithubEmulatorFile),\n counters: Counters\n})\n\n/**\n * The emulator state. The container is mutable (routes replace whole lists); every entity is\n * replaced, never edited in place.\n */\nexport type GithubEmulatorState = {\n viewer: GithubEmulatorUser\n repository: GithubEmulatorRepository\n labels: ReadonlyArray<GithubEmulatorLabel>\n issues: ReadonlyArray<GithubEmulatorIssue>\n comments: ReadonlyArray<GithubEmulatorComment>\n deletedComments: ReadonlyArray<number>\n files: ReadonlyArray<GithubEmulatorFile>\n counters: typeof Counters.Type\n}\n\n/** Account-variance profiles for the default seed. */\nexport const GithubEmulatorProfile = Schema.Literals(['default', 'empty'])\n\nexport type GithubEmulatorProfile = typeof GithubEmulatorProfile.Type\n\n/**\n * A typed seed. Start from `profile` (default `'default'`, the fixture entities); every other key,\n * when given, replaces that part of the profile. Counters default to the profile's, raised above\n * the highest seeded issue number; a counter given at or below a seeded value is invalid.\n */\nexport const GithubEmulatorSeed = Schema.Struct({\n profile: Schema.optionalKey(GithubEmulatorProfile),\n viewer: Schema.optionalKey(GithubEmulatorUser),\n repository: Schema.optionalKey(GithubEmulatorRepository),\n labels: Schema.optionalKey(Schema.Array(GithubEmulatorLabel)),\n issues: Schema.optionalKey(Schema.Array(GithubEmulatorSeedIssue)),\n files: Schema.optionalKey(Schema.Array(GithubEmulatorFile)),\n nextIssueNumber: Schema.optionalKey(IssueNumber),\n nextCommentId: Schema.optionalKey(CommentId)\n})\n\nexport type GithubEmulatorSeed = typeof GithubEmulatorSeed.Type\n\nconst strict = { onExcessProperty: 'error' } as const\n\nconst decodeSeedInput = Schema.decodeUnknownResult(GithubEmulatorSeed, strict)\n\nconst decodeStateInput = Schema.decodeUnknownResult(GithubEmulatorStateSchema, strict)\n\nconst issueMessage = (issue: Schema.SchemaError['issue']): string =>\n new Schema.SchemaError(issue).message\n\n/** Minted issue `id` values: `3000000000 + number`, as the fixtures write them. */\nexport const mintedIssueIdBase = 3_000_000_000\n\nexport const mintedIssueNodeId = (number: number): string => `I_kwSynthetic${number}`\n\nexport const mintedCommentNodeId = (id: number): string => `IC_kwSynthetic${id}`\n\n// Default entities, copied from the fixtures: the user, the practice repository (the paging\n// fixture's repository id, the contents fixture's branch), the five labels of the paging fixture,\n// the work issue of the label fixture, and the text file of the contents fixture.\n\nconst seededAt = '2026-09-30T12:00:00Z'\n\nconst defaultViewer: GithubEmulatorUser = {\n login: 'yolk-synthetic-bot',\n id: 1000001,\n type: 'User',\n siteAdmin: false\n}\n\nconst defaultRepository: GithubEmulatorRepository = {\n owner: 'yolk-synthetic',\n repo: 'conformance-practice',\n id: 100000001,\n defaultBranch: 'main'\n}\n\nconst label = (id: number, name: string, color: string): GithubEmulatorLabel => ({\n id,\n nodeId: `LA_kwSynthetic${id}`,\n name,\n color,\n default: false,\n description: `Synthetic ${name} label`\n})\n\nconst defaultLabels: ReadonlyArray<GithubEmulatorLabel> = [\n label(700000001, 'bug', 'd73a4a'),\n label(700000002, 'documentation', '0075ca'),\n label(700000003, 'enhancement', 'a2eeef'),\n label(700000004, 'question', 'd876e3'),\n label(700000005, 'synthetic-conformance', 'ededed')\n]\n\nconst workIssue: GithubEmulatorSeedIssue = {\n number: 1,\n id: mintedIssueIdBase + 1,\n nodeId: mintedIssueNodeId(1),\n title: 'Synthetic work issue for conformance runs',\n body: 'Synthetic work issue: conformance cases add and remove a label and a comment here.',\n state: 'open',\n stateReason: null,\n labels: ['bug'],\n user: defaultViewer,\n authorAssociation: 'OWNER',\n createdAt: seededAt,\n updatedAt: seededAt,\n closedAt: null\n}\n\nconst notesFile: GithubEmulatorFile = {\n path: 'docs/synthetic-notes.txt',\n sha: '5f1c0ffee5f1c0ffee5f1c0ffee5f1c0ffee0001',\n text:\n 'Synthetic conformance notes for the practice repository: café, naïve, façade.\\n' +\n 'Second synthetic line.\\n'\n}\n\ntype ProfileParts = {\n readonly viewer: GithubEmulatorUser\n readonly repository: GithubEmulatorRepository\n readonly labels: ReadonlyArray<GithubEmulatorLabel>\n readonly issues: ReadonlyArray<GithubEmulatorSeedIssue>\n readonly files: ReadonlyArray<GithubEmulatorFile>\n readonly counters: typeof Counters.Type\n}\n\nconst profileParts = (profile: GithubEmulatorProfile): ProfileParts =>\n profile === 'default'\n ? {\n viewer: defaultViewer,\n repository: defaultRepository,\n labels: defaultLabels,\n issues: [workIssue],\n files: [notesFile],\n // The lifecycle fixture's created issue and the comment fixture's created comment.\n counters: { nextIssueNumber: 42, nextCommentId: 9000000001 }\n }\n : {\n viewer: defaultViewer,\n repository: defaultRepository,\n labels: [],\n issues: [],\n files: [],\n counters: { nextIssueNumber: 1, nextCommentId: 1 }\n }\n\nconst duplicate = <A>(values: ReadonlyArray<A>): A | undefined =>\n values.find((value, index) => values.indexOf(value) !== index)\n\n/** Integrity problems a decoded seed can still have (duplicates, dangling or minted values). */\nconst seedProblem = (parts: ProfileParts): string | undefined => {\n const duplicates: ReadonlyArray<readonly [string, unknown]> = [\n ['label name', duplicate(parts.labels.map(entry => entry.name))],\n ['label id', duplicate(parts.labels.map(entry => entry.id))],\n ['issue number', duplicate(parts.issues.map(issue => issue.number))],\n ['issue id', duplicate(parts.issues.map(issue => issue.id))],\n // Node ids are global across types (labels and issues alike).\n [\n 'node id',\n duplicate([...parts.labels.map(entry => entry.nodeId), ...parts.issues.map(i => i.nodeId)])\n ],\n ['file path', duplicate(parts.files.map(file => file.path))]\n ]\n\n for (const [kind, value] of duplicates) {\n if (value !== undefined) return `duplicate ${kind} ${String(value)}`\n }\n\n const labelNames = new Set(parts.labels.map(entry => entry.name))\n\n for (const issue of parts.issues) {\n const missing = issue.labels.find(name => !labelNames.has(name))\n\n if (missing !== undefined) return `issue ${issue.number} names missing label ${missing}`\n\n if (duplicate(issue.labels) !== undefined) return `issue ${issue.number} repeats a label`\n\n if (issue.number >= parts.counters.nextIssueNumber) {\n return `nextIssueNumber must lie above seeded issue ${issue.number}`\n }\n\n // Minted ids never collide with seeded ones.\n if (issue.id >= mintedIssueIdBase + parts.counters.nextIssueNumber) {\n return `issue ${issue.number} uses an id in the minted form at or above nextIssueNumber`\n }\n }\n\n // Every minted node id form is reserved across all seeded node ids, of issues and labels alike.\n const reserved = [...parts.labels.map(entry => entry.nodeId), ...parts.issues.map(i => i.nodeId)]\n .map(nodeId => {\n const issueNumber = /^I_kwSynthetic(\\d+)$/.exec(nodeId)?.[1]\n const commentId = /^IC_kwSynthetic(\\d+)$/.exec(nodeId)?.[1]\n\n return (issueNumber !== undefined && Number(issueNumber) >= parts.counters.nextIssueNumber) ||\n (commentId !== undefined && Number(commentId) >= parts.counters.nextCommentId)\n ? nodeId\n : undefined\n })\n .find(nodeId => nodeId !== undefined)\n\n if (reserved !== undefined) {\n return `node id ${reserved} uses a minted form at or above its counter`\n }\n\n const prefix = parts.files.find(file =>\n parts.files.some(other => other.path.startsWith(`${file.path}/`))\n )\n\n return prefix === undefined ? undefined : `file ${prefix.path} is also a folder`\n}\n\n/** Build the emulator state for a decoded seed; a string is an integrity problem. */\nconst stateFromSeed = (seed: GithubEmulatorSeed): GithubEmulatorState | string => {\n const profile = profileParts(seed.profile ?? 'default')\n const issues = seed.issues ?? profile.issues\n const highest = Math.max(0, ...issues.map(issue => issue.number))\n\n const parts: ProfileParts = {\n viewer: seed.viewer ?? profile.viewer,\n repository: seed.repository ?? profile.repository,\n labels: seed.labels ?? profile.labels,\n issues,\n files: seed.files ?? profile.files,\n counters: {\n // Raised above the seeded numbers unless the seed names the counter itself (then checked).\n nextIssueNumber:\n seed.nextIssueNumber ?? Math.max(profile.counters.nextIssueNumber, highest + 1),\n nextCommentId: seed.nextCommentId ?? profile.counters.nextCommentId\n }\n }\n\n const problem = seedProblem(parts)\n\n return (\n problem ?? {\n viewer: parts.viewer,\n repository: parts.repository,\n labels: parts.labels,\n issues: parts.issues.map(issue => ({ ...issue, createdHere: false })),\n comments: [],\n deletedComments: [],\n files: parts.files,\n counters: parts.counters\n }\n )\n}\n\n/** Decode and build a seed; a string is the reason it is invalid. */\nexport const buildSeedState = (input: unknown): GithubEmulatorState | string => {\n const decoded = decodeSeedInput(input)\n\n return Result.isFailure(decoded)\n ? issueMessage(decoded.failure.issue)\n : stateFromSeed(decoded.success)\n}\n\n/** Decode a full state (a restored snapshot); a string is the reason it is invalid. */\nexport const decodeState = (input: unknown): GithubEmulatorState | string => {\n const decoded = decodeStateInput(input)\n\n return Result.isFailure(decoded) ? issueMessage(decoded.failure.issue) : { ...decoded.success }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"state.mjs","names":[],"sources":["../../src/github/state.ts"],"sourcesContent":["/**\n * GitHub emulator state: the authenticated user, the practice repository, its labels, issues,\n * comments, and files, the record of deleted comments, the counters, the seed input, the default\n * seed, and the profiles (internal; re-exported by `src/github.ts`).\n *\n * Entity shapes and the default entities follow the synthetic GitHub conformance fixtures, copied\n * as data (the same owner, repository, labels, work issue, file, user, and ids as the fixtures and\n * `githubConformanceFixtureSeeds`), never imported from SDK code. The repository id is the one the\n * paging fixture's `Link` URLs name, and the default branch is the one the contents fixture's URLs\n * name.\n *\n * Issue numbers below `nextIssueNumber` that the state does not hold are implied (the repository\n * reached them, but no fixture shows them): an answer that would render one is not emulated.\n * Numbers at or above it are not reached yet and answer the not-found fixture's 404. Created issue\n * numbers and comment ids come from counters that only advance; the default seed starts them at the\n * fixtures' created values (issue 42, comment 9000000001), and a seed's counters must lie above\n * every seeded number. Created issue `id` and `node_id` values derive from the minted number in the\n * fixtures' form (`3000000000 + number`, `I_kwSynthetic<number>`), and created comment `node_id`\n * values from the minted id (`IC_kwSynthetic<id>`); a seed may not use those minted forms at or\n * above its counters.\n *\n * Comments exist only as created here (no fixture shows a seeded comment). A deleted comment is\n * kept as a record (`deletedComments`): deleting it again answers the comment fixture's 404.\n *\n * @experimental\n */\nimport { Result } from 'effect'\nimport * as Schema from 'effect/Schema'\n\n/** A GitHub owner login (the connector's owner pattern). */\nexport const githubOwnerPattern = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/u\n\n/** A repository name in plain characters (no `.`/`..`, no `.git` suffix; checked below). */\nexport const githubRepoPattern = /^[A-Za-z0-9._-]{1,100}$/u\n\n/** A label name in plain characters (the conformance seed pattern; never percent-encoded). */\nexport const githubLabelNamePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,49}$/u\n\n/**\n * The source of a relative file path whose segments never start with a dot (the conformance seed\n * pattern), unanchored, so the route's raw pattern can add its length bound explicitly.\n */\nexport const githubFilePathSource = '[A-Za-z0-9_-][A-Za-z0-9._-]*(?:/[A-Za-z0-9_-][A-Za-z0-9._-]*)*'\n\n/** A relative file path whose segments never start with a dot (the conformance seed pattern). */\nexport const githubFilePathPattern = new RegExp(`^${githubFilePathSource}$`, 'u')\n\n/** A GitHub timestamp as the fixtures write it: whole seconds, UTC. */\nexport const githubTimestampPattern = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$/u\n\nconst Timestamp = Schema.String.check(Schema.isPattern(githubTimestampPattern))\n\nconst PositiveInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))\n\n/** The largest issue number the emulator addresses (ten digits, the route pattern). */\nexport const githubMaxIssueNumber = 9_999_999_999\n\nconst IssueNumber = PositiveInt.check(Schema.isLessThanOrEqualTo(githubMaxIssueNumber))\n\n/** The largest comment id the emulator addresses (fifteen digits, the delete route's pattern). */\nexport const githubMaxCommentId = 999_999_999_999_999\n\nconst CommentId = PositiveInt.check(Schema.isLessThanOrEqualTo(githubMaxCommentId))\n\nconst LabelName = Schema.String.check(Schema.isPattern(githubLabelNamePattern))\n\n/** A user as the fixtures render it (`login`, `id`, `type`, `site_admin`). */\nexport const GithubEmulatorUser = Schema.Struct({\n login: Schema.String.check(Schema.isPattern(githubOwnerPattern)),\n id: PositiveInt,\n type: Schema.String,\n siteAdmin: Schema.Boolean\n})\n\nexport type GithubEmulatorUser = typeof GithubEmulatorUser.Type\n\n/** The practice repository: its owner and name, its numeric id, and its default branch. */\nexport const GithubEmulatorRepository = Schema.Struct({\n owner: Schema.String.check(Schema.isPattern(githubOwnerPattern)),\n repo: Schema.String.check(\n Schema.isPattern(githubRepoPattern),\n Schema.makeFilter(\n (repo: string) =>\n (repo !== '.' && repo !== '..' && !repo.endsWith('.git')) ||\n 'a repository name is not . or .. and does not end in .git'\n )\n ),\n /** The id the `Link` URLs name (`/repositories/<id>/labels`). */\n id: PositiveInt,\n defaultBranch: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9._-]{1,100}$/u))\n})\n\nexport type GithubEmulatorRepository = typeof GithubEmulatorRepository.Type\n\n/** A repository label. */\nexport const GithubEmulatorLabel = Schema.Struct({\n id: PositiveInt,\n nodeId: Schema.String,\n name: LabelName,\n /** Six hex digits, as the fixtures write colors. */\n color: Schema.String.check(Schema.isPattern(/^[0-9a-f]{6}$/u)),\n default: Schema.Boolean,\n description: Schema.NullOr(Schema.String)\n})\n\nexport type GithubEmulatorLabel = typeof GithubEmulatorLabel.Type\n\n/** A seeded issue (its labels by name; never a pull request, never locked). */\nexport const GithubEmulatorSeedIssue = Schema.Struct({\n number: IssueNumber,\n id: PositiveInt,\n nodeId: Schema.String,\n title: Schema.String.check(Schema.isMinLength(1)),\n body: Schema.NullOr(Schema.String),\n state: Schema.Literals(['open', 'closed']),\n stateReason: Schema.NullOr(Schema.String),\n labels: Schema.Array(LabelName),\n user: GithubEmulatorUser,\n authorAssociation: Schema.String,\n createdAt: Timestamp,\n updatedAt: Timestamp,\n closedAt: Schema.NullOr(Timestamp)\n})\n\nexport type GithubEmulatorSeedIssue = typeof GithubEmulatorSeedIssue.Type\n\n/** A stored issue: a seeded one, or one created through the recorded create flow. */\nexport const GithubEmulatorIssue = Schema.Struct({\n ...GithubEmulatorSeedIssue.fields,\n /** Created here (only such issues are renamed or closed). */\n createdHere: Schema.Boolean\n})\n\nexport type GithubEmulatorIssue = typeof GithubEmulatorIssue.Type\n\n/** A comment created here on an issue. */\nexport const GithubEmulatorComment = Schema.Struct({\n id: CommentId,\n issueNumber: IssueNumber,\n body: Schema.String,\n user: GithubEmulatorUser,\n authorAssociation: Schema.String,\n createdAt: Timestamp,\n updatedAt: Timestamp\n})\n\nexport type GithubEmulatorComment = typeof GithubEmulatorComment.Type\n\n/** A UTF-8 text file in the default branch. */\nexport const GithubEmulatorFile = Schema.Struct({\n path: Schema.String.check(Schema.isPattern(githubFilePathPattern), Schema.isMaxLength(200)),\n /** The blob sha (40 lower-case hex digits). */\n sha: Schema.String.check(Schema.isPattern(/^[0-9a-f]{40}$/u)),\n text: Schema.String\n})\n\nexport type GithubEmulatorFile = typeof GithubEmulatorFile.Type\n\nconst Counters = Schema.Struct({\n /** The number the next created issue takes (one past the maximum when exhausted). */\n nextIssueNumber: PositiveInt.check(Schema.isLessThanOrEqualTo(githubMaxIssueNumber + 1)),\n /** The id the next created comment takes (one past the maximum when exhausted). */\n nextCommentId: PositiveInt.check(Schema.isLessThanOrEqualTo(githubMaxCommentId + 1))\n})\n\n/** The whole emulator state (JSON-compatible; what `snapshot()` returns). */\nexport const GithubEmulatorStateSchema = Schema.Struct({\n /** The authenticated user: the author of everything created here. */\n viewer: GithubEmulatorUser,\n repository: GithubEmulatorRepository,\n labels: Schema.Array(GithubEmulatorLabel),\n issues: Schema.Array(GithubEmulatorIssue),\n comments: Schema.Array(GithubEmulatorComment),\n /** Ids of comments deleted here (a second delete answers the recorded 404). */\n deletedComments: Schema.Array(CommentId),\n files: Schema.Array(GithubEmulatorFile),\n counters: Counters\n})\n\n/**\n * The emulator state. The container is mutable (routes replace whole lists); every entity is\n * replaced, never edited in place.\n */\nexport type GithubEmulatorState = {\n viewer: GithubEmulatorUser\n repository: GithubEmulatorRepository\n labels: ReadonlyArray<GithubEmulatorLabel>\n issues: ReadonlyArray<GithubEmulatorIssue>\n comments: ReadonlyArray<GithubEmulatorComment>\n deletedComments: ReadonlyArray<number>\n files: ReadonlyArray<GithubEmulatorFile>\n counters: typeof Counters.Type\n}\n\n/** Account-variance profiles for the default seed. */\nexport const GithubEmulatorProfile = Schema.Literals(['default', 'empty'])\n\nexport type GithubEmulatorProfile = typeof GithubEmulatorProfile.Type\n\n/**\n * A typed seed. Start from `profile` (default `'default'`, the fixture entities); every other key,\n * when given, replaces that part of the profile. Counters default to the profile's, raised above\n * the highest seeded issue number; a counter given at or below a seeded value is invalid.\n */\nexport const GithubEmulatorSeed = Schema.Struct({\n profile: Schema.optionalKey(GithubEmulatorProfile),\n viewer: Schema.optionalKey(GithubEmulatorUser),\n repository: Schema.optionalKey(GithubEmulatorRepository),\n labels: Schema.optionalKey(Schema.Array(GithubEmulatorLabel)),\n issues: Schema.optionalKey(Schema.Array(GithubEmulatorSeedIssue)),\n files: Schema.optionalKey(Schema.Array(GithubEmulatorFile)),\n nextIssueNumber: Schema.optionalKey(IssueNumber),\n nextCommentId: Schema.optionalKey(CommentId)\n})\n\nexport type GithubEmulatorSeed = typeof GithubEmulatorSeed.Type\n\nconst strict = { onExcessProperty: 'error' } as const\n\nconst decodeSeedInput = Schema.decodeUnknownResult(GithubEmulatorSeed, strict)\n\nconst decodeStateInput = Schema.decodeUnknownResult(GithubEmulatorStateSchema, strict)\n\nconst issueMessage = (issue: Schema.SchemaError['issue']): string =>\n new Schema.SchemaError(issue).message\n\n/** Minted issue `id` values: `3000000000 + number`, as the fixtures write them. */\nexport const mintedIssueIdBase = 3_000_000_000\n\nexport const mintedIssueNodeId = (number: number): string => `I_kwSynthetic${number}`\n\nexport const mintedCommentNodeId = (id: number): string => `IC_kwSynthetic${id}`\n\n// Default entities, copied from the fixtures: the user, the practice repository (the paging\n// fixture's repository id, the contents fixture's branch), the five labels of the paging fixture,\n// the work issue of the label fixture, and the text file of the contents fixture.\n\nconst seededAt = '2026-09-30T12:00:00Z'\n\nconst defaultViewer: GithubEmulatorUser = {\n login: 'yolk-synthetic-bot',\n id: 1000001,\n type: 'User',\n siteAdmin: false\n}\n\nconst defaultRepository: GithubEmulatorRepository = {\n owner: 'yolk-synthetic',\n repo: 'conformance-practice',\n id: 100000001,\n defaultBranch: 'main'\n}\n\nconst label = (id: number, name: string, color: string): GithubEmulatorLabel => ({\n id,\n nodeId: `LA_kwSynthetic${id}`,\n name,\n color,\n default: false,\n description: `Synthetic ${name} label`\n})\n\nconst defaultLabels: ReadonlyArray<GithubEmulatorLabel> = [\n label(700000001, 'bug', 'd73a4a'),\n label(700000002, 'documentation', '0075ca'),\n label(700000003, 'enhancement', 'a2eeef'),\n label(700000004, 'question', 'd876e3'),\n label(700000005, 'synthetic-conformance', 'ededed')\n]\n\nconst workIssue: GithubEmulatorSeedIssue = {\n number: 1,\n id: mintedIssueIdBase + 1,\n nodeId: mintedIssueNodeId(1),\n title: 'Synthetic work issue for conformance runs',\n body: 'Synthetic work issue: conformance cases add and remove a label and a comment here.',\n state: 'open',\n stateReason: null,\n labels: ['bug'],\n user: defaultViewer,\n authorAssociation: 'OWNER',\n createdAt: seededAt,\n updatedAt: seededAt,\n closedAt: null\n}\n\nconst notesFile: GithubEmulatorFile = {\n path: 'docs/synthetic-notes.txt',\n sha: '5f1c0ffee5f1c0ffee5f1c0ffee5f1c0ffee0001',\n text:\n 'Synthetic conformance notes for the practice repository: café, naïve, façade.\\n' +\n 'Second synthetic line.\\n'\n}\n\ntype ProfileParts = {\n readonly viewer: GithubEmulatorUser\n readonly repository: GithubEmulatorRepository\n readonly labels: ReadonlyArray<GithubEmulatorLabel>\n readonly issues: ReadonlyArray<GithubEmulatorSeedIssue>\n readonly files: ReadonlyArray<GithubEmulatorFile>\n readonly counters: typeof Counters.Type\n}\n\nconst profileParts = (profile: GithubEmulatorProfile): ProfileParts =>\n profile === 'default'\n ? {\n viewer: defaultViewer,\n repository: defaultRepository,\n labels: defaultLabels,\n issues: [workIssue],\n files: [notesFile],\n // The lifecycle fixture's created issue and the comment fixture's created comment.\n counters: { nextIssueNumber: 42, nextCommentId: 9000000001 }\n }\n : {\n viewer: defaultViewer,\n repository: defaultRepository,\n labels: [],\n issues: [],\n files: [],\n counters: { nextIssueNumber: 1, nextCommentId: 1 }\n }\n\nconst duplicate = <A>(values: ReadonlyArray<A>): A | undefined =>\n values.find((value, index) => values.indexOf(value) !== index)\n\n/** Integrity problems a decoded seed can still have (duplicates, dangling or minted values). */\nconst seedProblem = (parts: ProfileParts): string | undefined => {\n const duplicates: ReadonlyArray<readonly [string, unknown]> = [\n ['label name', duplicate(parts.labels.map(entry => entry.name))],\n ['label id', duplicate(parts.labels.map(entry => entry.id))],\n ['issue number', duplicate(parts.issues.map(issue => issue.number))],\n ['issue id', duplicate(parts.issues.map(issue => issue.id))],\n // Node ids are global across types (labels and issues alike).\n [\n 'node id',\n duplicate([...parts.labels.map(entry => entry.nodeId), ...parts.issues.map(i => i.nodeId)])\n ],\n ['file path', duplicate(parts.files.map(file => file.path))]\n ]\n\n for (const [kind, value] of duplicates) {\n if (value !== undefined) return `duplicate ${kind} ${String(value)}`\n }\n\n const labelNames = new Set(parts.labels.map(entry => entry.name))\n\n for (const issue of parts.issues) {\n const missing = issue.labels.find(name => !labelNames.has(name))\n\n if (missing !== undefined) return `issue ${issue.number} names missing label ${missing}`\n\n if (duplicate(issue.labels) !== undefined) return `issue ${issue.number} repeats a label`\n\n if (issue.number >= parts.counters.nextIssueNumber) {\n return `nextIssueNumber must lie above seeded issue ${issue.number}`\n }\n\n // Minted ids never collide with seeded ones.\n if (issue.id >= mintedIssueIdBase + parts.counters.nextIssueNumber) {\n return `issue ${issue.number} uses an id in the minted form at or above nextIssueNumber`\n }\n }\n\n // Every minted node id form is reserved across all seeded node ids, of issues and labels alike.\n const reserved = [...parts.labels.map(entry => entry.nodeId), ...parts.issues.map(i => i.nodeId)]\n .map(nodeId => {\n const issueNumber = /^I_kwSynthetic(\\d+)$/.exec(nodeId)?.[1]\n const commentId = /^IC_kwSynthetic(\\d+)$/.exec(nodeId)?.[1]\n\n return (issueNumber !== undefined && Number(issueNumber) >= parts.counters.nextIssueNumber) ||\n (commentId !== undefined && Number(commentId) >= parts.counters.nextCommentId)\n ? nodeId\n : undefined\n })\n .find(nodeId => nodeId !== undefined)\n\n if (reserved !== undefined) {\n return `node id ${reserved} uses a minted form at or above its counter`\n }\n\n const prefix = parts.files.find(file =>\n parts.files.some(other => other.path.startsWith(`${file.path}/`))\n )\n\n return prefix === undefined ? undefined : `file ${prefix.path} is also a folder`\n}\n\n/** Build the emulator state for a decoded seed; a string is an integrity problem. */\nconst stateFromSeed = (seed: GithubEmulatorSeed): GithubEmulatorState | string => {\n const profile = profileParts(seed.profile ?? 'default')\n const issues = seed.issues ?? profile.issues\n const highest = Math.max(0, ...issues.map(issue => issue.number))\n\n const parts: ProfileParts = {\n viewer: seed.viewer ?? profile.viewer,\n repository: seed.repository ?? profile.repository,\n labels: seed.labels ?? profile.labels,\n issues,\n files: seed.files ?? profile.files,\n counters: {\n // Raised above the seeded numbers unless the seed names the counter itself (then checked).\n nextIssueNumber:\n seed.nextIssueNumber ?? Math.max(profile.counters.nextIssueNumber, highest + 1),\n nextCommentId: seed.nextCommentId ?? profile.counters.nextCommentId\n }\n }\n\n const problem = seedProblem(parts)\n\n return (\n problem ?? {\n viewer: parts.viewer,\n repository: parts.repository,\n labels: parts.labels,\n issues: parts.issues.map(issue => ({ ...issue, createdHere: false })),\n comments: [],\n deletedComments: [],\n files: parts.files,\n counters: parts.counters\n }\n )\n}\n\n/** Decode and build a seed; a string is the reason it is invalid. */\nexport const buildSeedState = (input: unknown): GithubEmulatorState | string => {\n const decoded = decodeSeedInput(input)\n\n return Result.isFailure(decoded)\n ? issueMessage(decoded.failure.issue)\n : stateFromSeed(decoded.success)\n}\n\n/** Decode a full state (a restored snapshot); a string is the reason it is invalid. */\nexport const decodeState = (input: unknown): GithubEmulatorState | string => {\n const decoded = decodeStateInput(input)\n\n return Result.isFailure(decoded) ? issueMessage(decoded.failure.issue) : { ...decoded.success }\n}\n"],"mappings":"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"}
@@ -31,7 +31,7 @@ import * as Schema from "effect/Schema";
31
31
  */
32
32
  const JsonObject = Schema.Record(Schema.String, Schema.Json);
33
33
  /** A Gmail message, thread, label, or attachment id as the fixtures use them. */
34
- const GmailId = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{1,100}$/));
34
+ const GmailId = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{1,100}$/u));
35
35
  const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
36
36
  /**
37
37
  * The practice account's own address: exactly one plain `local@domain` (the shape the send case's
@@ -39,7 +39,7 @@ const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
39
39
  * the event creator. A seed may set another one, but the send answers only while it is the
40
40
  * recorded `practice@example.test` (the recorded `sizeEstimate` of the sent message covers it).
41
41
  */
42
- const GoogleEmulatorPracticeAddress = Schema.String.check(Schema.isMaxLength(254), Schema.isPattern(/^[A-Za-z0-9_%+-]+(?:\.[A-Za-z0-9_%+-]+)*@[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)+$/), Schema.makeFilter((value) => value.indexOf("@") <= 64));
42
+ const GoogleEmulatorPracticeAddress = Schema.String.check(Schema.isMaxLength(254), Schema.isPattern(/^[A-Za-z0-9_%+-]+(?:\.[A-Za-z0-9_%+-]+)*@[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)+$/u), Schema.makeFilter((value) => value.indexOf("@") <= 64));
43
43
  /**
44
44
  * A stored Gmail message with the renderings a fixture records for it: `minimal` (true when a
45
45
  * fixture records `format=minimal`), and the `metadata` and `full` payloads (null when none is
@@ -98,7 +98,7 @@ const GoogleEmulatorEventBoundary = Schema.Union([Schema.Struct({
98
98
  /** A stored calendar event with its wire fields (creator and organizer derive from the state). */
99
99
  const GoogleEmulatorCalendarEvent = Schema.Struct({
100
100
  calendarId: Schema.String,
101
- id: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{1,1024}$/)),
101
+ id: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{1,1024}$/u)),
102
102
  etag: Schema.String,
103
103
  status: Schema.Literals(["confirmed", "cancelled"]),
104
104
  htmlLink: Schema.String,
@@ -113,7 +113,7 @@ const GoogleEmulatorCalendarEvent = Schema.Struct({
113
113
  });
114
114
  /** A Drive file or folder with the fields the connector's `fields` selection answers. */
115
115
  const GoogleEmulatorDriveFile = Schema.Struct({
116
- id: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{10,200}$/)),
116
+ id: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{10,200}$/u)),
117
117
  name: Schema.String,
118
118
  mimeType: Schema.String,
119
119
  starred: Schema.Boolean,