google-drive-mock 0.0.1
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/.ENV_EXAMPLE +15 -0
- package/.aiexclude +6 -0
- package/.github/workflows/ci.yml +41 -0
- package/.github/workflows/release.yml +24 -0
- package/AGENTS.md +9 -0
- package/LICENSE +21 -0
- package/README.md +89 -0
- package/dist/batch.d.ts +2 -0
- package/dist/batch.js +236 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +186 -0
- package/dist/store.d.ts +23 -0
- package/dist/store.js +58 -0
- package/eslint.config.mjs +15 -0
- package/examples/google-login.html +196 -0
- package/examples/serve-login.ts +11 -0
- package/google-drive-mock.png +0 -0
- package/package.json +64 -0
- package/specs/googleapiscom-drive.json +1471 -0
- package/specs/openapi.json +7106 -0
- package/specs/openapi.yaml +4748 -0
- package/src/batch.ts +286 -0
- package/src/index.ts +219 -0
- package/src/store.ts +85 -0
- package/test/basics.test.ts +201 -0
- package/test/config.ts +193 -0
- package/test/latency.test.ts +65 -0
- package/test/routines.test.ts +224 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +17 -0
package/dist/store.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.driveStore = exports.DriveStore = void 0;
|
|
4
|
+
class DriveStore {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.files = new Map();
|
|
7
|
+
}
|
|
8
|
+
createFile(file) {
|
|
9
|
+
if (!file.name) {
|
|
10
|
+
throw new Error("File name is required");
|
|
11
|
+
}
|
|
12
|
+
const id = file.id || Math.random().toString(36).substring(7);
|
|
13
|
+
const newFile = Object.assign(Object.assign({ kind: "drive#file", mimeType: "application/octet-stream" }, file), { id, version: 1 });
|
|
14
|
+
this.files.set(id, newFile);
|
|
15
|
+
return newFile;
|
|
16
|
+
}
|
|
17
|
+
updateFile(id, updates) {
|
|
18
|
+
const file = this.files.get(id);
|
|
19
|
+
if (!file)
|
|
20
|
+
return null;
|
|
21
|
+
// Merge updates and increment version
|
|
22
|
+
const updatedFile = Object.assign(Object.assign(Object.assign({}, file), updates), { version: file.version + 1 });
|
|
23
|
+
this.files.set(id, updatedFile);
|
|
24
|
+
return updatedFile;
|
|
25
|
+
}
|
|
26
|
+
getFile(id) {
|
|
27
|
+
return this.files.get(id) || null;
|
|
28
|
+
}
|
|
29
|
+
deleteFile(id) {
|
|
30
|
+
return this.files.delete(id);
|
|
31
|
+
}
|
|
32
|
+
listFiles() {
|
|
33
|
+
// Basic implementation, ignores query for now
|
|
34
|
+
return Array.from(this.files.values());
|
|
35
|
+
}
|
|
36
|
+
clear() {
|
|
37
|
+
this.files.clear();
|
|
38
|
+
}
|
|
39
|
+
getAbout() {
|
|
40
|
+
return {
|
|
41
|
+
user: {
|
|
42
|
+
displayName: "Mock User",
|
|
43
|
+
emailAddress: "mock@example.com",
|
|
44
|
+
kind: "drive#user",
|
|
45
|
+
me: true,
|
|
46
|
+
permissionId: "mock-permission-id"
|
|
47
|
+
},
|
|
48
|
+
storageQuota: {
|
|
49
|
+
limit: "10000000000",
|
|
50
|
+
usage: "0",
|
|
51
|
+
usageInDrive: "0",
|
|
52
|
+
usageInDriveTrash: "0"
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.DriveStore = DriveStore;
|
|
58
|
+
exports.driveStore = new DriveStore();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import globals from "globals";
|
|
2
|
+
import pluginJs from "@eslint/js";
|
|
3
|
+
import tseslint from "typescript-eslint";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/** @type {import('eslint').Linter.Config[]} */
|
|
7
|
+
export default [
|
|
8
|
+
{ files: ["**/*.{js,mjs,cjs,ts}"] },
|
|
9
|
+
{ languageOptions: { globals: globals.node } },
|
|
10
|
+
pluginJs.configs.recommended,
|
|
11
|
+
...tseslint.configs.recommended,
|
|
12
|
+
{
|
|
13
|
+
ignores: ["dist/**", "coverage/**", "node_modules/**"]
|
|
14
|
+
}
|
|
15
|
+
];
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Google Drive Token Generator</title>
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
font-family: sans-serif;
|
|
11
|
+
padding: 20px;
|
|
12
|
+
max-width: 600px;
|
|
13
|
+
margin: 0 auto;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.form-group {
|
|
17
|
+
margin-bottom: 15px;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
label {
|
|
21
|
+
display: block;
|
|
22
|
+
margin-bottom: 5px;
|
|
23
|
+
font-weight: bold;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
input[type="text"] {
|
|
27
|
+
width: 100%;
|
|
28
|
+
padding: 8px;
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
button {
|
|
33
|
+
padding: 10px 20px;
|
|
34
|
+
background-color: #4285f4;
|
|
35
|
+
color: white;
|
|
36
|
+
border: none;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
font-size: 16px;
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
button:hover {
|
|
43
|
+
background-color: #357ae8;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
button#copy-btn {
|
|
47
|
+
background-color: #28a745;
|
|
48
|
+
margin-top: 10px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
button#copy-btn:hover {
|
|
52
|
+
background-color: #218838;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#token-display {
|
|
56
|
+
margin-top: 20px;
|
|
57
|
+
background: #f0f0f0;
|
|
58
|
+
padding: 15px;
|
|
59
|
+
border-radius: 4px;
|
|
60
|
+
display: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
textarea {
|
|
64
|
+
width: 100%;
|
|
65
|
+
padding: 8px;
|
|
66
|
+
box-sizing: border-box;
|
|
67
|
+
border: 1px solid #ccc;
|
|
68
|
+
border-radius: 4px;
|
|
69
|
+
resize: vertical;
|
|
70
|
+
font-family: monospace;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.hidden {
|
|
74
|
+
display: none;
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
77
|
+
<script src="https://accounts.google.com/gsi/client" async defer></script>
|
|
78
|
+
</head>
|
|
79
|
+
|
|
80
|
+
<body>
|
|
81
|
+
|
|
82
|
+
<h1>Google Drive Login</h1>
|
|
83
|
+
<p>Enter your Client ID to authenticate and get an access token.</p>
|
|
84
|
+
|
|
85
|
+
<div class="form-group">
|
|
86
|
+
<label for="client-id">Client ID:</label>
|
|
87
|
+
<input type="text" id="client-id" placeholder="YOUR_CLIENT_ID.apps.googleusercontent.com">
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<button id="login-btn" onclick="handleAuth()">Login to Google Drive</button>
|
|
91
|
+
|
|
92
|
+
<div id="token-display">
|
|
93
|
+
<h3>Access Token:</h3>
|
|
94
|
+
<textarea id="access-token" readonly rows="6"></textarea>
|
|
95
|
+
<button id="copy-btn" onclick="copyToken()">Copy Token</button>
|
|
96
|
+
|
|
97
|
+
<h3>Full .ENV Content:</h3>
|
|
98
|
+
<textarea id="env-content" readonly rows="12"></textarea>
|
|
99
|
+
<button id="copy-env-btn" onclick="copyEnv()">Copy .ENV</button>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<script>
|
|
103
|
+
let tokenClient;
|
|
104
|
+
|
|
105
|
+
window.onload = function () {
|
|
106
|
+
const storedClientId = localStorage.getItem('google_client_id');
|
|
107
|
+
if (storedClientId) {
|
|
108
|
+
document.getElementById('client-id').value = storedClientId;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function handleAuth() {
|
|
113
|
+
const clientId = document.getElementById('client-id').value.trim();
|
|
114
|
+
if (!clientId) {
|
|
115
|
+
alert('Please enter a Client ID');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Store Client ID
|
|
120
|
+
localStorage.setItem('google_client_id', clientId);
|
|
121
|
+
|
|
122
|
+
if (!window.google) {
|
|
123
|
+
alert('Google Identity Services library not loaded yet. Please wait or refresh.');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
tokenClient = google.accounts.oauth2.initTokenClient({
|
|
128
|
+
client_id: clientId,
|
|
129
|
+
scope: 'https://www.googleapis.com/auth/drive',
|
|
130
|
+
callback: (response) => {
|
|
131
|
+
if (response.error) {
|
|
132
|
+
alert('Error: ' + response.error);
|
|
133
|
+
console.error(response);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (response.access_token) {
|
|
137
|
+
document.getElementById('token-display').style.display = 'block';
|
|
138
|
+
|
|
139
|
+
// Set Token
|
|
140
|
+
document.getElementById('access-token').value = response.access_token;
|
|
141
|
+
|
|
142
|
+
// Set Env Content
|
|
143
|
+
const envContent = `# To run tests against the real Google Drive API
|
|
144
|
+
# Copy this file to .ENV and fill in the values
|
|
145
|
+
|
|
146
|
+
# 'mock' (default) or 'real'
|
|
147
|
+
TEST_TARGET=real
|
|
148
|
+
|
|
149
|
+
# OAuth2 Access Token for your Google Account
|
|
150
|
+
# Get one via 'npm run example:login'
|
|
151
|
+
GDRIVE_TOKEN=${response.access_token}
|
|
152
|
+
|
|
153
|
+
# Client ID for the Google Login Example
|
|
154
|
+
GDRIVE_CLIENT_ID=${clientId}
|
|
155
|
+
|
|
156
|
+
# Optional: Simulate latency in ms (only works with TEST_TARGET=mock)
|
|
157
|
+
# LATENCY=50
|
|
158
|
+
`;
|
|
159
|
+
document.getElementById('env-content').value = envContent;
|
|
160
|
+
|
|
161
|
+
console.log('Access Token:', response.access_token);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
tokenClient.requestAccessToken();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function copyToken() {
|
|
170
|
+
copyToClipboard('access-token', 'copy-btn');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function copyEnv() {
|
|
174
|
+
copyToClipboard('env-content', 'copy-env-btn');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function copyToClipboard(elementId, buttonId) {
|
|
178
|
+
const textEl = document.getElementById(elementId);
|
|
179
|
+
textEl.select();
|
|
180
|
+
textEl.setSelectionRange(0, 99999); /* For mobile devices */
|
|
181
|
+
|
|
182
|
+
navigator.clipboard.writeText(textEl.value).then(() => {
|
|
183
|
+
const btn = document.getElementById(buttonId);
|
|
184
|
+
const originalText = btn.innerText;
|
|
185
|
+
btn.innerText = 'Copied!';
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
btn.innerText = originalText;
|
|
188
|
+
}, 2000);
|
|
189
|
+
}).catch(err => {
|
|
190
|
+
console.error('Failed to copy text: ', err);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
</script>
|
|
194
|
+
</body>
|
|
195
|
+
|
|
196
|
+
</html>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
|
|
3
|
+
const app = express();
|
|
4
|
+
const port = 8080;
|
|
5
|
+
|
|
6
|
+
app.use(express.static(__dirname));
|
|
7
|
+
|
|
8
|
+
app.listen(port, () => {
|
|
9
|
+
console.log(`Login example running at http://localhost:${port}/google-login.html`);
|
|
10
|
+
console.log('NOTE: Ensure "http://localhost:8080" is added to your Authorized JavaScript origins in Google Cloud Console.');
|
|
11
|
+
});
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "google-drive-mock",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Mock-Server that simulates being google-drive. Used for testing.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/index.js",
|
|
10
|
+
"dev": "ts-node src/index.ts",
|
|
11
|
+
"test": "TEST_TARGET=mock vitest run",
|
|
12
|
+
"test:slow": "LATENCY=20 vitest run",
|
|
13
|
+
"test:browser": "start-server-and-test dev http://localhost:3000 'BROWSER_ENABLED=true vitest run --browser'",
|
|
14
|
+
"test:real": "TEST_TARGET=real vitest run",
|
|
15
|
+
"example:login": "ts-node examples/serve-login.ts",
|
|
16
|
+
"lint": "eslint .",
|
|
17
|
+
"lint:fix": "eslint . --fix"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/pubkey/google-drive-mock.git"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"google-drive",
|
|
25
|
+
"mock",
|
|
26
|
+
"testing",
|
|
27
|
+
"server",
|
|
28
|
+
"api",
|
|
29
|
+
"simulator",
|
|
30
|
+
"rxdb"
|
|
31
|
+
],
|
|
32
|
+
"author": "pubkey",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"type": "commonjs",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/pubkey/google-drive-mock/issues"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/pubkey/google-drive-mock#readme",
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"express": "5.2.1"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@eslint/js": "9.39.2",
|
|
44
|
+
"@types/cors": "2.8.19",
|
|
45
|
+
"@types/express": "5.0.6",
|
|
46
|
+
"@types/node": "25.1.0",
|
|
47
|
+
"@types/supertest": "6.0.3",
|
|
48
|
+
"@vitest/browser": "4.0.18",
|
|
49
|
+
"@vitest/browser-playwright": "4.0.18",
|
|
50
|
+
"async-test-util": "2.5.0",
|
|
51
|
+
"cors": "2.8.6",
|
|
52
|
+
"dotenv": "17.2.3",
|
|
53
|
+
"eslint": "9.39.2",
|
|
54
|
+
"express": "5.2.1",
|
|
55
|
+
"globals": "17.2.0",
|
|
56
|
+
"playwright": "1.58.0",
|
|
57
|
+
"start-server-and-test": "2.1.3",
|
|
58
|
+
"supertest": "7.2.2",
|
|
59
|
+
"ts-node": "10.9.2",
|
|
60
|
+
"typescript": "5.9.3",
|
|
61
|
+
"typescript-eslint": "8.54.0",
|
|
62
|
+
"vitest": "4.0.18"
|
|
63
|
+
}
|
|
64
|
+
}
|