@doubling/types 0.1.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/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # @doubling/types
2
+
3
+ Shared TypeScript interfaces and pure helpers consumed by `web/` and `sync/`. Single source of truth for Firestore document shapes (file/folder entities, org membership, teams, user profiles), file-extension to MIME mappings, and storage-path helpers.
4
+
5
+ Lives at the repo root as an npm workspace (`@doubling/types`). The compiled output is shipped at `dist/`, regenerated on `npm install` via the `prepare` script and rebuilt explicitly via `npm run build`.
6
+
7
+ ## Why this exists
8
+
9
+ Before this package, `web/` and `sync/` each kept their own copy of:
10
+
11
+ - File / folder document shapes (web as a TS interface, sync via JSDoc).
12
+ - The `EXT_TO_MIME` table mapping extensions to MIME types.
13
+ - `mimeTypeFromExt`, `isTextMimeType`, `extFromPath`, `storagePathFor`.
14
+
15
+ The duplication was load-bearing for shipping (web and sync run in different environments and the bytes / hash helpers are necessarily environment-specific), but the static parts drifted. New text extensions that landed on one side and not the other caused the daemon to upload with `application/octet-stream` while the web's eager-load path skipped the file because the mime didn't match. Adding `@doubling/types` collapses both copies for the static parts and leaves the env-specific bytes / hash helpers in each consumer.
16
+
17
+ ## Layout
18
+
19
+ - `src/firestore.ts`: `FileEntity`, `FolderEntity`, `Entity`, `OrgMembership`, `OrgMember`, `Team`, `TeamMember`, `UserProfile`, `Scope`.
20
+ - `src/mime.ts`: `EXT_TO_MIME`, `mimeTypeFromExt`, `isTextMimeType`.
21
+ - `src/paths.ts`: `extFromPath`, `storagePathFor`.
22
+ - `src/index.ts`: barrel export.
23
+
24
+ ## Adding a new extension
25
+
26
+ Edit `EXT_TO_MIME` in `src/mime.ts`. That's it. Both `web/` and `sync/` pick up the new entry on the next `tsc` build. No need to touch any other file.
27
+
28
+ ## Build
29
+
30
+ ```
31
+ npm run -w types build
32
+ ```
33
+
34
+ Emits `dist/index.js` plus `dist/*.d.ts`. The `dist/` directory is gitignored; CI runs the build automatically via the `prepare` script on `npm install`.
@@ -0,0 +1,59 @@
1
+ export type Scope = 'team' | 'private';
2
+ interface EntityBase {
3
+ id: string;
4
+ path?: string;
5
+ name?: string;
6
+ parentId?: string | null;
7
+ scope?: Scope | string;
8
+ teamId?: string | null;
9
+ ownerId?: string | null;
10
+ sharedWith?: string[];
11
+ createdAt?: number | string;
12
+ updatedAt?: number | string;
13
+ }
14
+ export interface FileEntity extends EntityBase {
15
+ type?: 'file';
16
+ mimeType?: string;
17
+ size?: number;
18
+ contentHash?: string;
19
+ storagePath?: string;
20
+ content?: string | null;
21
+ frontmatter?: unknown;
22
+ }
23
+ export interface FolderEntity extends EntityBase {
24
+ type: 'folder';
25
+ }
26
+ export type Entity = FileEntity | FolderEntity;
27
+ export interface OrgMembership {
28
+ orgId: string;
29
+ orgName: string;
30
+ role: string;
31
+ memberId: string;
32
+ }
33
+ export interface OrgMember {
34
+ id: string;
35
+ orgId?: string;
36
+ userId?: string;
37
+ email?: string;
38
+ role?: string;
39
+ orgName?: string;
40
+ }
41
+ export interface Team {
42
+ id: string;
43
+ name?: string;
44
+ isDefault?: boolean;
45
+ createdBy?: string;
46
+ createdAt?: string;
47
+ }
48
+ export interface TeamMember {
49
+ id: string;
50
+ teamId?: string;
51
+ userId?: string;
52
+ email?: string;
53
+ role?: string;
54
+ }
55
+ export interface UserProfile {
56
+ orgCount?: number;
57
+ }
58
+ export {};
59
+ //# sourceMappingURL=firestore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firestore.d.ts","sourceRoot":"","sources":["../src/firestore.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAKvC,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7B;AASD,MAAM,WAAW,UAAW,SAAQ,UAAU;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAGD,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,IAAI,EAAE,QAAQ,CAAC;CAChB;AAID,MAAM,MAAM,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;AAM/C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,16 @@
1
+ // Firestore document interfaces shared between web/ and sync/.
2
+ //
3
+ // These shapes are the contract for what each collection stores. Both
4
+ // readers (web's loadFiles, sync's onSnapshot listeners) and writers
5
+ // (web's createNewFile, sync's pushFileToCloud) import these so a
6
+ // schema change can never silently diverge between the two halves of
7
+ // the system.
8
+ //
9
+ // Field optionality reflects on-disk reality:
10
+ // - id is always present (it's the doc id, not a field).
11
+ // - Fields written by both web and sync are required.
12
+ // - Fields written by one side only or only on certain entity types
13
+ // are optional (e.g., ownerId is null on team files, parentId is
14
+ // null at the root).
15
+ export {};
16
+ //# sourceMappingURL=firestore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firestore.js","sourceRoot":"","sources":["../src/firestore.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,sEAAsE;AACtE,qEAAqE;AACrE,kEAAkE;AAClE,qEAAqE;AACrE,cAAc;AACd,EAAE;AACF,8CAA8C;AAC9C,2DAA2D;AAC3D,wDAAwD;AACxD,sEAAsE;AACtE,qEAAqE;AACrE,yBAAyB"}
@@ -0,0 +1,4 @@
1
+ export * from './firestore.js';
2
+ export * from './mime.js';
3
+ export * from './paths.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ // Public entry. Consumers import everything via `@doubling/types`.
2
+ //
3
+ // NodeNext module resolution requires the `.js` extension on
4
+ // relative imports in TypeScript source, even though the actual file
5
+ // on disk is `.ts`. tsc and Node's ESM loader rewrite to the
6
+ // compiled `.js` at build / runtime.
7
+ export * from './firestore.js';
8
+ export * from './mime.js';
9
+ export * from './paths.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,EAAE;AACF,6DAA6D;AAC7D,qEAAqE;AACrE,6DAA6D;AAC7D,qCAAqC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
package/dist/mime.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare const EXT_TO_MIME: Record<string, string>;
2
+ export declare function mimeTypeFromExt(ext: string | null | undefined): string;
3
+ export declare function isTextMimeType(mimeType: string | null | undefined): boolean;
4
+ //# sourceMappingURL=mime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mime.d.ts","sourceRoot":"","sources":["../src/mime.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA0C9C,CAAC;AAEF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGtE;AASD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG3E"}
package/dist/mime.js ADDED
@@ -0,0 +1,73 @@
1
+ // Single source of truth for file-extension to MIME-type mapping.
2
+ //
3
+ // Previously duplicated in `web/src/storage-helpers.ts` and
4
+ // `sync/storage-helpers.js`. The duplication had bitten us multiple
5
+ // times: a new text extension added on one side but not the other
6
+ // caused the daemon to upload with `application/octet-stream`, and
7
+ // the web's eager-load path then skipped the file because it didn't
8
+ // recognise the type. DOU-182 collapses both copies to this module.
9
+ //
10
+ // To add a new extension: edit the `EXT_TO_MIME` table here and
11
+ // (where the extension is text) verify `isTextMimeType` returns
12
+ // true for the resulting mime. No other file needs to change.
13
+ export const EXT_TO_MIME = {
14
+ md: 'text/markdown',
15
+ markdown: 'text/markdown',
16
+ txt: 'text/plain',
17
+ csv: 'text/csv',
18
+ html: 'text/html',
19
+ htm: 'text/html',
20
+ css: 'text/css',
21
+ js: 'text/javascript',
22
+ // Obsidian Bases (.base) files are YAML. Mapped to text/yaml so
23
+ // the web's eager-load path treats them as text and the Bases
24
+ // renderer can read entity.content at page-render time.
25
+ base: 'text/yaml',
26
+ yaml: 'text/yaml',
27
+ yml: 'text/yaml',
28
+ json: 'application/json',
29
+ pdf: 'application/pdf',
30
+ png: 'image/png',
31
+ jpg: 'image/jpeg',
32
+ jpeg: 'image/jpeg',
33
+ gif: 'image/gif',
34
+ webp: 'image/webp',
35
+ svg: 'image/svg+xml',
36
+ bmp: 'image/bmp',
37
+ heic: 'image/heic',
38
+ heif: 'image/heif',
39
+ mp3: 'audio/mpeg',
40
+ wav: 'audio/wav',
41
+ mp4: 'video/mp4',
42
+ webm: 'video/webm',
43
+ mov: 'video/quicktime',
44
+ zip: 'application/zip',
45
+ // Office Open XML (modern Office). The full type strings are
46
+ // mandatory: tools that dispatch by mime (Excel, third-party
47
+ // readers) ignore alternative spellings.
48
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
49
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
50
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
51
+ // Legacy Office formats (pre-2007 binary containers).
52
+ xls: 'application/vnd.ms-excel',
53
+ doc: 'application/msword',
54
+ ppt: 'application/vnd.ms-powerpoint',
55
+ };
56
+ export function mimeTypeFromExt(ext) {
57
+ if (ext == null)
58
+ return 'application/octet-stream';
59
+ return EXT_TO_MIME[String(ext).toLowerCase()] || 'application/octet-stream';
60
+ }
61
+ // Files of these mime types are treated as inline-readable text by
62
+ // the sync daemon (read with utf-8 encoding from disk, written with
63
+ // utf-8 encoding to disk) and by web's loadFiles (eager-fetched into
64
+ // entity.content). Everything else is binary, downloaded on demand.
65
+ //
66
+ // Missing mime type is treated as text for backward compatibility
67
+ // with markdown files written before the mime type was tracked.
68
+ export function isTextMimeType(mimeType) {
69
+ if (mimeType == null || mimeType === '')
70
+ return true;
71
+ return typeof mimeType === 'string' && mimeType.startsWith('text/');
72
+ }
73
+ //# sourceMappingURL=mime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mime.js","sourceRoot":"","sources":["../src/mime.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,4DAA4D;AAC5D,oEAAoE;AACpE,kEAAkE;AAClE,mEAAmE;AACnE,oEAAoE;AACpE,oEAAoE;AACpE,EAAE;AACF,gEAAgE;AAChE,gEAAgE;AAChE,8DAA8D;AAE9D,MAAM,CAAC,MAAM,WAAW,GAA2B;IACjD,EAAE,EAAE,eAAe;IACnB,QAAQ,EAAE,eAAe;IACzB,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,UAAU;IACf,EAAE,EAAE,iBAAiB;IACrB,gEAAgE;IAChE,8DAA8D;IAC9D,wDAAwD;IACxD,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,kBAAkB;IACxB,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,eAAe;IACpB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,YAAY;IACjB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,iBAAiB;IACtB,6DAA6D;IAC7D,6DAA6D;IAC7D,yCAAyC;IACzC,IAAI,EAAE,mEAAmE;IACzE,IAAI,EAAE,yEAAyE;IAC/E,IAAI,EAAE,2EAA2E;IACjF,sDAAsD;IACtD,GAAG,EAAE,0BAA0B;IAC/B,GAAG,EAAE,oBAAoB;IACzB,GAAG,EAAE,+BAA+B;CACrC,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,GAA8B;IAC5D,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,0BAA0B,CAAC;IACnD,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,0BAA0B,CAAC;AAC9E,CAAC;AAED,mEAAmE;AACnE,oEAAoE;AACpE,qEAAqE;AACrE,oEAAoE;AACpE,EAAE;AACF,kEAAkE;AAClE,gEAAgE;AAChE,MAAM,UAAU,cAAc,CAAC,QAAmC;IAChE,IAAI,QAAQ,IAAI,IAAI,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACrD,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function extFromPath(path: string | null | undefined): string;
2
+ export declare function storagePathFor(orgId: string, fileId: string, ext: string | null | undefined): string;
3
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAWA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKnE;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEpG"}
package/dist/paths.js ADDED
@@ -0,0 +1,23 @@
1
+ // Pure path helpers, environment-agnostic. No fs, no Firebase.
2
+ //
3
+ // Lives in @doubling/types (alongside the MIME helpers) because both
4
+ // web and sync derive Cloud Storage paths and extension strings from
5
+ // these, and they must agree on the convention. The function bodies
6
+ // are intentionally simple so the two sides cannot diverge by
7
+ // accident on an edge case.
8
+ // Extract the file extension (lowercased) from a path. Returns 'bin'
9
+ // for paths with no extension or where the dot is the first or last
10
+ // character (dotfiles, trailing dots).
11
+ export function extFromPath(path) {
12
+ const name = (((path == null ? '' : path) + '').split('/').pop()) || '';
13
+ const idx = name.lastIndexOf('.');
14
+ if (idx <= 0 || idx === name.length - 1)
15
+ return 'bin';
16
+ return name.slice(idx + 1).toLowerCase();
17
+ }
18
+ // Build the canonical Cloud Storage path for a file's content blob.
19
+ // Layout: orgs/{orgId}/files/{fileId}/current.{ext}
20
+ export function storagePathFor(orgId, fileId, ext) {
21
+ return `orgs/${orgId}/files/${fileId}/current.${ext || 'bin'}`;
22
+ }
23
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,qEAAqE;AACrE,qEAAqE;AACrE,oEAAoE;AACpE,8DAA8D;AAC9D,4BAA4B;AAE5B,qEAAqE;AACrE,oEAAoE;AACpE,uCAAuC;AACvC,MAAM,UAAU,WAAW,CAAC,IAA+B;IACzD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;IACxE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AAC3C,CAAC;AAED,oEAAoE;AACpE,oDAAoD;AACpD,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,MAAc,EAAE,GAA8B;IAC1F,OAAO,QAAQ,KAAK,UAAU,MAAM,YAAY,GAAG,IAAI,KAAK,EAAE,CAAC;AACjE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@doubling/types",
3
+ "version": "0.1.0",
4
+ "description": "Shared Firestore document interfaces and MIME / path helpers consumed by web/ and sync/. Single source of truth so the two consumers can never drift on a document shape (DOU-182, TS Phase 2 of the monorepo TypeScript migration).",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist/",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "typecheck": "tsc --noEmit",
21
+ "prepare": "tsc",
22
+ "prepack": "tsc"
23
+ },
24
+ "devDependencies": {
25
+ "typescript": "^5.9.3"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/Doubling-Inc/doubling-compound.git",
30
+ "directory": "types"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/Doubling-Inc/doubling-compound/issues"
34
+ },
35
+ "homepage": "https://github.com/Doubling-Inc/doubling-compound/tree/main/types#readme",
36
+ "license": "ISC",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }