Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
"node": ">=22.13.0"
},
"main": "./dist/extension.js",
"activationEvents": [],
"activationEvents": [
"onFileSystem:b2-config"
],
Comment thread
goanpeca marked this conversation as resolved.
"scripts": {
"build:icons": "node scripts/build-icons.js",
"clean:dist": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
Expand Down Expand Up @@ -335,6 +337,32 @@
}
}
},
"jsonValidation": [
{
"fileMatch": [
"b2-config:/**/lifecycle.json"
],
"url": "./resources/schemas/b2-config-lifecycle.schema.json"
},
{
"fileMatch": [
"b2-config:/**/cors.json"
],
"url": "./resources/schemas/b2-config-cors.schema.json"
},
{
"fileMatch": [
"b2-config:/**/notifications.json"
],
"url": "./resources/schemas/b2-config-notifications.schema.json"
},
{
"fileMatch": [
"b2-config:/**/bucketInfo.json"
],
"url": "./resources/schemas/b2-config-bucketInfo.schema.json"
}
],
Comment thread
goanpeca marked this conversation as resolved.
"languageModelTools": [
{
"name": "b2_listBuckets",
Expand Down
11 changes: 11 additions & 0 deletions resources/schemas/b2-config-bucketInfo.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "vscode://schemas/b2-config/bucketInfo",
"title": "Backblaze B2 Bucket Info",
"description": "Custom key-value metadata stored on a Backblaze B2 bucket.",
"type": "object",
"additionalProperties": {
"type": "string"
},
"default": {}
}
85 changes: 85 additions & 0 deletions resources/schemas/b2-config-cors.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "vscode://schemas/b2-config/cors",
"title": "Backblaze B2 CORS Rules",
"description": "CORS rules for browser access to a Backblaze B2 bucket.",
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"corsRuleName": {
"type": "string",
"description": "Unique name for this CORS rule."
},
"allowedOrigins": {
"type": "array",
"description": "Origins allowed to make cross-origin requests.",
"items": {
"type": "string"
}
},
"allowedOperations": {
"type": "array",
"description": "B2 or S3 operations permitted by this CORS rule.",
"items": {
"type": "string",
"enum": [
"b2_download_file_by_id",
"b2_download_file_by_name",
"b2_upload_file",
"b2_upload_part",
"s3_delete",
"s3_get",
"s3_head",
"s3_post",
"s3_put"
]
},
"uniqueItems": true
},
"allowedHeaders": {
"description": "Request headers allowed in preflight requests, or null if none are allowed.",
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
]
},
"exposeHeaders": {
"description": "Response headers exposed to browsers, or null if none are exposed.",
"anyOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "null"
}
]
},
"maxAgeSeconds": {
"type": "integer",
"minimum": 0,
"description": "Maximum time browsers may cache the preflight response."
}
},
"required": [
"corsRuleName",
"allowedOrigins",
"allowedOperations",
"allowedHeaders",
"exposeHeaders",
"maxAgeSeconds"
]
},
"default": []
}
43 changes: 43 additions & 0 deletions resources/schemas/b2-config-lifecycle.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "vscode://schemas/b2-config/lifecycle",
"title": "Backblaze B2 Lifecycle Rules",
"description": "Lifecycle rules for a Backblaze B2 bucket.",
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"fileNamePrefix": {
"type": "string",
"description": "File name prefix this lifecycle rule applies to. Use an empty string to match every object."
},
"daysFromUploadingToHiding": {
"description": "Days after upload before B2 hides matching objects. Use null to disable automatic hiding.",
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"daysFromHidingToDeleting": {
"description": "Days after an object is hidden before B2 deletes it. Use null to keep hidden versions.",
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
}
},
"required": ["fileNamePrefix", "daysFromUploadingToHiding", "daysFromHidingToDeleting"]
},
"default": []
}
93 changes: 93 additions & 0 deletions resources/schemas/b2-config-notifications.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "vscode://schemas/b2-config/notifications",
"title": "Backblaze B2 Event Notification Rules",
"description": "Event notification rules for a Backblaze B2 bucket. Masked secret values are preserved when left unchanged.",
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"properties": {
"name": {
"type": "string",
"description": "Unique name for this notification rule."
},
"eventTypes": {
"type": "array",
"description": "B2 event types that trigger this rule.",
"items": {
"type": "string",
"enum": [
"b2:ObjectCreated:*",
"b2:ObjectCreated:Upload",
"b2:ObjectCreated:MultipartUpload",
"b2:ObjectCreated:Copy",
"b2:ObjectCreated:Replica",
"b2:ObjectCreated:Hide",
"b2:ObjectDeleted:*",
"b2:ObjectDeleted:Delete",
"b2:ObjectDeleted:LifecycleRule"
]
},
"uniqueItems": true
},
"isEnabled": {
"type": "boolean",
"description": "Whether this rule is actively sending notifications."
},
"isSuspended": {
"type": "boolean",
"description": "Whether B2 has suspended this rule due to delivery failures."
},
"objectNamePrefix": {
"type": "string",
"description": "Only events for objects with this prefix trigger the rule. Use an empty string to match every object."
},
"suspensionReason": {
"type": "string",
"description": "Reason for suspension, or an empty string if not suspended."
},
"targetConfiguration": {
"type": "object",
"additionalProperties": true,
"properties": {
"targetType": {
"type": "string",
"description": "Webhook target type, usually url."
},
"url": {
"type": "string",
"format": "uri",
"description": "Webhook URL that receives event notifications."
},
"hmacSha256SigningSecret": {
"type": "string",
"description": "Optional HMAC-SHA256 signing secret. Leave __B2_CONFIG_MASKED_SECRET__ unchanged to preserve the existing secret."
},
"hmacSha256": {
"type": "string",
"description": "Optional HMAC-SHA256 signing secret. Leave __B2_CONFIG_MASKED_SECRET__ unchanged to preserve the existing secret."
},
"customHeaders": {
"type": "object",
"description": "Optional custom webhook request headers. Header values are masked on read.",
"additionalProperties": {
"type": "string"
}
}
},
"required": ["targetType", "url"]
}
},
"required": [
"name",
"eventTypes",
"isEnabled",
"isSuspended",
"objectNamePrefix",
"suspensionReason",
"targetConfiguration"
]
},
"default": []
}
12 changes: 10 additions & 2 deletions scripts/release-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,26 @@ const manifestContract = {
type: "git",
url: "https://github.com/backblaze-labs/b2-vscode.git",
},
activationEvents: [],
activationEvents: ["onFileSystem:b2-config"],
forbiddenTopLevelFields: ["extensionDependencies", "extensionPack"],
requiredPackageEntries: [
"extension/resources/b2-icon.png",
"extension/resources/b2-icon.svg",
"extension/resources/b2-icons.woff",
"extension/resources/schemas/b2-config-bucketInfo.schema.json",
"extension/resources/schemas/b2-config-cors.schema.json",
"extension/resources/schemas/b2-config-lifecycle.schema.json",
"extension/resources/schemas/b2-config-notifications.schema.json",
],
requiredInstalledFiles: [
"dist/extension.js",
"resources/b2-icon.png",
"resources/b2-icon.svg",
"resources/b2-icons.woff",
"resources/schemas/b2-config-bucketInfo.schema.json",
"resources/schemas/b2-config-cors.schema.json",
"resources/schemas/b2-config-lifecycle.schema.json",
"resources/schemas/b2-config-notifications.schema.json",
],
commandIds: [
"b2.authenticate",
Expand All @@ -59,7 +67,7 @@ const manifestContract = {
"b2_deleteFile",
"b2_presignUrl",
],
contributesSha256: "40a5f09a30986dfcb974032113ec6afaa2a694fa9fd12421b222955dac64eda7",
contributesSha256: "ded59c90229a7abbf10894fb367ca48e6d4040a8069848ff076e7cf88cfd5b2c",
};

