@camstack/core 0.1.1 → 0.1.3
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/dist/builtins/local-backup/index.d.mts +42 -0
- package/dist/builtins/local-backup/index.d.ts +42 -0
- package/dist/builtins/local-backup/index.js +188 -0
- package/dist/builtins/local-backup/index.js.map +1 -0
- package/dist/builtins/local-backup/index.mjs +11 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.mts +2 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +2 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +210 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js.map +1 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +10 -0
- package/dist/builtins/sqlite-storage/index.d.mts +4 -0
- package/dist/builtins/sqlite-storage/index.d.ts +4 -0
- package/dist/builtins/sqlite-storage/index.js +1025 -0
- package/dist/builtins/sqlite-storage/index.js.map +1 -0
- package/dist/builtins/sqlite-storage/index.mjs +31 -0
- package/dist/builtins/sqlite-storage/index.mjs.map +1 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.mts +2 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +2 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +317 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js.map +1 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +10 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs.map +1 -0
- package/dist/builtins/winston-logging/index.d.mts +30 -0
- package/dist/builtins/winston-logging/index.d.ts +30 -0
- package/dist/builtins/winston-logging/index.js +185 -0
- package/dist/builtins/winston-logging/index.js.map +1 -0
- package/dist/builtins/winston-logging/index.mjs +11 -0
- package/dist/builtins/winston-logging/index.mjs.map +1 -0
- package/dist/chunk-LQFPAEQF.mjs +147 -0
- package/dist/chunk-LQFPAEQF.mjs.map +1 -0
- package/dist/{chunk-LZOMFHX3.mjs → chunk-QEMJH3KY.mjs} +11 -1
- package/dist/chunk-QEMJH3KY.mjs.map +1 -0
- package/dist/chunk-R3DIIBBX.mjs +532 -0
- package/dist/chunk-R3DIIBBX.mjs.map +1 -0
- package/dist/chunk-SO4LROOT.mjs +150 -0
- package/dist/chunk-SO4LROOT.mjs.map +1 -0
- package/dist/chunk-SPA4JBKN.mjs +175 -0
- package/dist/chunk-SPA4JBKN.mjs.map +1 -0
- package/dist/chunk-YXNXYYHL.mjs +282 -0
- package/dist/chunk-YXNXYYHL.mjs.map +1 -0
- package/dist/dist-N7SR63RN.mjs +3515 -0
- package/dist/dist-N7SR63RN.mjs.map +1 -0
- package/dist/filesystem-storage.addon-C42r589X.d.mts +57 -0
- package/dist/filesystem-storage.addon-C42r589X.d.ts +57 -0
- package/dist/index.d.mts +281 -849
- package/dist/index.d.ts +281 -849
- package/dist/index.js +8351 -1942
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4086 -2164
- package/dist/index.mjs.map +1 -1
- package/dist/onnxruntime_binding-6Q6HXASN.node +0 -0
- package/dist/onnxruntime_binding-EKZT2NRK.node +0 -0
- package/dist/onnxruntime_binding-P6S7V3CI.node +0 -0
- package/dist/onnxruntime_binding-PJNNIIUO.node +0 -0
- package/dist/onnxruntime_binding-UN6SPTQK.node +0 -0
- package/dist/sql-schema-CKz78rId.d.mts +97 -0
- package/dist/sql-schema-CKz78rId.d.ts +97 -0
- package/dist/sqlite-settings.addon-DigoKwpZ.d.mts +70 -0
- package/dist/sqlite-settings.addon-DigoKwpZ.d.ts +70 -0
- package/dist/{storage-location-manager-F4YZMHGM.mjs → storage-location-manager-UQRGHTCA.mjs} +2 -2
- package/dist/storage-location-manager-UQRGHTCA.mjs.map +1 -0
- package/dist/{wrapper-NTBY5HOA.mjs → wrapper-Y55ADNM5.mjs} +2 -2
- package/package.json +64 -12
- /package/dist/{chunk-LZOMFHX3.mjs.map → builtins/local-backup/index.mjs.map} +0 -0
- /package/dist/{storage-location-manager-F4YZMHGM.mjs.map → builtins/sqlite-storage/filesystem-storage.addon.mjs.map} +0 -0
- /package/dist/{wrapper-NTBY5HOA.mjs.map → wrapper-Y55ADNM5.mjs.map} +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IScopedLogger, IEventBus, IStorageLocation, BackupManifest, ICamstackAddon, IConfigurable, AddonManifest, AddonContext, CapabilityProviderMap, ConfigUISchema } from '@camstack/types';
|
|
2
|
+
export { BackupManifest } from '@camstack/types';
|
|
3
|
+
|
|
4
|
+
interface BackupConfig {
|
|
5
|
+
readonly backupDir: string;
|
|
6
|
+
readonly retentionCount: number;
|
|
7
|
+
}
|
|
8
|
+
declare class LocalBackupService {
|
|
9
|
+
private readonly config;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly eventBus;
|
|
12
|
+
private readonly storage;
|
|
13
|
+
private manifests;
|
|
14
|
+
constructor(config: BackupConfig, logger: IScopedLogger, eventBus: IEventBus, storage: IStorageLocation);
|
|
15
|
+
/** Create a backup of specified locations */
|
|
16
|
+
backup(options?: {
|
|
17
|
+
locations?: string[];
|
|
18
|
+
label?: string;
|
|
19
|
+
}): Promise<BackupManifest>;
|
|
20
|
+
/** Restore from a backup */
|
|
21
|
+
restore(backupId: string): Promise<void>;
|
|
22
|
+
/** List all backups sorted by timestamp descending */
|
|
23
|
+
list(): readonly BackupManifest[];
|
|
24
|
+
/** Delete a specific backup */
|
|
25
|
+
delete(backupId: string): Promise<void>;
|
|
26
|
+
private pruneOldBackups;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare class LocalBackupAddon implements ICamstackAddon, IConfigurable {
|
|
30
|
+
readonly manifest: AddonManifest;
|
|
31
|
+
private service;
|
|
32
|
+
private currentConfig;
|
|
33
|
+
initialize(context: AddonContext): Promise<void>;
|
|
34
|
+
shutdown(): Promise<void>;
|
|
35
|
+
getService(): LocalBackupService;
|
|
36
|
+
getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
|
|
37
|
+
getConfigSchema(): ConfigUISchema;
|
|
38
|
+
getConfig(): Record<string, unknown>;
|
|
39
|
+
onConfigChange(config: Record<string, unknown>): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type BackupConfig, LocalBackupAddon, LocalBackupService, LocalBackupAddon as default };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IScopedLogger, IEventBus, IStorageLocation, BackupManifest, ICamstackAddon, IConfigurable, AddonManifest, AddonContext, CapabilityProviderMap, ConfigUISchema } from '@camstack/types';
|
|
2
|
+
export { BackupManifest } from '@camstack/types';
|
|
3
|
+
|
|
4
|
+
interface BackupConfig {
|
|
5
|
+
readonly backupDir: string;
|
|
6
|
+
readonly retentionCount: number;
|
|
7
|
+
}
|
|
8
|
+
declare class LocalBackupService {
|
|
9
|
+
private readonly config;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly eventBus;
|
|
12
|
+
private readonly storage;
|
|
13
|
+
private manifests;
|
|
14
|
+
constructor(config: BackupConfig, logger: IScopedLogger, eventBus: IEventBus, storage: IStorageLocation);
|
|
15
|
+
/** Create a backup of specified locations */
|
|
16
|
+
backup(options?: {
|
|
17
|
+
locations?: string[];
|
|
18
|
+
label?: string;
|
|
19
|
+
}): Promise<BackupManifest>;
|
|
20
|
+
/** Restore from a backup */
|
|
21
|
+
restore(backupId: string): Promise<void>;
|
|
22
|
+
/** List all backups sorted by timestamp descending */
|
|
23
|
+
list(): readonly BackupManifest[];
|
|
24
|
+
/** Delete a specific backup */
|
|
25
|
+
delete(backupId: string): Promise<void>;
|
|
26
|
+
private pruneOldBackups;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare class LocalBackupAddon implements ICamstackAddon, IConfigurable {
|
|
30
|
+
readonly manifest: AddonManifest;
|
|
31
|
+
private service;
|
|
32
|
+
private currentConfig;
|
|
33
|
+
initialize(context: AddonContext): Promise<void>;
|
|
34
|
+
shutdown(): Promise<void>;
|
|
35
|
+
getService(): LocalBackupService;
|
|
36
|
+
getCapabilityProvider<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
|
|
37
|
+
getConfigSchema(): ConfigUISchema;
|
|
38
|
+
getConfig(): Record<string, unknown>;
|
|
39
|
+
onConfigChange(config: Record<string, unknown>): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { type BackupConfig, LocalBackupAddon, LocalBackupService, LocalBackupAddon as default };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/builtins/local-backup/index.ts
|
|
31
|
+
var local_backup_exports = {};
|
|
32
|
+
__export(local_backup_exports, {
|
|
33
|
+
LocalBackupAddon: () => LocalBackupAddon,
|
|
34
|
+
LocalBackupService: () => LocalBackupService,
|
|
35
|
+
default: () => LocalBackupAddon
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(local_backup_exports);
|
|
38
|
+
|
|
39
|
+
// src/builtins/local-backup/local-backup.ts
|
|
40
|
+
var import_node_crypto = require("crypto");
|
|
41
|
+
var LocalBackupService = class {
|
|
42
|
+
constructor(config, logger, eventBus, storage) {
|
|
43
|
+
this.config = config;
|
|
44
|
+
this.logger = logger;
|
|
45
|
+
this.eventBus = eventBus;
|
|
46
|
+
this.storage = storage;
|
|
47
|
+
}
|
|
48
|
+
manifests = [];
|
|
49
|
+
/** Create a backup of specified locations */
|
|
50
|
+
async backup(options) {
|
|
51
|
+
const id = (0, import_node_crypto.randomUUID)();
|
|
52
|
+
const timestamp = Date.now();
|
|
53
|
+
const locations = options?.locations ?? ["config", "events", "logs"];
|
|
54
|
+
this.logger.info(`Starting backup ${id} (${locations.join(", ")})`);
|
|
55
|
+
const manifest = {
|
|
56
|
+
id,
|
|
57
|
+
timestamp,
|
|
58
|
+
label: options?.label,
|
|
59
|
+
locations,
|
|
60
|
+
sizeMB: 0,
|
|
61
|
+
path: `${this.config.backupDir}/${id}`
|
|
62
|
+
};
|
|
63
|
+
const updated = [...this.manifests, manifest];
|
|
64
|
+
this.manifests = updated;
|
|
65
|
+
await this.pruneOldBackups();
|
|
66
|
+
this.eventBus.emit({
|
|
67
|
+
id: (0, import_node_crypto.randomUUID)(),
|
|
68
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
69
|
+
source: { type: "addon", id: "local-backup" },
|
|
70
|
+
category: "backup.completed",
|
|
71
|
+
data: { backupId: id, locations: [...locations], sizeMB: manifest.sizeMB }
|
|
72
|
+
});
|
|
73
|
+
this.logger.info(`Backup ${id} completed`);
|
|
74
|
+
return manifest;
|
|
75
|
+
}
|
|
76
|
+
/** Restore from a backup */
|
|
77
|
+
async restore(backupId) {
|
|
78
|
+
const manifest = this.manifests.find((m) => m.id === backupId);
|
|
79
|
+
if (!manifest) throw new Error(`Backup ${backupId} not found`);
|
|
80
|
+
this.logger.info(`Restoring from backup ${backupId}`);
|
|
81
|
+
this.eventBus.emit({
|
|
82
|
+
id: (0, import_node_crypto.randomUUID)(),
|
|
83
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
84
|
+
source: { type: "addon", id: "local-backup" },
|
|
85
|
+
category: "backup.restored",
|
|
86
|
+
data: { backupId }
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** List all backups sorted by timestamp descending */
|
|
90
|
+
list() {
|
|
91
|
+
return [...this.manifests].sort((a, b) => b.timestamp - a.timestamp);
|
|
92
|
+
}
|
|
93
|
+
/** Delete a specific backup */
|
|
94
|
+
async delete(backupId) {
|
|
95
|
+
this.manifests = this.manifests.filter((m) => m.id !== backupId);
|
|
96
|
+
}
|
|
97
|
+
async pruneOldBackups() {
|
|
98
|
+
const sorted = [...this.manifests].sort((a, b) => a.timestamp - b.timestamp);
|
|
99
|
+
while (sorted.length > this.config.retentionCount) {
|
|
100
|
+
const oldest = sorted.shift();
|
|
101
|
+
if (oldest) {
|
|
102
|
+
this.logger.info(`Pruning old backup ${oldest.id}`);
|
|
103
|
+
this.manifests = this.manifests.filter((m) => m.id !== oldest.id);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/builtins/local-backup/local-backup.addon.ts
|
|
110
|
+
var path = __toESM(require("path"));
|
|
111
|
+
var LocalBackupAddon = class {
|
|
112
|
+
manifest = {
|
|
113
|
+
id: "local-backup",
|
|
114
|
+
name: "Local Backup",
|
|
115
|
+
version: "1.0.0",
|
|
116
|
+
capabilities: ["backup"]
|
|
117
|
+
};
|
|
118
|
+
service = null;
|
|
119
|
+
currentConfig = {
|
|
120
|
+
retentionCount: 7
|
|
121
|
+
};
|
|
122
|
+
async initialize(context) {
|
|
123
|
+
this.currentConfig = {
|
|
124
|
+
retentionCount: context.addonConfig.retentionCount ?? this.currentConfig.retentionCount
|
|
125
|
+
};
|
|
126
|
+
const backupConfig = {
|
|
127
|
+
backupDir: path.join(context.locationPaths.data, "backups"),
|
|
128
|
+
retentionCount: this.currentConfig.retentionCount
|
|
129
|
+
};
|
|
130
|
+
this.service = new LocalBackupService(
|
|
131
|
+
backupConfig,
|
|
132
|
+
context.logger,
|
|
133
|
+
context.eventBus,
|
|
134
|
+
context.storage
|
|
135
|
+
);
|
|
136
|
+
context.logger.info("Local Backup initialized");
|
|
137
|
+
}
|
|
138
|
+
async shutdown() {
|
|
139
|
+
this.service = null;
|
|
140
|
+
}
|
|
141
|
+
getService() {
|
|
142
|
+
if (!this.service) throw new Error("Local Backup not initialized");
|
|
143
|
+
return this.service;
|
|
144
|
+
}
|
|
145
|
+
getCapabilityProvider(name) {
|
|
146
|
+
if (name === "backup" && this.service) {
|
|
147
|
+
return this.service;
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
getConfigSchema() {
|
|
152
|
+
return {
|
|
153
|
+
sections: [
|
|
154
|
+
{
|
|
155
|
+
id: "backup-retention",
|
|
156
|
+
title: "Backup Retention",
|
|
157
|
+
description: "How many local backup snapshots to keep on disk.",
|
|
158
|
+
columns: 1,
|
|
159
|
+
fields: [
|
|
160
|
+
{
|
|
161
|
+
type: "number",
|
|
162
|
+
key: "retentionCount",
|
|
163
|
+
label: "Retention Count",
|
|
164
|
+
description: "Number of backup snapshots to keep before deleting the oldest",
|
|
165
|
+
min: 1,
|
|
166
|
+
max: 100,
|
|
167
|
+
step: 1
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
getConfig() {
|
|
175
|
+
return { ...this.currentConfig };
|
|
176
|
+
}
|
|
177
|
+
async onConfigChange(config) {
|
|
178
|
+
this.currentConfig = {
|
|
179
|
+
retentionCount: config.retentionCount ?? this.currentConfig.retentionCount
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
184
|
+
0 && (module.exports = {
|
|
185
|
+
LocalBackupAddon,
|
|
186
|
+
LocalBackupService
|
|
187
|
+
});
|
|
188
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/builtins/local-backup/index.ts","../../../src/builtins/local-backup/local-backup.ts","../../../src/builtins/local-backup/local-backup.addon.ts"],"sourcesContent":["export { LocalBackupService } from './local-backup'\nexport type { BackupManifest, BackupConfig } from './local-backup'\nexport { LocalBackupAddon } from './local-backup.addon'\nexport { LocalBackupAddon as default } from './local-backup.addon'\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, IStorageLocation, BackupManifest } from '@camstack/types'\n\nexport type { BackupManifest }\n\nexport interface BackupConfig {\n readonly backupDir: string\n readonly retentionCount: number\n}\n\nexport class LocalBackupService {\n private manifests: BackupManifest[] = []\n\n constructor(\n private readonly config: BackupConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n private readonly storage: IStorageLocation,\n ) {}\n\n /** Create a backup of specified locations */\n async backup(options?: {\n locations?: string[]\n label?: string\n }): Promise<BackupManifest> {\n const id = randomUUID()\n const timestamp = Date.now()\n const locations = options?.locations ?? ['config', 'events', 'logs']\n\n this.logger.info(`Starting backup ${id} (${locations.join(', ')})`)\n\n const manifest: BackupManifest = {\n id,\n timestamp,\n label: options?.label,\n locations,\n sizeMB: 0,\n path: `${this.config.backupDir}/${id}`,\n }\n\n const updated = [...this.manifests, manifest]\n this.manifests = updated\n\n await this.pruneOldBackups()\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: 'backup.completed',\n data: { backupId: id, locations: [...locations], sizeMB: manifest.sizeMB },\n })\n\n this.logger.info(`Backup ${id} completed`)\n return manifest\n }\n\n /** Restore from a backup */\n async restore(backupId: string): Promise<void> {\n const manifest = this.manifests.find((m) => m.id === backupId)\n if (!manifest) throw new Error(`Backup ${backupId} not found`)\n\n this.logger.info(`Restoring from backup ${backupId}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: 'backup.restored',\n data: { backupId },\n })\n }\n\n /** List all backups sorted by timestamp descending */\n list(): readonly BackupManifest[] {\n return [...this.manifests].sort((a, b) => b.timestamp - a.timestamp)\n }\n\n /** Delete a specific backup */\n async delete(backupId: string): Promise<void> {\n this.manifests = this.manifests.filter((m) => m.id !== backupId)\n }\n\n private async pruneOldBackups(): Promise<void> {\n const sorted = [...this.manifests].sort((a, b) => a.timestamp - b.timestamp)\n\n while (sorted.length > this.config.retentionCount) {\n const oldest = sorted.shift()\n if (oldest) {\n this.logger.info(`Pruning old backup ${oldest.id}`)\n this.manifests = this.manifests.filter((m) => m.id !== oldest.id)\n }\n }\n }\n}\n","import * as path from 'node:path'\nimport type {\n ICamstackAddon, AddonManifest, AddonContext,\n IConfigurable, ConfigUISchema, CapabilityProviderMap,\n} from '@camstack/types'\nimport { LocalBackupService } from './local-backup'\nimport type { BackupConfig } from './local-backup'\n\nexport class LocalBackupAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'local-backup',\n name: 'Local Backup',\n version: '1.0.0',\n capabilities: ['backup'],\n }\n\n private service: LocalBackupService | null = null\n private currentConfig = {\n retentionCount: 7,\n }\n\n async initialize(context: AddonContext): Promise<void> {\n this.currentConfig = {\n retentionCount: (context.addonConfig.retentionCount as number) ?? this.currentConfig.retentionCount,\n }\n const backupConfig: BackupConfig = {\n backupDir: path.join(context.locationPaths.data, 'backups'),\n retentionCount: this.currentConfig.retentionCount,\n }\n this.service = new LocalBackupService(\n backupConfig,\n context.logger,\n context.eventBus,\n context.storage,\n )\n context.logger.info('Local Backup initialized')\n }\n\n async shutdown(): Promise<void> {\n this.service = null\n }\n\n getService(): LocalBackupService {\n if (!this.service) throw new Error('Local Backup not initialized')\n return this.service\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'backup' as string && this.service) {\n return this.service as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getConfigSchema(): ConfigUISchema {\n return {\n sections: [\n {\n id: 'backup-retention',\n title: 'Backup Retention',\n description: 'How many local backup snapshots to keep on disk.',\n columns: 1,\n fields: [\n {\n type: 'number',\n key: 'retentionCount',\n label: 'Retention Count',\n description: 'Number of backup snapshots to keep before deleting the oldest',\n min: 1,\n max: 100,\n step: 1,\n },\n ],\n },\n ],\n }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig = {\n retentionCount: (config.retentionCount as number) ?? this.currentConfig.retentionCount,\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/builtins/sqlite-storage/filesystem-storage.addon.ts
|
|
31
|
+
var filesystem_storage_addon_exports = {};
|
|
32
|
+
__export(filesystem_storage_addon_exports, {
|
|
33
|
+
FilesystemStorageAddon: () => FilesystemStorageAddon,
|
|
34
|
+
default: () => filesystem_storage_addon_default
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(filesystem_storage_addon_exports);
|
|
37
|
+
|
|
38
|
+
// src/builtins/sqlite-storage/filesystem-storage-provider.ts
|
|
39
|
+
var fs = __toESM(require("fs"));
|
|
40
|
+
var path = __toESM(require("path"));
|
|
41
|
+
var STORAGE_LOCATION_TYPES = [
|
|
42
|
+
"recordings-high",
|
|
43
|
+
"recordings-low",
|
|
44
|
+
"recordings-clips",
|
|
45
|
+
"event-images",
|
|
46
|
+
"models",
|
|
47
|
+
"addons-data",
|
|
48
|
+
"cache",
|
|
49
|
+
"logs"
|
|
50
|
+
];
|
|
51
|
+
var DEFAULT_LOCATION_SUBDIRS = {
|
|
52
|
+
"recordings-high": "recordings-high",
|
|
53
|
+
"recordings-low": "recordings-low",
|
|
54
|
+
"recordings-clips": "recordings-clips",
|
|
55
|
+
"event-images": "event-images",
|
|
56
|
+
"models": "models",
|
|
57
|
+
"addons-data": "addons-data",
|
|
58
|
+
"cache": "/tmp/camstack-cache",
|
|
59
|
+
"logs": "logs"
|
|
60
|
+
};
|
|
61
|
+
var FilesystemStorageProvider = class {
|
|
62
|
+
id = "local";
|
|
63
|
+
name = "Local Filesystem";
|
|
64
|
+
supportedLocations = [...STORAGE_LOCATION_TYPES];
|
|
65
|
+
rootPath;
|
|
66
|
+
locationPaths;
|
|
67
|
+
constructor(rootPath, overrides) {
|
|
68
|
+
this.rootPath = path.resolve(rootPath);
|
|
69
|
+
this.locationPaths = /* @__PURE__ */ new Map();
|
|
70
|
+
for (const loc of STORAGE_LOCATION_TYPES) {
|
|
71
|
+
const override = overrides?.[loc];
|
|
72
|
+
if (override) {
|
|
73
|
+
this.locationPaths.set(loc, path.resolve(override));
|
|
74
|
+
} else {
|
|
75
|
+
const subdir = DEFAULT_LOCATION_SUBDIRS[loc];
|
|
76
|
+
this.locationPaths.set(
|
|
77
|
+
loc,
|
|
78
|
+
path.isAbsolute(subdir) ? subdir : path.join(this.rootPath, subdir)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
resolve(location, relativePath) {
|
|
84
|
+
const base = this.locationPaths.get(location);
|
|
85
|
+
if (!base) throw new Error(`Unknown storage location: ${location}`);
|
|
86
|
+
return path.join(base, relativePath);
|
|
87
|
+
}
|
|
88
|
+
async write(location, relativePath, data) {
|
|
89
|
+
const filePath = this.resolve(location, relativePath);
|
|
90
|
+
await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
91
|
+
if (Buffer.isBuffer(data)) {
|
|
92
|
+
await fs.promises.writeFile(filePath, data);
|
|
93
|
+
} else {
|
|
94
|
+
const writeStream = fs.createWriteStream(filePath);
|
|
95
|
+
await new Promise((resolve2, reject) => {
|
|
96
|
+
data.pipe(writeStream);
|
|
97
|
+
writeStream.on("finish", resolve2);
|
|
98
|
+
writeStream.on("error", reject);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async read(location, relativePath) {
|
|
103
|
+
return fs.promises.readFile(this.resolve(location, relativePath));
|
|
104
|
+
}
|
|
105
|
+
async exists(location, relativePath) {
|
|
106
|
+
try {
|
|
107
|
+
await fs.promises.access(this.resolve(location, relativePath));
|
|
108
|
+
return true;
|
|
109
|
+
} catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async list(location, prefix) {
|
|
114
|
+
const base = this.locationPaths.get(location);
|
|
115
|
+
if (!base) return [];
|
|
116
|
+
const dir = prefix ? path.join(base, prefix) : base;
|
|
117
|
+
try {
|
|
118
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
119
|
+
return entries.map((e) => prefix ? `${prefix}/${e.name}` : e.name);
|
|
120
|
+
} catch {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async delete(location, relativePath) {
|
|
125
|
+
const filePath = this.resolve(location, relativePath);
|
|
126
|
+
await fs.promises.rm(filePath, { force: true });
|
|
127
|
+
}
|
|
128
|
+
async getAvailableSpace(location) {
|
|
129
|
+
const base = this.locationPaths.get(location);
|
|
130
|
+
if (!base) return null;
|
|
131
|
+
try {
|
|
132
|
+
const stats = await fs.promises.statfs(base);
|
|
133
|
+
return stats.bavail * stats.bsize;
|
|
134
|
+
} catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async initialize() {
|
|
139
|
+
for (const [, dirPath] of this.locationPaths) {
|
|
140
|
+
await fs.promises.mkdir(dirPath, { recursive: true });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async shutdown() {
|
|
144
|
+
}
|
|
145
|
+
/** Get the resolved path for a location type */
|
|
146
|
+
getLocationPath(location) {
|
|
147
|
+
const p = this.locationPaths.get(location);
|
|
148
|
+
if (!p) throw new Error(`Unknown storage location: ${location}`);
|
|
149
|
+
return p;
|
|
150
|
+
}
|
|
151
|
+
/** Get the root path */
|
|
152
|
+
getRootPath() {
|
|
153
|
+
return this.rootPath;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/builtins/sqlite-storage/filesystem-storage.addon.ts
|
|
158
|
+
var FilesystemStorageAddon = class {
|
|
159
|
+
manifest = {
|
|
160
|
+
id: "filesystem-storage",
|
|
161
|
+
name: "Local Filesystem Storage",
|
|
162
|
+
version: "1.0.0",
|
|
163
|
+
capabilities: [{ name: "storage", mode: "collection" }]
|
|
164
|
+
};
|
|
165
|
+
provider = null;
|
|
166
|
+
currentConfig = {
|
|
167
|
+
rootPath: "camstack-data"
|
|
168
|
+
};
|
|
169
|
+
async initialize(context) {
|
|
170
|
+
const rootPath = context.addonConfig.rootPath ?? this.currentConfig.rootPath;
|
|
171
|
+
this.currentConfig.rootPath = rootPath;
|
|
172
|
+
const overrides = {};
|
|
173
|
+
for (const key of Object.keys(context.addonConfig)) {
|
|
174
|
+
if (key.startsWith("override.")) {
|
|
175
|
+
const loc = key.slice("override.".length);
|
|
176
|
+
overrides[loc] = context.addonConfig[key];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
this.provider = new FilesystemStorageProvider(rootPath, overrides);
|
|
180
|
+
await this.provider.initialize();
|
|
181
|
+
context.logger.info(`Filesystem storage initialized at ${this.provider.getRootPath()}`);
|
|
182
|
+
}
|
|
183
|
+
async shutdown() {
|
|
184
|
+
await this.provider?.shutdown();
|
|
185
|
+
}
|
|
186
|
+
getCapabilityProvider(name) {
|
|
187
|
+
if (name === "storage" && this.provider) {
|
|
188
|
+
return this.provider;
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
getProvider() {
|
|
193
|
+
return this.provider;
|
|
194
|
+
}
|
|
195
|
+
getConfigSchema() {
|
|
196
|
+
return { sections: [] };
|
|
197
|
+
}
|
|
198
|
+
getConfig() {
|
|
199
|
+
return { ...this.currentConfig };
|
|
200
|
+
}
|
|
201
|
+
async onConfigChange(config) {
|
|
202
|
+
this.currentConfig.rootPath = config.rootPath ?? this.currentConfig.rootPath;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
var filesystem_storage_addon_default = FilesystemStorageAddon;
|
|
206
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
207
|
+
0 && (module.exports = {
|
|
208
|
+
FilesystemStorageAddon
|
|
209
|
+
});
|
|
210
|
+
//# sourceMappingURL=filesystem-storage.addon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/builtins/sqlite-storage/filesystem-storage.addon.ts","../../../src/builtins/sqlite-storage/filesystem-storage-provider.ts"],"sourcesContent":["import type {\n ICamstackAddon,\n AddonManifest,\n AddonContext,\n IConfigurable,\n ConfigUISchema,\n CapabilityProviderMap,\n} from '@camstack/types'\nimport { FilesystemStorageProvider } from './filesystem-storage-provider'\n\n/**\n * Filesystem Storage addon — provides local disk storage for all location types.\n * Capability: 'storage' (collection)\n */\nexport class FilesystemStorageAddon implements ICamstackAddon, IConfigurable {\n readonly manifest: AddonManifest = {\n id: 'filesystem-storage',\n name: 'Local Filesystem Storage',\n version: '1.0.0',\n capabilities: [{ name: 'storage', mode: 'collection' }],\n }\n\n private provider: FilesystemStorageProvider | null = null\n private currentConfig = {\n rootPath: 'camstack-data',\n }\n\n async initialize(context: AddonContext): Promise<void> {\n const rootPath = (context.addonConfig.rootPath as string) ?? this.currentConfig.rootPath\n this.currentConfig.rootPath = rootPath\n\n // Read location overrides from config\n const overrides: Partial<Record<string, string>> = {}\n for (const key of Object.keys(context.addonConfig)) {\n if (key.startsWith('override.')) {\n const loc = key.slice('override.'.length)\n overrides[loc] = context.addonConfig[key] as string\n }\n }\n\n this.provider = new FilesystemStorageProvider(rootPath, overrides as any)\n await this.provider.initialize()\n context.logger.info(`Filesystem storage initialized at ${this.provider.getRootPath()}`)\n }\n\n async shutdown(): Promise<void> {\n await this.provider?.shutdown()\n }\n\n getCapabilityProvider<K extends keyof CapabilityProviderMap>(\n name: K,\n ): CapabilityProviderMap[K] | null {\n if (name === 'storage' && this.provider) {\n return this.provider as unknown as CapabilityProviderMap[K]\n }\n return null\n }\n\n getProvider(): FilesystemStorageProvider | null {\n return this.provider\n }\n\n getConfigSchema(): ConfigUISchema {\n return { sections: [] }\n }\n\n getConfig(): Record<string, unknown> {\n return { ...this.currentConfig }\n }\n\n async onConfigChange(config: Record<string, unknown>): Promise<void> {\n this.currentConfig.rootPath = (config.rootPath as string) ?? this.currentConfig.rootPath\n }\n}\n\nexport default FilesystemStorageAddon\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type {\n IStorageProvider as INewStorageProvider,\n StorageLocationType,\n} from '@camstack/types'\n\n// Inline constants to avoid runtime dependency on @camstack/types\n// (types is external in tsup bundle, may not be resolvable from data/addons/)\nconst STORAGE_LOCATION_TYPES: readonly StorageLocationType[] = [\n 'recordings-high', 'recordings-low', 'recordings-clips', 'event-images',\n 'models', 'addons-data', 'cache', 'logs',\n]\n\nconst DEFAULT_LOCATION_SUBDIRS: Readonly<Record<StorageLocationType, string>> = {\n 'recordings-high': 'recordings-high',\n 'recordings-low': 'recordings-low',\n 'recordings-clips': 'recordings-clips',\n 'event-images': 'event-images',\n 'models': 'models',\n 'addons-data': 'addons-data',\n 'cache': '/tmp/camstack-cache',\n 'logs': 'logs',\n}\n\n/**\n * Filesystem storage provider — serves all location types from a local directory tree.\n *\n * Default layout:\n * {rootPath}/recordings-high/\n * {rootPath}/recordings-low/\n * {rootPath}/recordings-clips/\n * {rootPath}/event-images/\n * {rootPath}/models/\n * {rootPath}/addons-data/\n * {rootPath}/logs/\n * /tmp/camstack-cache/ (cache is always local)\n *\n * Individual location paths can be overridden.\n */\nexport class FilesystemStorageProvider implements INewStorageProvider {\n readonly id = 'local'\n readonly name = 'Local Filesystem'\n readonly supportedLocations: readonly StorageLocationType[] = [...STORAGE_LOCATION_TYPES]\n\n private readonly rootPath: string\n private readonly locationPaths: Map<StorageLocationType, string>\n\n constructor(rootPath: string, overrides?: Partial<Record<StorageLocationType, string>>) {\n this.rootPath = path.resolve(rootPath)\n this.locationPaths = new Map()\n\n for (const loc of STORAGE_LOCATION_TYPES) {\n const override = overrides?.[loc]\n if (override) {\n this.locationPaths.set(loc, path.resolve(override))\n } else {\n const subdir = DEFAULT_LOCATION_SUBDIRS[loc]\n // Absolute paths (like /tmp/camstack-cache) are used as-is\n this.locationPaths.set(\n loc,\n path.isAbsolute(subdir) ? subdir : path.join(this.rootPath, subdir),\n )\n }\n }\n }\n\n resolve(location: StorageLocationType, relativePath: string): string {\n const base = this.locationPaths.get(location)\n if (!base) throw new Error(`Unknown storage location: ${location}`)\n return path.join(base, relativePath)\n }\n\n async write(location: StorageLocationType, relativePath: string, data: Buffer | NodeJS.ReadableStream): Promise<void> {\n const filePath = this.resolve(location, relativePath)\n await fs.promises.mkdir(path.dirname(filePath), { recursive: true })\n\n if (Buffer.isBuffer(data)) {\n await fs.promises.writeFile(filePath, data)\n } else {\n // Stream\n const writeStream = fs.createWriteStream(filePath)\n await new Promise<void>((resolve, reject) => {\n (data as NodeJS.ReadableStream).pipe(writeStream)\n writeStream.on('finish', resolve)\n writeStream.on('error', reject)\n })\n }\n }\n\n async read(location: StorageLocationType, relativePath: string): Promise<Buffer> {\n return fs.promises.readFile(this.resolve(location, relativePath))\n }\n\n async exists(location: StorageLocationType, relativePath: string): Promise<boolean> {\n try {\n await fs.promises.access(this.resolve(location, relativePath))\n return true\n } catch {\n return false\n }\n }\n\n async list(location: StorageLocationType, prefix?: string): Promise<readonly string[]> {\n const base = this.locationPaths.get(location)\n if (!base) return []\n const dir = prefix ? path.join(base, prefix) : base\n try {\n const entries = await fs.promises.readdir(dir, { withFileTypes: true })\n return entries.map(e => (prefix ? `${prefix}/${e.name}` : e.name))\n } catch {\n return []\n }\n }\n\n async delete(location: StorageLocationType, relativePath: string): Promise<void> {\n const filePath = this.resolve(location, relativePath)\n await fs.promises.rm(filePath, { force: true })\n }\n\n async getAvailableSpace(location: StorageLocationType): Promise<number | null> {\n const base = this.locationPaths.get(location)\n if (!base) return null\n try {\n const stats = await fs.promises.statfs(base)\n return stats.bavail * stats.bsize\n } catch {\n return null\n }\n }\n\n async initialize(): Promise<void> {\n for (const [, dirPath] of this.locationPaths) {\n await fs.promises.mkdir(dirPath, { recursive: true })\n }\n }\n\n async shutdown(): Promise<void> {\n // Nothing to clean up for filesystem\n }\n\n /** Get the resolved path for a location type */\n getLocationPath(location: StorageLocationType): string {\n const p = this.locationPaths.get(location)\n if (!p) throw new Error(`Unknown storage location: ${location}`)\n return p\n }\n\n /** Get the root path */\n getRootPath(): string {\n return this.rootPath\n }\n}\n\nexport default FilesystemStorageProvider\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAoB;AACpB,WAAsB;AAQtB,IAAM,yBAAyD;AAAA,EAC7D;AAAA,EAAmB;AAAA,EAAkB;AAAA,EAAoB;AAAA,EACzD;AAAA,EAAU;AAAA,EAAe;AAAA,EAAS;AACpC;AAEA,IAAM,2BAA0E;AAAA,EAC9E,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,eAAe;AAAA,EACf,SAAS;AAAA,EACT,QAAQ;AACV;AAiBO,IAAM,4BAAN,MAA+D;AAAA,EAC3D,KAAK;AAAA,EACL,OAAO;AAAA,EACP,qBAAqD,CAAC,GAAG,sBAAsB;AAAA,EAEvE;AAAA,EACA;AAAA,EAEjB,YAAY,UAAkB,WAA0D;AACtF,SAAK,WAAgB,aAAQ,QAAQ;AACrC,SAAK,gBAAgB,oBAAI,IAAI;AAE7B,eAAW,OAAO,wBAAwB;AACxC,YAAM,WAAW,YAAY,GAAG;AAChC,UAAI,UAAU;AACZ,aAAK,cAAc,IAAI,KAAU,aAAQ,QAAQ,CAAC;AAAA,MACpD,OAAO;AACL,cAAM,SAAS,yBAAyB,GAAG;AAE3C,aAAK,cAAc;AAAA,UACjB;AAAA,UACK,gBAAW,MAAM,IAAI,SAAc,UAAK,KAAK,UAAU,MAAM;AAAA,QACpE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,QAAQ,UAA+B,cAA8B;AACnE,UAAM,OAAO,KAAK,cAAc,IAAI,QAAQ;AAC5C,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,6BAA6B,QAAQ,EAAE;AAClE,WAAY,UAAK,MAAM,YAAY;AAAA,EACrC;AAAA,EAEA,MAAM,MAAM,UAA+B,cAAsB,MAAqD;AACpH,UAAM,WAAW,KAAK,QAAQ,UAAU,YAAY;AACpD,UAAS,YAAS,MAAW,aAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAEnE,QAAI,OAAO,SAAS,IAAI,GAAG;AACzB,YAAS,YAAS,UAAU,UAAU,IAAI;AAAA,IAC5C,OAAO;AAEL,YAAM,cAAiB,qBAAkB,QAAQ;AACjD,YAAM,IAAI,QAAc,CAACA,UAAS,WAAW;AAC3C,QAAC,KAA+B,KAAK,WAAW;AAChD,oBAAY,GAAG,UAAUA,QAAO;AAChC,oBAAY,GAAG,SAAS,MAAM;AAAA,MAChC,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,UAA+B,cAAuC;AAC/E,WAAU,YAAS,SAAS,KAAK,QAAQ,UAAU,YAAY,CAAC;AAAA,EAClE;AAAA,EAEA,MAAM,OAAO,UAA+B,cAAwC;AAClF,QAAI;AACF,YAAS,YAAS,OAAO,KAAK,QAAQ,UAAU,YAAY,CAAC;AAC7D,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,UAA+B,QAA6C;AACrF,UAAM,OAAO,KAAK,cAAc,IAAI,QAAQ;AAC5C,QAAI,CAAC,KAAM,QAAO,CAAC;AACnB,UAAM,MAAM,SAAc,UAAK,MAAM,MAAM,IAAI;AAC/C,QAAI;AACF,YAAM,UAAU,MAAS,YAAS,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;AACtE,aAAO,QAAQ,IAAI,OAAM,SAAS,GAAG,MAAM,IAAI,EAAE,IAAI,KAAK,EAAE,IAAK;AAAA,IACnE,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,UAA+B,cAAqC;AAC/E,UAAM,WAAW,KAAK,QAAQ,UAAU,YAAY;AACpD,UAAS,YAAS,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,EAChD;AAAA,EAEA,MAAM,kBAAkB,UAAuD;AAC7E,UAAM,OAAO,KAAK,cAAc,IAAI,QAAQ;AAC5C,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI;AACF,YAAM,QAAQ,MAAS,YAAS,OAAO,IAAI;AAC3C,aAAO,MAAM,SAAS,MAAM;AAAA,IAC9B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,aAA4B;AAChC,eAAW,CAAC,EAAE,OAAO,KAAK,KAAK,eAAe;AAC5C,YAAS,YAAS,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,IACtD;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAAA,EAEhC;AAAA;AAAA,EAGA,gBAAgB,UAAuC;AACrD,UAAM,IAAI,KAAK,cAAc,IAAI,QAAQ;AACzC,QAAI,CAAC,EAAG,OAAM,IAAI,MAAM,6BAA6B,QAAQ,EAAE;AAC/D,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AACF;;;AD1IO,IAAM,yBAAN,MAAsE;AAAA,EAClE,WAA0B;AAAA,IACjC,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,cAAc,CAAC,EAAE,MAAM,WAAW,MAAM,aAAa,CAAC;AAAA,EACxD;AAAA,EAEQ,WAA6C;AAAA,EAC7C,gBAAgB;AAAA,IACtB,UAAU;AAAA,EACZ;AAAA,EAEA,MAAM,WAAW,SAAsC;AACrD,UAAM,WAAY,QAAQ,YAAY,YAAuB,KAAK,cAAc;AAChF,SAAK,cAAc,WAAW;AAG9B,UAAM,YAA6C,CAAC;AACpD,eAAW,OAAO,OAAO,KAAK,QAAQ,WAAW,GAAG;AAClD,UAAI,IAAI,WAAW,WAAW,GAAG;AAC/B,cAAM,MAAM,IAAI,MAAM,YAAY,MAAM;AACxC,kBAAU,GAAG,IAAI,QAAQ,YAAY,GAAG;AAAA,MAC1C;AAAA,IACF;AAEA,SAAK,WAAW,IAAI,0BAA0B,UAAU,SAAgB;AACxE,UAAM,KAAK,SAAS,WAAW;AAC/B,YAAQ,OAAO,KAAK,qCAAqC,KAAK,SAAS,YAAY,CAAC,EAAE;AAAA,EACxF;AAAA,EAEA,MAAM,WAA0B;AAC9B,UAAM,KAAK,UAAU,SAAS;AAAA,EAChC;AAAA,EAEA,sBACE,MACiC;AACjC,QAAI,SAAS,aAAa,KAAK,UAAU;AACvC,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAAA,EAEA,cAAgD;AAC9C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,kBAAkC;AAChC,WAAO,EAAE,UAAU,CAAC,EAAE;AAAA,EACxB;AAAA,EAEA,YAAqC;AACnC,WAAO,EAAE,GAAG,KAAK,cAAc;AAAA,EACjC;AAAA,EAEA,MAAM,eAAe,QAAgD;AACnE,SAAK,cAAc,WAAY,OAAO,YAAuB,KAAK,cAAc;AAAA,EAClF;AACF;AAEA,IAAO,mCAAQ;","names":["resolve"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FilesystemStorageAddon,
|
|
3
|
+
filesystem_storage_addon_default
|
|
4
|
+
} from "../../chunk-SPA4JBKN.mjs";
|
|
5
|
+
import "../../chunk-QEMJH3KY.mjs";
|
|
6
|
+
export {
|
|
7
|
+
FilesystemStorageAddon,
|
|
8
|
+
filesystem_storage_addon_default as default
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=filesystem-storage.addon.mjs.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { F as FilesystemStorageAddon, a as FilesystemStorageProvider, F as default } from '../../filesystem-storage.addon-C42r589X.mjs';
|
|
2
|
+
export { S as SqliteSettingsAddon, a as SqliteSettingsBackend } from '../../sqlite-settings.addon-DigoKwpZ.mjs';
|
|
3
|
+
export { A as AddonTableSchema, C as CORE_TABLE_DDL, F as FileSystemStorage, S as SettingsStore, a as SqliteStorageAddon, b as SqliteStorageProvider, c as addonTableToDdl } from '../../sql-schema-CKz78rId.mjs';
|
|
4
|
+
import '@camstack/types';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { F as FilesystemStorageAddon, a as FilesystemStorageProvider, F as default } from '../../filesystem-storage.addon-C42r589X.js';
|
|
2
|
+
export { S as SqliteSettingsAddon, a as SqliteSettingsBackend } from '../../sqlite-settings.addon-DigoKwpZ.js';
|
|
3
|
+
export { A as AddonTableSchema, C as CORE_TABLE_DDL, F as FileSystemStorage, S as SettingsStore, a as SqliteStorageAddon, b as SqliteStorageProvider, c as addonTableToDdl } from '../../sql-schema-CKz78rId.js';
|
|
4
|
+
import '@camstack/types';
|