@v7-cms/adapters 0.0.0-alpha.10

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.
@@ -0,0 +1,169 @@
1
+ let shaCounter = 0;
2
+ export class FakeGitHub {
3
+ calls = [];
4
+ /** Commits made, so tests can assert on messages and ordering. */
5
+ commits = [];
6
+ branches;
7
+ options;
8
+ defaultBranch;
9
+ constructor(options = {}) {
10
+ this.options = options;
11
+ this.defaultBranch = options.branch ?? 'main';
12
+ const files = new Map();
13
+ for (const [path, text] of Object.entries(options.files ?? {})) {
14
+ files.set(path, { text, sha: nextSha() });
15
+ }
16
+ this.branches = new Map([[this.defaultBranch, files]]);
17
+ }
18
+ snapshot(branch) {
19
+ const files = this.branches.get(branch ?? this.defaultBranch) ?? new Map();
20
+ return Object.fromEntries([...files].map(([path, file]) => [path, file.text]));
21
+ }
22
+ shaOf(path, branch) {
23
+ return this.branches.get(branch ?? this.defaultBranch)?.get(path)?.sha;
24
+ }
25
+ /** Simulates someone else committing, so conflict handling can be tested. */
26
+ externalEdit(path, text, branch) {
27
+ const files = this.branches.get(branch ?? this.defaultBranch);
28
+ files.set(path, { text, sha: nextSha() });
29
+ }
30
+ branchNames() {
31
+ return [...this.branches.keys()];
32
+ }
33
+ /** The fetch implementation to hand the adapter. */
34
+ fetch = async (input, init = {}) => {
35
+ const url = new URL(typeof input === 'string' ? input : input.toString());
36
+ const method = init.method ?? 'GET';
37
+ const path = decodeURIComponent(url.pathname.replace(/^\/repos\/[^/]+\/[^/]+/, ''));
38
+ let body;
39
+ if (typeof init.body === 'string') {
40
+ try {
41
+ body = JSON.parse(init.body);
42
+ }
43
+ catch {
44
+ body = init.body;
45
+ }
46
+ }
47
+ this.calls.push({ method, path, ...(body === undefined ? {} : { body }) });
48
+ if (this.options.failWith) {
49
+ return json({ message: this.options.failWith.message ?? 'failed' }, this.options.failWith.status);
50
+ }
51
+ if (method !== 'GET' && this.options.failWritesWith) {
52
+ return json({ message: 'write refused' }, this.options.failWritesWith);
53
+ }
54
+ // GET /repos/:owner/:repo — used by init().
55
+ if (method === 'GET' && path === '')
56
+ return json({ full_name: 'owner/repo' });
57
+ const tree = /^\/git\/trees\/([^?]+)/.exec(path);
58
+ if (method === 'GET' && tree) {
59
+ const branch = tree[1];
60
+ const files = this.branches.get(branch);
61
+ if (!files)
62
+ return json({ message: 'Not Found' }, 404);
63
+ const entries = [...files].map(([filePath, file]) => ({
64
+ path: filePath,
65
+ type: 'blob',
66
+ sha: file.sha,
67
+ size: file.text.length,
68
+ }));
69
+ return json({ tree: entries, truncated: false });
70
+ }
71
+ const contents = /^\/contents\/(.+)$/.exec(path);
72
+ if (contents && method === 'DELETE') {
73
+ const filePath = contents[1];
74
+ const payload = body;
75
+ const target = payload.branch ?? this.defaultBranch;
76
+ const targetFiles = this.branches.get(target);
77
+ if (!targetFiles)
78
+ return json({ message: 'Branch not found' }, 422);
79
+ const existing = targetFiles.get(filePath);
80
+ if (!existing)
81
+ return json({ message: 'Not Found' }, 404);
82
+ if (payload.sha !== undefined && payload.sha !== existing.sha) {
83
+ return json({ message: 'sha does not match' }, 409);
84
+ }
85
+ targetFiles.delete(filePath);
86
+ this.commits.push({ message: 'delete', path: filePath, branch: target });
87
+ return json({ commit: { sha: nextSha() } });
88
+ }
89
+ if (contents) {
90
+ const filePath = contents[1];
91
+ const ref = url.searchParams.get('ref') ?? this.defaultBranch;
92
+ const files = this.branches.get(ref) ?? this.branches.get(this.defaultBranch);
93
+ if (method === 'GET') {
94
+ const file = files.get(filePath);
95
+ if (!file)
96
+ return json({ message: 'Not Found' }, 404);
97
+ return json({
98
+ content: base64(file.binary ?? new TextEncoder().encode(file.text)),
99
+ sha: file.sha,
100
+ encoding: 'base64',
101
+ type: 'file',
102
+ });
103
+ }
104
+ const payload = body;
105
+ const target = payload.branch ?? this.defaultBranch;
106
+ const targetFiles = this.branches.get(target);
107
+ if (!targetFiles)
108
+ return json({ message: 'Branch not found' }, 422);
109
+ const existing = targetFiles.get(filePath);
110
+ // The real API refuses a stale sha; matching that is the point of the fake.
111
+ if (payload.sha !== undefined && existing && existing.sha !== payload.sha) {
112
+ return json({ message: 'sha does not match' }, 409);
113
+ }
114
+ if (payload.sha !== undefined && !existing) {
115
+ return json({ message: 'sha does not match' }, 409);
116
+ }
117
+ if (payload.sha === undefined && existing) {
118
+ // Creating over an existing file without its sha is also a conflict.
119
+ return json({ message: 'sha was not supplied' }, 422);
120
+ }
121
+ const bytes = toBytes(payload.content);
122
+ const sha = nextSha();
123
+ targetFiles.set(filePath, { text: new TextDecoder().decode(bytes), sha, binary: bytes });
124
+ this.commits.push({ message: payload.message, path: filePath, branch: target });
125
+ return json({ content: { sha }, commit: { sha: nextSha() } });
126
+ }
127
+ if (method === 'GET' && path === '/branches') {
128
+ return json([...this.branches.keys()].map((name) => ({ name })));
129
+ }
130
+ const ref = /^\/git\/ref\/heads\/(.+)$/.exec(path);
131
+ if (method === 'GET' && ref) {
132
+ const branch = ref[1];
133
+ const files = this.branches.get(branch);
134
+ if (!files)
135
+ return json({ message: 'Not Found' }, 404);
136
+ return json({ object: { sha: `commit-${branch}` } });
137
+ }
138
+ if (method === 'POST' && path === '/git/refs') {
139
+ const payload = body;
140
+ const name = payload.ref.replace('refs/heads/', '');
141
+ if (this.branches.has(name))
142
+ return json({ message: 'Reference already exists' }, 422);
143
+ const source = [...this.branches.entries()].find(([, files]) => files.size &&
144
+ `commit-${[...this.branches.keys()].find((b) => this.branches.get(b) === files)}` ===
145
+ payload.sha);
146
+ void source;
147
+ // Branches copy the default branch's contents, which is what the adapter relies on.
148
+ this.branches.set(name, new Map(this.branches.get(this.defaultBranch)));
149
+ return json({ ref: payload.ref, object: { sha: payload.sha } });
150
+ }
151
+ return json({ message: `Unhandled ${method} ${path}` }, 404);
152
+ };
153
+ }
154
+ const json = (value, status = 200) => new Response(JSON.stringify(value), {
155
+ status,
156
+ headers: { 'Content-Type': 'application/json' },
157
+ });
158
+ const nextSha = () => `sha${(shaCounter += 1).toString(16)}`;
159
+ function base64(bytes) {
160
+ let binary = '';
161
+ for (const byte of bytes)
162
+ binary += String.fromCharCode(byte);
163
+ return btoa(binary);
164
+ }
165
+ function toBytes(value) {
166
+ const binary = atob(value.replace(/\s/g, ''));
167
+ return Uint8Array.from(binary, (character) => character.charCodeAt(0));
168
+ }
169
+ //# sourceMappingURL=fake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake.js","sourceRoot":"","sources":["../../src/github/fake.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /** The shape the trees API returns, shared by the adapter and its test double. */
2
+ export interface TreeEntry {
3
+ path: string;
4
+ type: 'blob' | 'tree';
5
+ sha: string;
6
+ size?: number;
7
+ }
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/github/types.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/github/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ export * from './memory.js';
2
+ export * from './github/adapter.js';
3
+ export * from './github/auth.js';
4
+ export * from './fs-access.js';
5
+ export * from './proxy.js';
6
+ export type { StorageAdapter, MediaStore, DirEntry, FileContents, AccountInfo, } from '@v7-cms/core/storage';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAG3B,YAAY,EACV,cAAc,EACd,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,WAAW,GACZ,MAAM,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './memory.js';
2
+ export * from './github/adapter.js';
3
+ export * from './github/auth.js';
4
+ export * from './fs-access.js';
5
+ export * from './proxy.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * An in-memory backend. It exists so the editor and its tests can run a complete editing flow
3
+ * without a network or a filesystem, and it doubles as the reference implementation of the
4
+ * storage contract: every other adapter must behave the way this one does.
5
+ */
6
+ import { type DirEntry, type FileContents, type MediaStore, type StorageAdapter, type WriteOptions, type WriteResult } from '@v7-cms/core/storage';
7
+ export declare class MemoryAdapter implements StorageAdapter {
8
+ readonly kind: "memory";
9
+ private files;
10
+ private branches;
11
+ private current;
12
+ private commits;
13
+ private mediaFiles;
14
+ constructor(initial?: Record<string, string>, branch?: string);
15
+ init(): Promise<void>;
16
+ /** The files this adapter holds, for assertions in tests. */
17
+ snapshot(): Record<string, string>;
18
+ /** The commit log, so tests can assert on write messages. */
19
+ log(): Array<{
20
+ message: string;
21
+ path: string;
22
+ branch: string;
23
+ }>;
24
+ listDir(path: string): Promise<DirEntry[]>;
25
+ readFile(path: string): Promise<FileContents>;
26
+ readBinary(path: string): Promise<Uint8Array>;
27
+ exists(path: string): Promise<boolean>;
28
+ writeFile(path: string, contents: string | Uint8Array, options: WriteOptions): Promise<WriteResult>;
29
+ deleteFile(path: string, options: WriteOptions): Promise<void>;
30
+ listBranches(): Promise<string[]>;
31
+ createBranch(name: string, from: string): Promise<void>;
32
+ media(): MediaStore;
33
+ }
34
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,YAAY,EAEjB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAe9B,qBAAa,aAAc,YAAW,cAAc;IAClD,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;IAClC,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAgE;IAC/E,OAAO,CAAC,UAAU,CAA0D;gBAEhE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EAAE,MAAM,SAAS;IAQ3D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,6DAA6D;IAC7D,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIlC,6DAA6D;IAC7D,GAAG,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAIzD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAqB1C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAM7C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAM7C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItC,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,UAAU,EAC7B,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,WAAW,CAAC;IAwBjB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9D,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIjC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7D,KAAK,IAAI,UAAU;CAyBpB"}
package/dist/memory.js ADDED
@@ -0,0 +1,147 @@
1
+ /**
2
+ * An in-memory backend. It exists so the editor and its tests can run a complete editing flow
3
+ * without a network or a filesystem, and it doubles as the reference implementation of the
4
+ * storage contract: every other adapter must behave the way this one does.
5
+ */
6
+ import { ConflictError, NotFoundError, } from '@v7-cms/core/storage';
7
+ const normalise = (path) => path.replace(/^\/+/, '').replace(/\/+$/, '');
8
+ /** A stable hash stand-in: conflicts only need equality, not cryptographic strength. */
9
+ function hash(text) {
10
+ let value = 0;
11
+ for (let index = 0; index < text.length; index += 1) {
12
+ value = (value * 31 + text.charCodeAt(index)) | 0;
13
+ }
14
+ return `sha-${(value >>> 0).toString(16)}`;
15
+ }
16
+ export class MemoryAdapter {
17
+ kind = 'memory';
18
+ files;
19
+ branches;
20
+ current;
21
+ commits = [];
22
+ mediaFiles = new Map();
23
+ constructor(initial = {}, branch = 'main') {
24
+ this.files = new Map(Object.entries(initial).map(([path, text]) => [normalise(path), { text, sha: hash(text) }]));
25
+ this.current = branch;
26
+ this.branches = new Map([[branch, this.files]]);
27
+ }
28
+ async init() {
29
+ /* Nothing to set up. */
30
+ }
31
+ /** The files this adapter holds, for assertions in tests. */
32
+ snapshot() {
33
+ return Object.fromEntries([...this.files].map(([path, file]) => [path, file.text]));
34
+ }
35
+ /** The commit log, so tests can assert on write messages. */
36
+ log() {
37
+ return [...this.commits];
38
+ }
39
+ async listDir(path) {
40
+ const prefix = path ? `${normalise(path)}/` : '';
41
+ const seen = new Map();
42
+ for (const key of this.files.keys()) {
43
+ if (!key.startsWith(prefix))
44
+ continue;
45
+ const rest = key.slice(prefix.length);
46
+ const slash = rest.indexOf('/');
47
+ if (slash === -1) {
48
+ seen.set(rest, {
49
+ name: rest,
50
+ type: 'file',
51
+ sha: this.files.get(key).sha,
52
+ });
53
+ }
54
+ else {
55
+ const dir = rest.slice(0, slash);
56
+ seen.set(dir, { name: dir, type: 'dir' });
57
+ }
58
+ }
59
+ return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name));
60
+ }
61
+ async readFile(path) {
62
+ const file = this.files.get(normalise(path));
63
+ if (!file)
64
+ throw new NotFoundError(path);
65
+ return { text: file.text, sha: file.sha };
66
+ }
67
+ async readBinary(path) {
68
+ const file = this.files.get(normalise(path));
69
+ if (!file)
70
+ throw new NotFoundError(path);
71
+ return file.binary ?? new TextEncoder().encode(file.text);
72
+ }
73
+ async exists(path) {
74
+ return this.files.has(normalise(path));
75
+ }
76
+ async writeFile(path, contents, options) {
77
+ const key = normalise(path);
78
+ const existing = this.files.get(key);
79
+ if (options.sha !== undefined && existing && existing.sha !== options.sha) {
80
+ throw new ConflictError(`"${key}" changed since it was read.`);
81
+ }
82
+ if (options.sha !== undefined && !existing) {
83
+ throw new ConflictError(`"${key}" no longer exists.`);
84
+ }
85
+ const text = typeof contents === 'string' ? contents : new TextDecoder().decode(contents);
86
+ const sha = hash(text);
87
+ this.files.set(key, {
88
+ text,
89
+ sha,
90
+ ...(typeof contents === 'string' ? {} : { binary: contents }),
91
+ });
92
+ this.commits.push({
93
+ message: options.message,
94
+ path: key,
95
+ branch: this.current,
96
+ });
97
+ return { sha };
98
+ }
99
+ async deleteFile(path, options) {
100
+ const key = normalise(path);
101
+ if (!this.files.has(key))
102
+ throw new NotFoundError(path);
103
+ this.files.delete(key);
104
+ this.commits.push({
105
+ message: options.message,
106
+ path: key,
107
+ branch: this.current,
108
+ });
109
+ }
110
+ async listBranches() {
111
+ return [...this.branches.keys()];
112
+ }
113
+ async createBranch(name, from) {
114
+ const source = this.branches.get(from);
115
+ if (!source)
116
+ throw new NotFoundError(from);
117
+ if (this.branches.has(name))
118
+ return;
119
+ this.branches.set(name, new Map(source));
120
+ }
121
+ media() {
122
+ return {
123
+ upload: async (file, options) => {
124
+ const name = options.filename ?? file.name;
125
+ const path = `${normalise(options.folder)}/${name}`;
126
+ const ref = {
127
+ path,
128
+ url: `/${path}`,
129
+ size: file.data.byteLength,
130
+ name,
131
+ };
132
+ this.mediaFiles.set(path, { ref, data: file.data });
133
+ return ref;
134
+ },
135
+ list: async (folder) => {
136
+ const prefix = `${normalise(folder)}/`;
137
+ return [...this.mediaFiles.values()]
138
+ .filter((entry) => entry.ref.path.startsWith(prefix))
139
+ .map((entry) => entry.ref);
140
+ },
141
+ remove: async (path) => {
142
+ this.mediaFiles.delete(normalise(path));
143
+ },
144
+ };
145
+ }
146
+ }
147
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The proxy backend, from the editor's side.
3
+ *
4
+ * Speaks to `@v7-cms/proxy` over HTTP. It exists for browsers without the File System Access API —
5
+ * Firefox and Safari — where the author runs a small local process instead of picking a folder.
6
+ */
7
+ import { type DirEntry, type FileContents, type MediaStore, type StorageAdapter, type WriteOptions, type WriteResult } from '@v7-cms/core/storage';
8
+ export interface ProxyAdapterOptions {
9
+ /** Base URL of the proxy, e.g. `http://127.0.0.1:5177`. */
10
+ url: string;
11
+ /** Token the proxy printed when it started. */
12
+ token: string;
13
+ fetch?: typeof globalThis.fetch;
14
+ }
15
+ export declare class ProxyAdapter implements StorageAdapter {
16
+ readonly kind: "proxy";
17
+ private url;
18
+ private token;
19
+ private request;
20
+ /** Content revision per path, so a write can detect an outside change. */
21
+ private seen;
22
+ constructor(options: ProxyAdapterOptions);
23
+ init(): Promise<void>;
24
+ /** Which folder the proxy is serving, so the editor can check it is the right one. */
25
+ describe(): Promise<{
26
+ repo: string;
27
+ }>;
28
+ private call;
29
+ private action;
30
+ listDir(path: string): Promise<DirEntry[]>;
31
+ exists(path: string): Promise<boolean>;
32
+ readFile(path: string): Promise<FileContents>;
33
+ readBinary(path: string): Promise<Uint8Array>;
34
+ writeFile(path: string, contents: string | Uint8Array, _options: WriteOptions): Promise<WriteResult>;
35
+ deleteFile(path: string, _options: WriteOptions): Promise<void>;
36
+ /** A plain folder has no branches; the proxy reports one implicit branch. */
37
+ listBranches(): Promise<string[]>;
38
+ createBranch(): Promise<void>;
39
+ media(): MediaStore;
40
+ }
41
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,YAAY,EAEjB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,mBAAmB;IAClC,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAQD,qBAAa,YAAa,YAAW,cAAc;IACjD,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IACjC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAA0B;IACzC,0EAA0E;IAC1E,OAAO,CAAC,IAAI,CAA6B;gBAE7B,OAAO,EAAE,mBAAmB;IAQlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,sFAAsF;IAChF,QAAQ,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAM3C,OAAO,CAAC,IAAI;YAWE,MAAM;IAUd,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAK1C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAW7C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAa7C,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,UAAU,EAC7B,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,WAAW,CAAC;IAkBjB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrE,6EAA6E;IACvE,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIjC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC,KAAK,IAAI,UAAU;CA4BpB"}
package/dist/proxy.js ADDED
@@ -0,0 +1,159 @@
1
+ /**
2
+ * The proxy backend, from the editor's side.
3
+ *
4
+ * Speaks to `@v7-cms/proxy` over HTTP. It exists for browsers without the File System Access API —
5
+ * Firefox and Safari — where the author runs a small local process instead of picking a folder.
6
+ */
7
+ import { ConflictError, NotFoundError, } from '@v7-cms/core/storage';
8
+ export class ProxyAdapter {
9
+ kind = 'proxy';
10
+ url;
11
+ token;
12
+ request;
13
+ /** Content revision per path, so a write can detect an outside change. */
14
+ seen = new Map();
15
+ constructor(options) {
16
+ this.url = options.url.replace(/\/$/, '');
17
+ this.token = options.token;
18
+ // Detached `fetch` loses its receiver and the browser rejects it as an illegal invocation.
19
+ const base = options.fetch ?? globalThis.fetch;
20
+ this.request = base === globalThis.fetch ? base.bind(globalThis) : base;
21
+ }
22
+ async init() {
23
+ // `/api/health` is deliberately token-free so a wrong token stays diagnosable, which means it
24
+ // cannot be what verifies the token. A real call does: it fails now rather than on first save.
25
+ const response = await this.call('/api/v1', {
26
+ method: 'POST',
27
+ body: JSON.stringify({ action: 'info' }),
28
+ });
29
+ if (response.status === 401)
30
+ throw new Error('The proxy rejected the token.');
31
+ if (!response.ok)
32
+ throw new Error(`The proxy at ${this.url} did not answer.`);
33
+ }
34
+ /** Which folder the proxy is serving, so the editor can check it is the right one. */
35
+ async describe() {
36
+ const response = await this.call('/api/health');
37
+ if (!response.ok)
38
+ throw new Error(`The proxy at ${this.url} did not answer.`);
39
+ return (await response.json());
40
+ }
41
+ call(path, init = {}) {
42
+ return this.request(`${this.url}${path}`, {
43
+ ...init,
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ 'x-v7-cms-token': this.token,
47
+ ...init.headers,
48
+ },
49
+ });
50
+ }
51
+ async action(body) {
52
+ const response = await this.call('/api/v1', {
53
+ method: 'POST',
54
+ body: JSON.stringify(body),
55
+ });
56
+ const payload = (await response.json());
57
+ if (!response.ok)
58
+ throw new Error(String(payload['error'] ?? 'The proxy refused the request.'));
59
+ return payload;
60
+ }
61
+ async listDir(path) {
62
+ const result = await this.action({ action: 'listDir', path });
63
+ return result.entries;
64
+ }
65
+ async exists(path) {
66
+ const result = await this.action({ action: 'exists', path });
67
+ return result.exists;
68
+ }
69
+ async readFile(path) {
70
+ const result = await this.action({ action: 'readFile', path }).catch((error) => {
71
+ throw /Not found/.test(error.message) ? new NotFoundError(path) : error;
72
+ });
73
+ const size = result.file.size ?? 0;
74
+ this.seen.set(path, size);
75
+ return { text: result.file.text ?? '', sha: String(size) };
76
+ }
77
+ async readBinary(path) {
78
+ const result = await this.action({ action: 'readFile', path }).catch((error) => {
79
+ throw /Not found/.test(error.message) ? new NotFoundError(path) : error;
80
+ });
81
+ if (result.file.base64 === undefined) {
82
+ return new TextEncoder().encode(result.file.text ?? '');
83
+ }
84
+ const binary = atob(result.file.base64);
85
+ return Uint8Array.from(binary, (character) => character.charCodeAt(0));
86
+ }
87
+ async writeFile(path, contents, _options) {
88
+ // The proxy has no revision to check against; conflicts surface as a refused path instead.
89
+ const payload = { action: 'writeFile', path };
90
+ if (typeof contents === 'string')
91
+ payload['text'] = contents;
92
+ else
93
+ payload['base64'] = base64FromBytes(contents);
94
+ try {
95
+ const result = await this.action(payload);
96
+ this.seen.set(path, result.result.size);
97
+ return { sha: String(result.result.size) };
98
+ }
99
+ catch (error) {
100
+ const message = error.message;
101
+ // A permission failure is a conflict the author can act on, not a crash.
102
+ if (/outside the repository|escapes/.test(message))
103
+ throw new ConflictError(message);
104
+ throw error;
105
+ }
106
+ }
107
+ async deleteFile(path, _options) {
108
+ void _options;
109
+ await this.action({ action: 'deleteFile', path }).catch((error) => {
110
+ throw /Not found/.test(error.message) ? new NotFoundError(path) : error;
111
+ });
112
+ this.seen.delete(path);
113
+ }
114
+ /** A plain folder has no branches; the proxy reports one implicit branch. */
115
+ async listBranches() {
116
+ return ['local'];
117
+ }
118
+ async createBranch() {
119
+ /* Nothing to create. */
120
+ }
121
+ media() {
122
+ return {
123
+ upload: async (file, options) => {
124
+ const name = options.filename ?? file.name;
125
+ const response = await this.call('/api/media', {
126
+ method: 'POST',
127
+ body: JSON.stringify({ name, base64: base64FromBytes(file.data) }),
128
+ });
129
+ const payload = (await response.json());
130
+ if (!response.ok)
131
+ throw new Error(String(payload['error'] ?? 'Upload refused.'));
132
+ const path = String(payload['path']);
133
+ return {
134
+ path,
135
+ url: `/${path}`,
136
+ name,
137
+ size: file.data.byteLength,
138
+ };
139
+ },
140
+ list: async (folder) => {
141
+ const response = await this.call(`/api/media?folder=${encodeURIComponent(folder)}`);
142
+ const payload = (await response.json());
143
+ return payload.assets ?? [];
144
+ },
145
+ remove: async (path) => {
146
+ await this.deleteFile(path, { message: `Delete ${path}` });
147
+ },
148
+ };
149
+ }
150
+ }
151
+ function base64FromBytes(bytes) {
152
+ let binary = '';
153
+ const chunk = 0x8000;
154
+ for (let index = 0; index < bytes.length; index += chunk) {
155
+ binary += String.fromCharCode(...bytes.subarray(index, index + chunk));
156
+ }
157
+ return btoa(binary);
158
+ }
159
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,aAAa,EACb,aAAa,GAQd,MAAM,sBAAsB,CAAC;AAgB9B,MAAM,OAAO,YAAY;IACd,IAAI,GAAG,OAAgB,CAAC;IACzB,GAAG,CAAS;IACZ,KAAK,CAAS;IACd,OAAO,CAA0B;IACzC,0EAA0E;IAClE,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,YAAY,OAA4B;QACtC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,2FAA2F;QAC3F,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,OAAO,GAAG,IAAI,KAAK,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,IAAI;QACR,8FAA8F;QAC9F,+FAA+F;QAC/F,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;SACzC,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC9E,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,GAAG,kBAAkB,CAAC,CAAC;IAChF,CAAC;IAED,sFAAsF;IACtF,KAAK,CAAC,QAAQ;QACZ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAChD,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,GAAG,kBAAkB,CAAC,CAAC;QAC9E,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAqB,CAAC;IACrD,CAAC;IAEO,IAAI,CAAC,IAAY,EAAE,OAAoB,EAAE;QAC/C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,EAAE,EAAE;YACxC,GAAG,IAAI;YACP,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,gBAAgB,EAAE,IAAI,CAAC,KAAK;gBAC5B,GAAG,IAAI,CAAC,OAAO;aAChB;SACF,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,MAAM,CAAI,IAA6B;QACnD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;QACnE,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,gCAAgC,CAAC,CAAC,CAAC;QAChG,OAAO,OAAY,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAY;QACxB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAA0B,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvF,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAsB,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,OAAO,MAAM,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY;QACzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAwB,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CACzF,CAAC,KAAY,EAAE,EAAE;YACf,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC1E,CAAC,CACF,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAwB,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CACzF,CAAC,KAAY,EAAE,EAAE;YACf,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC1E,CAAC,CACF,CAAC;QACF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACrC,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,SAAS,CACb,IAAY,EACZ,QAA6B,EAC7B,QAAsB;QAEtB,2FAA2F;QAC3F,MAAM,OAAO,GAA4B,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QACvE,IAAI,OAAO,QAAQ,KAAK,QAAQ;YAAE,OAAO,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC;;YACxD,OAAO,CAAC,QAAQ,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAA+B,OAAO,CAAC,CAAC;YACxE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACxC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAI,KAAe,CAAC,OAAO,CAAC;YACzC,yEAAyE;YACzE,IAAI,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;YACrF,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY,EAAE,QAAsB;QACnD,KAAK,QAAQ,CAAC;QACd,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;YACvE,MAAM,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC1E,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,6EAA6E;IAC7E,KAAK,CAAC,YAAY;QAChB,OAAO,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,wBAAwB;IAC1B,CAAC;IAED,KAAK;QACH,OAAO;YACL,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;gBAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC;gBAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;oBAC7C,MAAM,EAAE,MAAM;oBACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;iBACnE,CAAC,CAAC;gBACH,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;gBACnE,IAAI,CAAC,QAAQ,CAAC,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC;gBACjF,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;gBACrC,OAAO;oBACL,IAAI;oBACJ,GAAG,EAAE,IAAI,IAAI,EAAE;oBACf,IAAI;oBACJ,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU;iBACR,CAAC;YACvB,CAAC;YACD,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACrB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,qBAAqB,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACpF,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;gBACnE,OAAO,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;YAC9B,CAAC;YACD,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBACrB,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7D,CAAC;SACF,CAAC;IACJ,CAAC;CACF;AAED,SAAS,eAAe,CAAC,KAAiB;IACxC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,KAAK,GAAG,MAAM,CAAC;IACrB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,KAAK,EAAE,CAAC;QACzD,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC"}