@scalar/oas-utils 0.15.3 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @scalar/oas-utils
2
2
 
3
+ ## 0.17.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#9211](https://github.com/scalar/scalar/pull/9211): feat: UID-based workspaces and local-team migration
8
+
9
+ IndexedDB v2 migrates existing data into the new shape, collapses all workspaces into the local team (aligned with a single team workspace on the client for now), resolves slug collisions deterministically, re-keys chunk stores by workspaceUid, and strips x-scalar-tabs and x-scalar-active-tab from meta chunks so routing does not follow stale paths after migration or slug changes.
10
+
11
+ - [#9211](https://github.com/scalar/scalar/pull/9211): feat: make `WorkspaceDocument` an union of OpenApiDocument and AsyncApiDocument
12
+
13
+ ### Patch Changes
14
+
15
+ - [#9211](https://github.com/scalar/scalar/pull/9211): refactor(oas-utils): drop local `migrations/semver` and use `isVersionLessThan` from `@scalar/helpers` in the workspace migrator. The previous `semverLessThan` export is removed from `@scalar/oas-utils/migrations`; import from `@scalar/helpers/general/compare-versions` instead.
16
+ - [#9211](https://github.com/scalar/scalar/pull/9211): feat: add more analytics events
17
+
18
+ ## 0.16.0
19
+
20
+ ### Minor Changes
21
+
22
+ - [#9195](https://github.com/scalar/scalar/pull/9195): feat: UID-based workspaces and local-team migration
23
+
24
+ IndexedDB v2 migrates existing data into the new shape, collapses all workspaces into the local team (aligned with a single team workspace on the client for now), resolves slug collisions deterministically, re-keys chunk stores by workspaceUid, and strips x-scalar-tabs and x-scalar-active-tab from meta chunks so routing does not follow stale paths after migration or slug changes.
25
+
26
+ - [#9018](https://github.com/scalar/scalar/pull/9018): feat: make `WorkspaceDocument` an union of OpenApiDocument and AsyncApiDocument
27
+
28
+ ### Patch Changes
29
+
30
+ - [#9063](https://github.com/scalar/scalar/pull/9063): refactor(oas-utils): drop local `migrations/semver` and use `isVersionLessThan` from `@scalar/helpers` in the workspace migrator. The previous `semverLessThan` export is removed from `@scalar/oas-utils/migrations`; import from `@scalar/helpers/general/compare-versions` instead.
31
+ - [#9125](https://github.com/scalar/scalar/pull/9125): feat: add more analytics events
32
+
3
33
  ## 0.15.3
4
34
 
5
35
  ## 0.15.2
@@ -1,4 +1,4 @@
1
- import type { ApiReferenceEvents } from '@scalar/workspace-store/events';
1
+ import type { AnyEventListener, ApiReferenceEvents, WorkspaceEventBus } from '@scalar/workspace-store/events';
2
2
  import type { RequestFactory, VariablesStore } from '@scalar/workspace-store/request-example';
3
3
  import type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document';
4
4
  import type { OperationObject } from '@scalar/workspace-store/schemas/v3.1/strict/operation';
@@ -113,13 +113,49 @@ export type ClientPlugin = {
113
113
  components?: Partial<ClientPluginComponents>;
114
114
  /** Lifecycle hooks for app-level concerns */
115
115
  lifecycle?: ClientPluginLifecycle;
116
- /** Subscribe to event bus events. The framework handles subscribe/unsubscribe automatically. */
117
- on?: Partial<{
118
- [K in keyof ApiReferenceEvents]: (payload: ApiReferenceEvents[K]) => void;
119
- }>;
116
+ /**
117
+ * Subscribe to every event on the bus. The framework wires this up to
118
+ * `bus.onAny` and handles subscribe/unsubscribe automatically.
119
+ *
120
+ * The listener receives a single tagged-union argument `{ event, payload }`
121
+ * where `event` is the discriminant. Narrowing on `event` automatically
122
+ * narrows `payload` to the exact type for that event — no casts, no `as`
123
+ * assertions, and no manual runtime type checks just to satisfy the
124
+ * compiler. Destructuring in the parameter list works too.
125
+ *
126
+ * @example
127
+ * on: ({ event, payload }) => {
128
+ * if (event === 'log:user-login') {
129
+ * // payload is narrowed to { uid: string; email?: string; teamUid: string }
130
+ * posthog.identify(payload.uid, { email: payload.email })
131
+ * }
132
+ *
133
+ * if (event === 'operation:create:operation') {
134
+ * // payload is narrowed to the operation-create payload
135
+ * analytics.track('operation_created', payload)
136
+ * }
137
+ * }
138
+ */
139
+ on?: AnyEventListener;
120
140
  /** Custom response body handlers for specific content types */
121
141
  responseBody?: ResponseBodyHandler[];
122
142
  };
143
+ /**
144
+ * Subscribes a single plugin's `on` listener to the given event bus via `onAny`.
145
+ *
146
+ * The plugin's `on` is passed straight through to `bus.onAny`, so it will
147
+ * receive every event emitted on the bus as a `{ event, payload }` object.
148
+ * Plugins without an `on` listener get a no-op unsubscribe.
149
+ *
150
+ * Returns an unsubscribe function. Call it when the plugin is torn down or
151
+ * the bus is destroyed to remove the wildcard listener.
152
+ *
153
+ * @example
154
+ * const unsubscribe = subscribePluginEvents(eventBus, plugin)
155
+ * // later...
156
+ * unsubscribe()
157
+ */
158
+ export declare const subscribePluginEvents: (eventBus: WorkspaceEventBus, plugin: ClientPlugin) => (() => void);
123
159
  /**
124
160
  * Maps hook names to their expected payload types.
125
161
  * This ensures type safety when executing hooks with their corresponding payloads.
@@ -1 +1 @@
1
- {"version":3,"file":"client-plugins.d.ts","sourceRoot":"","sources":["../../src/helpers/client-plugins.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client-plugins.d.ts","sourceRoot":"","sources":["../../src/helpers/client-plugins.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,26 @@
1
+ /**
2
+ * Subscribes a single plugin's `on` listener to the given event bus via `onAny`.
3
+ *
4
+ * The plugin's `on` is passed straight through to `bus.onAny`, so it will
5
+ * receive every event emitted on the bus as a `{ event, payload }` object.
6
+ * Plugins without an `on` listener get a no-op unsubscribe.
7
+ *
8
+ * Returns an unsubscribe function. Call it when the plugin is torn down or
9
+ * the bus is destroyed to remove the wildcard listener.
10
+ *
11
+ * @example
12
+ * const unsubscribe = subscribePluginEvents(eventBus, plugin)
13
+ * // later...
14
+ * unsubscribe()
15
+ */
16
+ export const subscribePluginEvents = (eventBus, plugin) => {
17
+ if (!plugin.on) {
18
+ return () => {
19
+ // no-op
20
+ };
21
+ }
22
+ return eventBus.onAny(plugin.on);
23
+ };
1
24
  /**
2
25
  * Execute any hook with type-safe payload handling.
3
26
  * The payload type is inferred from the hook name to ensure correct usage.
@@ -1,3 +1,3 @@
1
- export { type ClientPlugin, type ResponseBodyHandler, executeHook } from './client-plugins.js';
1
+ export { type ClientPlugin, type ResponseBodyHandler, executeHook, subscribePluginEvents } from './client-plugins.js';
2
2
  export { formatJsonOrYamlString, json, parseJsonOrYaml, transformToJson, yaml } from './parse.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC3F,OAAO,EAAE,sBAAsB,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAClH,OAAO,EAAE,sBAAsB,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA"}
@@ -1,2 +1,2 @@
1
- export { executeHook } from './client-plugins.js';
1
+ export { executeHook, subscribePluginEvents } from './client-plugins.js';
2
2
  export { formatJsonOrYamlString, json, parseJsonOrYaml, transformToJson, yaml } from './parse.js';
@@ -1,5 +1,4 @@
1
1
  export { DATA_VERSION, DATA_VERSION_LS_LEY } from './data-version.js';
2
2
  export { migrateLocalStorageToIndexDb, shouldMigrateToIndexDb, transformLegacyDataToWorkspace, } from './migrate-to-indexdb.js';
3
3
  export { migrator } from './migrator.js';
4
- export { semverLessThan } from './semver.js';
5
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA"}
@@ -1,4 +1,3 @@
1
1
  export { DATA_VERSION, DATA_VERSION_LS_LEY } from './data-version.js';
2
2
  export { migrateLocalStorageToIndexDb, shouldMigrateToIndexDb, transformLegacyDataToWorkspace, } from './migrate-to-indexdb.js';
3
3
  export { migrator } from './migrator.js';
4
- export { semverLessThan } from './semver.js';
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-to-indexdb.d.ts","sourceRoot":"","sources":["../../src/migrations/migrate-to-indexdb.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,+BAA+B,EAAE,MAAM,qCAAqC,CAAA;AAOrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oDAAoD,CAAA;AAgB3F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAOnE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,qBA6CxC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GACjC,sBAAsB,OAAO,CAAC,UAAU,CAAC,OAAO,+BAA+B,CAAC,CAAC,CAAC,WAAW,CAAC,KAC7F,OAAO,CAAC,OAAO,CAiBjB,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,GAAU,YAAY;IAC/D,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;CAC/B;;;;IA8IA,CAAA"}
1
+ {"version":3,"file":"migrate-to-indexdb.d.ts","sourceRoot":"","sources":["../../src/migrations/migrate-to-indexdb.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,+BAA+B,EAAwB,MAAM,qCAAqC,CAAA;AAO3G,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oDAAoD,CAAA;AAiB3F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAOnE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,qBAuDxC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GACjC,sBAAsB,OAAO,CAAC,UAAU,CAAC,OAAO,+BAA+B,CAAC,CAAC,CAAC,WAAW,CAAC,KAC7F,OAAO,CAAC,OAAO,CAiBjB,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,GAAU,YAAY;IAC/D,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;CAC/B;;;;IAgJA,CAAA"}
@@ -8,9 +8,10 @@ import { extractServerFromPath } from '@scalar/helpers/url/extract-server-from-p
8
8
  import { presets } from '@scalar/themes';
9
9
  import { createWorkspaceStore } from '@scalar/workspace-store/client';
10
10
  import { AuthSchema } from '@scalar/workspace-store/entities/auth';
11
- import { createWorkspaceStorePersistence } from '@scalar/workspace-store/persistence';
11
+ import { createWorkspaceStorePersistence, generateWorkspaceUid } from '@scalar/workspace-store/persistence';
12
12
  import { xScalarEnvironmentSchema, } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments';
13
13
  import { xScalarCookieSchema } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies';
14
+ import { isOpenApiDocument } from '@scalar/workspace-store/schemas/type-guards';
14
15
  import { coerceValue } from '@scalar/workspace-store/schemas/typebox-coerce';
15
16
  import { ColorModeSchema } from '@scalar/workspace-store/schemas/workspace';
16
17
  import { migrator } from '../migrations/migrator.js';
@@ -45,8 +46,18 @@ export const migrateLocalStorageToIndexDb = async () => {
45
46
  // Step 2: Transform to new workspace structure
46
47
  const workspaces = await transformLegacyDataToWorkspace(legacyData);
47
48
  const limit = createLimiter(MAX_CONCURRENT_DB_WRITES);
48
- // Step 3: Save to IndexedDB
49
- await Promise.all(workspaces.map((workspace) => limit(() => workspacePersistence.setItem({ teamSlug: 'local', slug: workspace.slug }, {
49
+ // Step 3: Save to IndexedDB. Every migrated workspace is keyed by a
50
+ // fresh `workspaceUid` and lands under the local team legacy
51
+ // installs predate the team concept, so there is no team membership
52
+ // to preserve. The slug from legacy data becomes the URL-facing slug
53
+ // and is unique within the local team by construction (it derives
54
+ // from the legacy workspace UID).
55
+ await Promise.all(workspaces.map((workspace) => limit(() => workspacePersistence.setItem({
56
+ workspaceUid: generateWorkspaceUid(),
57
+ teamUid: 'local',
58
+ teamSlug: 'local',
59
+ slug: workspace.slug,
60
+ }, {
50
61
  name: workspace.name,
51
62
  workspace: workspace.workspace,
52
63
  }))));
@@ -183,7 +194,9 @@ export const transformLegacyDataToWorkspace = async (legacyData) => {
183
194
  });
184
195
  }
185
196
  const drafts = store.workspace.documents[DRAFTS_DOCUMENT_NAME];
186
- if (drafts) {
197
+ // The drafts document is always OpenAPI-shaped (constructed above with `paths`); the
198
+ // guard narrows the WorkspaceDocument union so we can access `.paths` safely.
199
+ if (isOpenApiDocument(drafts)) {
187
200
  // Make sure the drafts document has a GET / route cuz that's the first route we navigate the user to
188
201
  drafts.paths ??= {};
189
202
  drafts.paths['/'] ??= {};
@@ -1 +1 @@
1
- {"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../../src/migrations/migrator.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAEnE,6CAA6C;AAC7C,eAAO,MAAM,QAAQ,QAAO;IAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;CAqDzF,CAAA"}
1
+ {"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../../src/migrations/migrator.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAEnE,6CAA6C;AAC7C,eAAO,MAAM,QAAQ,QAAO;IAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;CAqDzF,CAAA"}
@@ -1,5 +1,5 @@
1
+ import { isVersionLessThan } from '@scalar/helpers/general/compare-versions';
1
2
  import { getLocalStorageVersion, parseLocalStorage } from '../migrations/local-storage.js';
2
- import { semverLessThan } from '../migrations/semver.js';
3
3
  import { migrate_v_2_1_0 } from '../migrations/v-2.1.0/migration.js';
4
4
  import { migrate_v_2_2_0 } from '../migrations/v-2.2.0/migration.js';
5
5
  import { migrate_v_2_3_0 } from '../migrations/v-2.3.0/migration.js';
@@ -22,23 +22,23 @@ export const migrator = () => {
22
22
  workspaces: parseLocalStorage('workspace'),
23
23
  };
24
24
  // 0.0.0 -> 2.1.0 migration
25
- if (semverLessThan(dataVersion, '2.1.0')) {
25
+ if (isVersionLessThan(dataVersion, '2.1.0')) {
26
26
  data = migrate_v_2_1_0(data);
27
27
  }
28
28
  // 2.1.0 -> 2.2.0 migration
29
- if (semverLessThan(dataVersion, '2.2.0')) {
29
+ if (isVersionLessThan(dataVersion, '2.2.0')) {
30
30
  data = migrate_v_2_2_0(data);
31
31
  }
32
32
  // 2.2.0 -> 2.3.0 migration
33
- if (semverLessThan(dataVersion, '2.3.0')) {
33
+ if (isVersionLessThan(dataVersion, '2.3.0')) {
34
34
  data = migrate_v_2_3_0(data);
35
35
  }
36
36
  // 2.3.0 -> 2.4.0 migration
37
- if (semverLessThan(dataVersion, '2.4.0')) {
37
+ if (isVersionLessThan(dataVersion, '2.4.0')) {
38
38
  data = migrate_v_2_4_0(data);
39
39
  }
40
40
  // 2.4.0 -> 2.5.0 migration
41
- if (semverLessThan(dataVersion, '2.5.0')) {
41
+ if (isVersionLessThan(dataVersion, '2.5.0')) {
42
42
  data = migrate_v_2_5_0(data);
43
43
  }
44
44
  // Convert to data array
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "specification",
17
17
  "yaml"
18
18
  ],
19
- "version": "0.15.3",
19
+ "version": "0.17.0",
20
20
  "engines": {
21
21
  "node": ">=22"
22
22
  },
@@ -43,10 +43,10 @@
43
43
  "flatted": "^3.4.0",
44
44
  "vue": "^3.5.30",
45
45
  "yaml": "^2.8.3",
46
- "@scalar/helpers": "0.6.0",
47
- "@scalar/themes": "0.15.3",
48
- "@scalar/workspace-store": "0.49.3",
49
- "@scalar/types": "0.9.6"
46
+ "@scalar/helpers": "0.8.0",
47
+ "@scalar/workspace-store": "0.51.0",
48
+ "@scalar/types": "0.11.0",
49
+ "@scalar/themes": "0.15.5"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@types/node": "^24.1.0",
@@ -1,5 +0,0 @@
1
- /**
2
- * Compares semver versions and checks if the left one is less than the right
3
- */
4
- export declare const semverLessThan: (left: string, right: string) => boolean;
5
- //# sourceMappingURL=semver.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"semver.d.ts","sourceRoot":"","sources":["../../src/migrations/semver.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,OAyB5D,CAAA"}
@@ -1,25 +0,0 @@
1
- /**
2
- * Compares semver versions and checks if the left one is less than the right
3
- */
4
- export const semverLessThan = (left, right) => {
5
- // Parse the strings into numbers
6
- const parseSemver = (version) => {
7
- const [major = 0, minor = 0, patch = 0] = version.split('.').map((part) => Number.parseInt(part, 10));
8
- return { major, minor, patch };
9
- };
10
- const { major: major1, minor: minor1, patch: patch1 } = parseSemver(left);
11
- const { major: major2, minor: minor2, patch: patch2 } = parseSemver(right);
12
- if (major1 < major2) {
13
- return true;
14
- }
15
- if (major1 > major2) {
16
- return false;
17
- }
18
- if (minor1 < minor2) {
19
- return true;
20
- }
21
- if (minor1 > minor2) {
22
- return false;
23
- }
24
- return patch1 < patch2;
25
- };