function stableStringify(value) {
Expand Down
32 changes: 28 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import { withTimeout } from "./services/transferTimeout";
import { AuthService } from "./services/authService";
import { cleanupStaleTempFileCache, TempFileManager } from "./services/tempFileManager";
import { B2TreeProvider } from "./providers/b2TreeProvider";
import {
B2_CONFIG_SCHEME,
B2ConfigFileSystemProvider,
} from "./providers/b2ConfigFileSystemProvider";
import { B2StatusBar } from "./ui/statusBar";
import { registerCommands } from "./commands";
import { registerB2Tools } from "./tools/registration";
Expand Down Expand Up @@ -220,8 +224,28 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
// 4. Status bar
const statusBar = new B2StatusBar(authService);

// 5. Register commands
const setAuthenticatedClient = createAuthenticatedClientSetter();
// 5. Register virtual bucket-configuration documents
const configFileSystemProvider = new B2ConfigFileSystemProvider(() => currentClient);
context.subscriptions.push(
vscode.workspace.registerFileSystemProvider(B2_CONFIG_SCHEME, configFileSystemProvider, {
isCaseSensitive: true,
}),
configFileSystemProvider,
vscode.workspace.onDidCloseTextDocument((document) => {
if (document.uri.scheme === B2_CONFIG_SCHEME) {
configFileSystemProvider.deleteCacheEntry(document.uri);
}
}),
);

// 6. Register commands
const setAuthenticatedClient = createAuthenticatedClientSetter(
scheduleAuthenticatedCleanups,
(client) => {
currentClient = client;
configFileSystemProvider.clearCache();
},
);
registerCommands({
context,
authService,
Expand All @@ -233,11 +257,11 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
});
registerB2Tools(context, () => currentClient);

// 6. Track disposables
// 7. Track disposables
context.subscriptions.push(treeView, statusBar, authService, tempFileManager);
scheduleTempCleanups(context);

// 7. Auto-auth: try to resolve stored/env credentials
// 8. Auto-auth: try to resolve stored/env credentials
try {
const credentials = await authService.resolveCredentials();
if (credentials) {
Expand Down
Loading
Loading