@gravito/nebula 1.0.0-alpha.6 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-TW.md +1 -1
- package/dist/index.cjs +116 -70
- package/dist/index.d.cts +96 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.js +162 -0
- package/package.json +11 -8
- package/dist/index.mjs +0 -117
package/README.md
CHANGED
package/README.zh-TW.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1,141 +1,187 @@
|
|
|
1
|
-
|
|
2
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
1
|
+
"use strict";
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
19
|
-
var __toCommonJS = (from) => {
|
|
20
|
-
var entry = __moduleCache.get(from), desc;
|
|
21
|
-
if (entry)
|
|
22
|
-
return entry;
|
|
23
|
-
entry = __defProp({}, "__esModule", { value: true });
|
|
24
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
25
|
-
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
26
|
-
get: () => from[key],
|
|
27
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
28
|
-
}));
|
|
29
|
-
__moduleCache.set(from, entry);
|
|
30
|
-
return entry;
|
|
31
|
-
};
|
|
32
6
|
var __export = (target, all) => {
|
|
33
7
|
for (var name in all)
|
|
34
|
-
__defProp(target, name, {
|
|
35
|
-
get: all[name],
|
|
36
|
-
enumerable: true,
|
|
37
|
-
configurable: true,
|
|
38
|
-
set: (newValue) => all[name] = () => newValue
|
|
39
|
-
});
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
40
9
|
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
41
19
|
|
|
42
20
|
// src/index.ts
|
|
43
|
-
var
|
|
44
|
-
__export(
|
|
45
|
-
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
LocalStorageProvider: () => LocalStorageProvider,
|
|
24
|
+
OrbitNebula: () => OrbitNebula,
|
|
46
25
|
OrbitStorage: () => OrbitStorage,
|
|
47
|
-
|
|
26
|
+
default: () => orbitStorage
|
|
48
27
|
});
|
|
49
|
-
module.exports = __toCommonJS(
|
|
50
|
-
var import_promises = require("
|
|
51
|
-
var import_node_path = require("
|
|
52
|
-
|
|
53
|
-
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
var import_promises = require("fs/promises");
|
|
30
|
+
var import_node_path = require("path");
|
|
31
|
+
var import_core = require("@gravito/core");
|
|
32
|
+
var LocalStorageProvider = class {
|
|
54
33
|
rootDir;
|
|
55
34
|
baseUrl;
|
|
35
|
+
runtime = (0, import_core.getRuntimeAdapter)();
|
|
36
|
+
/**
|
|
37
|
+
* Create a new LocalStorageProvider.
|
|
38
|
+
*
|
|
39
|
+
* @param rootDir - The root directory for storage.
|
|
40
|
+
* @param baseUrl - The base URL for accessing stored files.
|
|
41
|
+
*/
|
|
56
42
|
constructor(rootDir, baseUrl = "/storage") {
|
|
57
43
|
this.rootDir = rootDir;
|
|
58
44
|
this.baseUrl = baseUrl;
|
|
59
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Store data in a file.
|
|
48
|
+
*
|
|
49
|
+
* @param key - The storage key (path).
|
|
50
|
+
* @param data - The data to store.
|
|
51
|
+
*/
|
|
60
52
|
async put(key, data) {
|
|
61
|
-
const path =
|
|
53
|
+
const path = this.resolveKeyPath(key);
|
|
62
54
|
const dir = path.substring(0, path.lastIndexOf("/"));
|
|
63
55
|
if (dir && dir !== this.rootDir) {
|
|
64
|
-
await import_promises.mkdir(dir, { recursive: true });
|
|
56
|
+
await (0, import_promises.mkdir)(dir, { recursive: true });
|
|
65
57
|
}
|
|
66
|
-
await
|
|
58
|
+
await this.runtime.writeFile(path, data);
|
|
67
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Retrieve a file.
|
|
62
|
+
*
|
|
63
|
+
* @param key - The storage key.
|
|
64
|
+
* @returns A promise resolving to the file Blob or null if not found.
|
|
65
|
+
*/
|
|
68
66
|
async get(key) {
|
|
69
|
-
const
|
|
70
|
-
if (!await
|
|
67
|
+
const path = this.resolveKeyPath(key);
|
|
68
|
+
if (!await this.runtime.exists(path)) {
|
|
71
69
|
return null;
|
|
72
70
|
}
|
|
73
|
-
return
|
|
71
|
+
return await this.runtime.readFileAsBlob(path);
|
|
74
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Delete a file.
|
|
75
|
+
*
|
|
76
|
+
* @param key - The storage key.
|
|
77
|
+
*/
|
|
75
78
|
async delete(key) {
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
await fs.unlink(import_node_path.join(this.rootDir, key));
|
|
79
|
-
} catch {}
|
|
79
|
+
await this.runtime.deleteFile(this.resolveKeyPath(key));
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Get the public URL for a file.
|
|
83
|
+
*
|
|
84
|
+
* @param key - The storage key.
|
|
85
|
+
* @returns The public URL string.
|
|
86
|
+
*/
|
|
81
87
|
getUrl(key) {
|
|
82
|
-
|
|
88
|
+
const safeKey = this.normalizeKey(key);
|
|
89
|
+
return `${this.baseUrl}/${safeKey}`;
|
|
83
90
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
normalizeKey(key) {
|
|
92
|
+
if (!key || key.includes("\0")) {
|
|
93
|
+
throw new Error("Invalid storage key.");
|
|
94
|
+
}
|
|
95
|
+
const normalized = (0, import_node_path.normalize)(key).replace(/^[/\\]+/, "");
|
|
96
|
+
if (normalized === "." || normalized === ".." || normalized.startsWith(`..${import_node_path.sep}`) || (0, import_node_path.isAbsolute)(normalized)) {
|
|
97
|
+
throw new Error("Invalid storage key.");
|
|
98
|
+
}
|
|
99
|
+
return normalized.replace(/\\/g, "/");
|
|
100
|
+
}
|
|
101
|
+
resolveKeyPath(key) {
|
|
102
|
+
const normalized = this.normalizeKey(key);
|
|
103
|
+
const root = (0, import_node_path.resolve)(this.rootDir);
|
|
104
|
+
const resolved = (0, import_node_path.resolve)(root, normalized);
|
|
105
|
+
const rootPrefix = root.endsWith(import_node_path.sep) ? root : `${root}${import_node_path.sep}`;
|
|
106
|
+
if (!resolved.startsWith(rootPrefix) && resolved !== root) {
|
|
107
|
+
throw new Error("Invalid storage key.");
|
|
108
|
+
}
|
|
109
|
+
return resolved;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
var OrbitNebula = class {
|
|
88
113
|
constructor(options) {
|
|
89
114
|
this.options = options;
|
|
90
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Install storage service into PlanetCore.
|
|
118
|
+
*
|
|
119
|
+
* @param core - The PlanetCore instance.
|
|
120
|
+
* @throws {Error} If configuration or provider is missing.
|
|
121
|
+
*/
|
|
91
122
|
install(core) {
|
|
92
123
|
const config = this.options || core.config.get("storage");
|
|
93
124
|
if (!config) {
|
|
94
|
-
throw new Error(
|
|
125
|
+
throw new Error(
|
|
126
|
+
'[OrbitNebula] Configuration is required. Please provide options or set "storage" in core config.'
|
|
127
|
+
);
|
|
95
128
|
}
|
|
96
129
|
const { exposeAs = "storage" } = config;
|
|
97
130
|
const logger = core.logger;
|
|
98
|
-
logger.info(`[
|
|
131
|
+
logger.info(`[OrbitNebula] Initializing Storage (Exposed as: ${exposeAs})`);
|
|
99
132
|
let provider = config.provider;
|
|
100
133
|
if (!provider && config.local) {
|
|
101
|
-
logger.info(`[
|
|
134
|
+
logger.info(`[OrbitNebula] Using LocalStorageProvider at ${config.local.root}`);
|
|
102
135
|
provider = new LocalStorageProvider(config.local.root, config.local.baseUrl);
|
|
103
136
|
}
|
|
104
137
|
if (!provider) {
|
|
105
|
-
throw new Error(
|
|
138
|
+
throw new Error(
|
|
139
|
+
"[OrbitNebula] No provider configured. Please provide a provider instance or local configuration."
|
|
140
|
+
);
|
|
106
141
|
}
|
|
107
142
|
const storageService = {
|
|
108
|
-
...provider,
|
|
109
143
|
put: async (key, data) => {
|
|
110
144
|
const finalData = await core.hooks.applyFilters("storage:upload", data, { key });
|
|
111
145
|
await provider?.put(key, finalData);
|
|
112
146
|
await core.hooks.doAction("storage:uploaded", { key });
|
|
113
|
-
}
|
|
147
|
+
},
|
|
148
|
+
get: (key) => provider?.get(key),
|
|
149
|
+
delete: (key) => provider?.delete(key),
|
|
150
|
+
getUrl: (key) => provider?.getUrl(key)
|
|
114
151
|
};
|
|
115
152
|
core.adapter.use("*", async (c, next) => {
|
|
116
153
|
c.set(exposeAs, storageService);
|
|
117
154
|
await next();
|
|
118
|
-
return;
|
|
155
|
+
return void 0;
|
|
119
156
|
});
|
|
120
157
|
core.hooks.doAction("storage:init", storageService);
|
|
121
158
|
}
|
|
122
|
-
}
|
|
159
|
+
};
|
|
123
160
|
function orbitStorage(core, options) {
|
|
124
|
-
const orbit = new
|
|
161
|
+
const orbit = new OrbitNebula(options);
|
|
125
162
|
orbit.install(core);
|
|
126
163
|
let provider = options.provider;
|
|
127
164
|
if (!provider && options.local) {
|
|
128
165
|
provider = new LocalStorageProvider(options.local.root, options.local.baseUrl);
|
|
129
166
|
}
|
|
130
167
|
if (!provider) {
|
|
131
|
-
throw new Error("[
|
|
168
|
+
throw new Error("[OrbitNebula] No provider configured.");
|
|
132
169
|
}
|
|
133
170
|
return {
|
|
134
|
-
...provider,
|
|
135
171
|
put: async (key, data) => {
|
|
136
172
|
const finalData = await core.hooks.applyFilters("storage:upload", data, { key });
|
|
137
173
|
await provider?.put(key, finalData);
|
|
138
174
|
await core.hooks.doAction("storage:uploaded", { key });
|
|
139
|
-
}
|
|
175
|
+
},
|
|
176
|
+
get: (key) => provider?.get(key),
|
|
177
|
+
delete: (key) => provider?.delete(key),
|
|
178
|
+
getUrl: (key) => provider?.getUrl(key)
|
|
140
179
|
};
|
|
141
180
|
}
|
|
181
|
+
var OrbitStorage = OrbitNebula;
|
|
182
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
183
|
+
0 && (module.exports = {
|
|
184
|
+
LocalStorageProvider,
|
|
185
|
+
OrbitNebula,
|
|
186
|
+
OrbitStorage
|
|
187
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { PlanetCore, GravitoOrbit } from '@gravito/core';
|
|
2
|
+
|
|
3
|
+
interface StorageProvider {
|
|
4
|
+
put(key: string, data: Blob | Buffer | string): Promise<void>;
|
|
5
|
+
get(key: string): Promise<Blob | null>;
|
|
6
|
+
delete(key: string): Promise<void>;
|
|
7
|
+
getUrl(key: string): string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Local storage provider implementation.
|
|
11
|
+
*/
|
|
12
|
+
declare class LocalStorageProvider implements StorageProvider {
|
|
13
|
+
private rootDir;
|
|
14
|
+
private baseUrl;
|
|
15
|
+
private runtime;
|
|
16
|
+
/**
|
|
17
|
+
* Create a new LocalStorageProvider.
|
|
18
|
+
*
|
|
19
|
+
* @param rootDir - The root directory for storage.
|
|
20
|
+
* @param baseUrl - The base URL for accessing stored files.
|
|
21
|
+
*/
|
|
22
|
+
constructor(rootDir: string, baseUrl?: string);
|
|
23
|
+
/**
|
|
24
|
+
* Store data in a file.
|
|
25
|
+
*
|
|
26
|
+
* @param key - The storage key (path).
|
|
27
|
+
* @param data - The data to store.
|
|
28
|
+
*/
|
|
29
|
+
put(key: string, data: Blob | Buffer | string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Retrieve a file.
|
|
32
|
+
*
|
|
33
|
+
* @param key - The storage key.
|
|
34
|
+
* @returns A promise resolving to the file Blob or null if not found.
|
|
35
|
+
*/
|
|
36
|
+
get(key: string): Promise<Blob | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Delete a file.
|
|
39
|
+
*
|
|
40
|
+
* @param key - The storage key.
|
|
41
|
+
*/
|
|
42
|
+
delete(key: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Get the public URL for a file.
|
|
45
|
+
*
|
|
46
|
+
* @param key - The storage key.
|
|
47
|
+
* @returns The public URL string.
|
|
48
|
+
*/
|
|
49
|
+
getUrl(key: string): string;
|
|
50
|
+
private normalizeKey;
|
|
51
|
+
private resolveKeyPath;
|
|
52
|
+
}
|
|
53
|
+
interface OrbitNebulaOptions {
|
|
54
|
+
provider?: StorageProvider;
|
|
55
|
+
exposeAs?: string;
|
|
56
|
+
local?: {
|
|
57
|
+
root: string;
|
|
58
|
+
baseUrl?: string;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** @deprecated Use OrbitNebulaOptions instead */
|
|
62
|
+
type OrbitStorageOptions = OrbitNebulaOptions;
|
|
63
|
+
/**
|
|
64
|
+
* OrbitNebula - Storage Orbit
|
|
65
|
+
*
|
|
66
|
+
* Provides file storage functionality for Gravito applications.
|
|
67
|
+
*/
|
|
68
|
+
declare class OrbitNebula implements GravitoOrbit {
|
|
69
|
+
private options?;
|
|
70
|
+
constructor(options?: OrbitNebulaOptions | undefined);
|
|
71
|
+
/**
|
|
72
|
+
* Install storage service into PlanetCore.
|
|
73
|
+
*
|
|
74
|
+
* @param core - The PlanetCore instance.
|
|
75
|
+
* @throws {Error} If configuration or provider is missing.
|
|
76
|
+
*/
|
|
77
|
+
install(core: PlanetCore): void;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Functional API for installing OrbitNebula.
|
|
81
|
+
*
|
|
82
|
+
* @param core - The PlanetCore instance.
|
|
83
|
+
* @param options - Storage options.
|
|
84
|
+
* @returns The configured storage provider wrapper.
|
|
85
|
+
* @throws {Error} If provider is not configured.
|
|
86
|
+
*/
|
|
87
|
+
declare function orbitStorage(core: PlanetCore, options: OrbitNebulaOptions): {
|
|
88
|
+
put: (key: string, data: Blob | Buffer | string) => Promise<void>;
|
|
89
|
+
get: (key: string) => Promise<Blob | null>;
|
|
90
|
+
delete: (key: string) => Promise<void>;
|
|
91
|
+
getUrl: (key: string) => string;
|
|
92
|
+
};
|
|
93
|
+
/** @deprecated Use OrbitNebula instead */
|
|
94
|
+
declare const OrbitStorage: typeof OrbitNebula;
|
|
95
|
+
|
|
96
|
+
export { LocalStorageProvider, OrbitNebula, type OrbitNebulaOptions, OrbitStorage, type OrbitStorageOptions, type StorageProvider, orbitStorage as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { PlanetCore, GravitoOrbit } from '@gravito/core';
|
|
2
|
+
|
|
3
|
+
interface StorageProvider {
|
|
4
|
+
put(key: string, data: Blob | Buffer | string): Promise<void>;
|
|
5
|
+
get(key: string): Promise<Blob | null>;
|
|
6
|
+
delete(key: string): Promise<void>;
|
|
7
|
+
getUrl(key: string): string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Local storage provider implementation.
|
|
11
|
+
*/
|
|
12
|
+
declare class LocalStorageProvider implements StorageProvider {
|
|
13
|
+
private rootDir;
|
|
14
|
+
private baseUrl;
|
|
15
|
+
private runtime;
|
|
16
|
+
/**
|
|
17
|
+
* Create a new LocalStorageProvider.
|
|
18
|
+
*
|
|
19
|
+
* @param rootDir - The root directory for storage.
|
|
20
|
+
* @param baseUrl - The base URL for accessing stored files.
|
|
21
|
+
*/
|
|
22
|
+
constructor(rootDir: string, baseUrl?: string);
|
|
23
|
+
/**
|
|
24
|
+
* Store data in a file.
|
|
25
|
+
*
|
|
26
|
+
* @param key - The storage key (path).
|
|
27
|
+
* @param data - The data to store.
|
|
28
|
+
*/
|
|
29
|
+
put(key: string, data: Blob | Buffer | string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Retrieve a file.
|
|
32
|
+
*
|
|
33
|
+
* @param key - The storage key.
|
|
34
|
+
* @returns A promise resolving to the file Blob or null if not found.
|
|
35
|
+
*/
|
|
36
|
+
get(key: string): Promise<Blob | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Delete a file.
|
|
39
|
+
*
|
|
40
|
+
* @param key - The storage key.
|
|
41
|
+
*/
|
|
42
|
+
delete(key: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Get the public URL for a file.
|
|
45
|
+
*
|
|
46
|
+
* @param key - The storage key.
|
|
47
|
+
* @returns The public URL string.
|
|
48
|
+
*/
|
|
49
|
+
getUrl(key: string): string;
|
|
50
|
+
private normalizeKey;
|
|
51
|
+
private resolveKeyPath;
|
|
52
|
+
}
|
|
53
|
+
interface OrbitNebulaOptions {
|
|
54
|
+
provider?: StorageProvider;
|
|
55
|
+
exposeAs?: string;
|
|
56
|
+
local?: {
|
|
57
|
+
root: string;
|
|
58
|
+
baseUrl?: string;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** @deprecated Use OrbitNebulaOptions instead */
|
|
62
|
+
type OrbitStorageOptions = OrbitNebulaOptions;
|
|
63
|
+
/**
|
|
64
|
+
* OrbitNebula - Storage Orbit
|
|
65
|
+
*
|
|
66
|
+
* Provides file storage functionality for Gravito applications.
|
|
67
|
+
*/
|
|
68
|
+
declare class OrbitNebula implements GravitoOrbit {
|
|
69
|
+
private options?;
|
|
70
|
+
constructor(options?: OrbitNebulaOptions | undefined);
|
|
71
|
+
/**
|
|
72
|
+
* Install storage service into PlanetCore.
|
|
73
|
+
*
|
|
74
|
+
* @param core - The PlanetCore instance.
|
|
75
|
+
* @throws {Error} If configuration or provider is missing.
|
|
76
|
+
*/
|
|
77
|
+
install(core: PlanetCore): void;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Functional API for installing OrbitNebula.
|
|
81
|
+
*
|
|
82
|
+
* @param core - The PlanetCore instance.
|
|
83
|
+
* @param options - Storage options.
|
|
84
|
+
* @returns The configured storage provider wrapper.
|
|
85
|
+
* @throws {Error} If provider is not configured.
|
|
86
|
+
*/
|
|
87
|
+
declare function orbitStorage(core: PlanetCore, options: OrbitNebulaOptions): {
|
|
88
|
+
put: (key: string, data: Blob | Buffer | string) => Promise<void>;
|
|
89
|
+
get: (key: string) => Promise<Blob | null>;
|
|
90
|
+
delete: (key: string) => Promise<void>;
|
|
91
|
+
getUrl: (key: string) => string;
|
|
92
|
+
};
|
|
93
|
+
/** @deprecated Use OrbitNebula instead */
|
|
94
|
+
declare const OrbitStorage: typeof OrbitNebula;
|
|
95
|
+
|
|
96
|
+
export { LocalStorageProvider, OrbitNebula, type OrbitNebulaOptions, OrbitStorage, type OrbitStorageOptions, type StorageProvider, orbitStorage as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { mkdir } from "fs/promises";
|
|
3
|
+
import { isAbsolute, normalize, resolve, sep } from "path";
|
|
4
|
+
import {
|
|
5
|
+
getRuntimeAdapter
|
|
6
|
+
} from "@gravito/core";
|
|
7
|
+
var LocalStorageProvider = class {
|
|
8
|
+
rootDir;
|
|
9
|
+
baseUrl;
|
|
10
|
+
runtime = getRuntimeAdapter();
|
|
11
|
+
/**
|
|
12
|
+
* Create a new LocalStorageProvider.
|
|
13
|
+
*
|
|
14
|
+
* @param rootDir - The root directory for storage.
|
|
15
|
+
* @param baseUrl - The base URL for accessing stored files.
|
|
16
|
+
*/
|
|
17
|
+
constructor(rootDir, baseUrl = "/storage") {
|
|
18
|
+
this.rootDir = rootDir;
|
|
19
|
+
this.baseUrl = baseUrl;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Store data in a file.
|
|
23
|
+
*
|
|
24
|
+
* @param key - The storage key (path).
|
|
25
|
+
* @param data - The data to store.
|
|
26
|
+
*/
|
|
27
|
+
async put(key, data) {
|
|
28
|
+
const path = this.resolveKeyPath(key);
|
|
29
|
+
const dir = path.substring(0, path.lastIndexOf("/"));
|
|
30
|
+
if (dir && dir !== this.rootDir) {
|
|
31
|
+
await mkdir(dir, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
await this.runtime.writeFile(path, data);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Retrieve a file.
|
|
37
|
+
*
|
|
38
|
+
* @param key - The storage key.
|
|
39
|
+
* @returns A promise resolving to the file Blob or null if not found.
|
|
40
|
+
*/
|
|
41
|
+
async get(key) {
|
|
42
|
+
const path = this.resolveKeyPath(key);
|
|
43
|
+
if (!await this.runtime.exists(path)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return await this.runtime.readFileAsBlob(path);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Delete a file.
|
|
50
|
+
*
|
|
51
|
+
* @param key - The storage key.
|
|
52
|
+
*/
|
|
53
|
+
async delete(key) {
|
|
54
|
+
await this.runtime.deleteFile(this.resolveKeyPath(key));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get the public URL for a file.
|
|
58
|
+
*
|
|
59
|
+
* @param key - The storage key.
|
|
60
|
+
* @returns The public URL string.
|
|
61
|
+
*/
|
|
62
|
+
getUrl(key) {
|
|
63
|
+
const safeKey = this.normalizeKey(key);
|
|
64
|
+
return `${this.baseUrl}/${safeKey}`;
|
|
65
|
+
}
|
|
66
|
+
normalizeKey(key) {
|
|
67
|
+
if (!key || key.includes("\0")) {
|
|
68
|
+
throw new Error("Invalid storage key.");
|
|
69
|
+
}
|
|
70
|
+
const normalized = normalize(key).replace(/^[/\\]+/, "");
|
|
71
|
+
if (normalized === "." || normalized === ".." || normalized.startsWith(`..${sep}`) || isAbsolute(normalized)) {
|
|
72
|
+
throw new Error("Invalid storage key.");
|
|
73
|
+
}
|
|
74
|
+
return normalized.replace(/\\/g, "/");
|
|
75
|
+
}
|
|
76
|
+
resolveKeyPath(key) {
|
|
77
|
+
const normalized = this.normalizeKey(key);
|
|
78
|
+
const root = resolve(this.rootDir);
|
|
79
|
+
const resolved = resolve(root, normalized);
|
|
80
|
+
const rootPrefix = root.endsWith(sep) ? root : `${root}${sep}`;
|
|
81
|
+
if (!resolved.startsWith(rootPrefix) && resolved !== root) {
|
|
82
|
+
throw new Error("Invalid storage key.");
|
|
83
|
+
}
|
|
84
|
+
return resolved;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var OrbitNebula = class {
|
|
88
|
+
constructor(options) {
|
|
89
|
+
this.options = options;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Install storage service into PlanetCore.
|
|
93
|
+
*
|
|
94
|
+
* @param core - The PlanetCore instance.
|
|
95
|
+
* @throws {Error} If configuration or provider is missing.
|
|
96
|
+
*/
|
|
97
|
+
install(core) {
|
|
98
|
+
const config = this.options || core.config.get("storage");
|
|
99
|
+
if (!config) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
'[OrbitNebula] Configuration is required. Please provide options or set "storage" in core config.'
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const { exposeAs = "storage" } = config;
|
|
105
|
+
const logger = core.logger;
|
|
106
|
+
logger.info(`[OrbitNebula] Initializing Storage (Exposed as: ${exposeAs})`);
|
|
107
|
+
let provider = config.provider;
|
|
108
|
+
if (!provider && config.local) {
|
|
109
|
+
logger.info(`[OrbitNebula] Using LocalStorageProvider at ${config.local.root}`);
|
|
110
|
+
provider = new LocalStorageProvider(config.local.root, config.local.baseUrl);
|
|
111
|
+
}
|
|
112
|
+
if (!provider) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
"[OrbitNebula] No provider configured. Please provide a provider instance or local configuration."
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
const storageService = {
|
|
118
|
+
put: async (key, data) => {
|
|
119
|
+
const finalData = await core.hooks.applyFilters("storage:upload", data, { key });
|
|
120
|
+
await provider?.put(key, finalData);
|
|
121
|
+
await core.hooks.doAction("storage:uploaded", { key });
|
|
122
|
+
},
|
|
123
|
+
get: (key) => provider?.get(key),
|
|
124
|
+
delete: (key) => provider?.delete(key),
|
|
125
|
+
getUrl: (key) => provider?.getUrl(key)
|
|
126
|
+
};
|
|
127
|
+
core.adapter.use("*", async (c, next) => {
|
|
128
|
+
c.set(exposeAs, storageService);
|
|
129
|
+
await next();
|
|
130
|
+
return void 0;
|
|
131
|
+
});
|
|
132
|
+
core.hooks.doAction("storage:init", storageService);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function orbitStorage(core, options) {
|
|
136
|
+
const orbit = new OrbitNebula(options);
|
|
137
|
+
orbit.install(core);
|
|
138
|
+
let provider = options.provider;
|
|
139
|
+
if (!provider && options.local) {
|
|
140
|
+
provider = new LocalStorageProvider(options.local.root, options.local.baseUrl);
|
|
141
|
+
}
|
|
142
|
+
if (!provider) {
|
|
143
|
+
throw new Error("[OrbitNebula] No provider configured.");
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
put: async (key, data) => {
|
|
147
|
+
const finalData = await core.hooks.applyFilters("storage:upload", data, { key });
|
|
148
|
+
await provider?.put(key, finalData);
|
|
149
|
+
await core.hooks.doAction("storage:uploaded", { key });
|
|
150
|
+
},
|
|
151
|
+
get: (key) => provider?.get(key),
|
|
152
|
+
delete: (key) => provider?.delete(key),
|
|
153
|
+
getUrl: (key) => provider?.getUrl(key)
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
var OrbitStorage = OrbitNebula;
|
|
157
|
+
export {
|
|
158
|
+
LocalStorageProvider,
|
|
159
|
+
OrbitNebula,
|
|
160
|
+
OrbitStorage,
|
|
161
|
+
orbitStorage as default
|
|
162
|
+
};
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravito/nebula",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
7
|
"description": "Standard Storage Orbit for Galaxy Architecture",
|
|
8
|
-
"module": "./dist/index.mjs",
|
|
9
8
|
"main": "./dist/index.cjs",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
10
|
"type": "module",
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
|
-
"import": "./dist/index.
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
16
|
"require": "./dist/index.cjs"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "bun run build.ts",
|
|
26
26
|
"test": "bun test",
|
|
27
|
-
"typecheck": "tsc --noEmit"
|
|
27
|
+
"typecheck": "bun tsc -p tsconfig.json --noEmit --skipLibCheck",
|
|
28
|
+
"test:coverage": "bun test --coverage --coverage-threshold=80",
|
|
29
|
+
"test:ci": "bun test --coverage --coverage-threshold=80"
|
|
28
30
|
},
|
|
29
31
|
"keywords": [
|
|
30
32
|
"gravito",
|
|
@@ -35,12 +37,13 @@
|
|
|
35
37
|
"author": "Carl Lee <carllee0520@gmail.com>",
|
|
36
38
|
"license": "MIT",
|
|
37
39
|
"peerDependencies": {
|
|
38
|
-
"gravito
|
|
40
|
+
"@gravito/core": "workspace:*"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
|
-
"gravito-core": "1.0.0-beta.5",
|
|
42
|
-
"hono": "^4.11.1",
|
|
43
43
|
"bun-types": "latest",
|
|
44
|
+
"@gravito/core": "workspace:*",
|
|
45
|
+
"@gravito/photon": "workspace:*",
|
|
46
|
+
"tsup": "^8.5.1",
|
|
44
47
|
"typescript": "^5.9.3"
|
|
45
48
|
},
|
|
46
49
|
"homepage": "https://github.com/gravito-framework/gravito#readme",
|
|
@@ -49,4 +52,4 @@
|
|
|
49
52
|
"url": "git+https://github.com/gravito-framework/gravito.git",
|
|
50
53
|
"directory": "packages/nebula"
|
|
51
54
|
}
|
|
52
|
-
}
|
|
55
|
+
}
|
package/dist/index.mjs
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
import { mkdir } from "node:fs/promises";
|
|
22
|
-
import { join } from "node:path";
|
|
23
|
-
|
|
24
|
-
class LocalStorageProvider {
|
|
25
|
-
rootDir;
|
|
26
|
-
baseUrl;
|
|
27
|
-
constructor(rootDir, baseUrl = "/storage") {
|
|
28
|
-
this.rootDir = rootDir;
|
|
29
|
-
this.baseUrl = baseUrl;
|
|
30
|
-
}
|
|
31
|
-
async put(key, data) {
|
|
32
|
-
const path = join(this.rootDir, key);
|
|
33
|
-
const dir = path.substring(0, path.lastIndexOf("/"));
|
|
34
|
-
if (dir && dir !== this.rootDir) {
|
|
35
|
-
await mkdir(dir, { recursive: true });
|
|
36
|
-
}
|
|
37
|
-
await Bun.write(path, data);
|
|
38
|
-
}
|
|
39
|
-
async get(key) {
|
|
40
|
-
const file = Bun.file(join(this.rootDir, key));
|
|
41
|
-
if (!await file.exists()) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
return file;
|
|
45
|
-
}
|
|
46
|
-
async delete(key) {
|
|
47
|
-
const fs = await import("node:fs/promises");
|
|
48
|
-
try {
|
|
49
|
-
await fs.unlink(join(this.rootDir, key));
|
|
50
|
-
} catch {}
|
|
51
|
-
}
|
|
52
|
-
getUrl(key) {
|
|
53
|
-
return `${this.baseUrl}/${key}`;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
class OrbitStorage {
|
|
58
|
-
options;
|
|
59
|
-
constructor(options) {
|
|
60
|
-
this.options = options;
|
|
61
|
-
}
|
|
62
|
-
install(core) {
|
|
63
|
-
const config = this.options || core.config.get("storage");
|
|
64
|
-
if (!config) {
|
|
65
|
-
throw new Error('[OrbitStorage] Configuration is required. Please provide options or set "storage" in core config.');
|
|
66
|
-
}
|
|
67
|
-
const { exposeAs = "storage" } = config;
|
|
68
|
-
const logger = core.logger;
|
|
69
|
-
logger.info(`[OrbitStorage] Initializing Storage (Exposed as: ${exposeAs})`);
|
|
70
|
-
let provider = config.provider;
|
|
71
|
-
if (!provider && config.local) {
|
|
72
|
-
logger.info(`[OrbitStorage] Using LocalStorageProvider at ${config.local.root}`);
|
|
73
|
-
provider = new LocalStorageProvider(config.local.root, config.local.baseUrl);
|
|
74
|
-
}
|
|
75
|
-
if (!provider) {
|
|
76
|
-
throw new Error("[OrbitStorage] No provider configured. Please provide a provider instance or local configuration.");
|
|
77
|
-
}
|
|
78
|
-
const storageService = {
|
|
79
|
-
...provider,
|
|
80
|
-
put: async (key, data) => {
|
|
81
|
-
const finalData = await core.hooks.applyFilters("storage:upload", data, { key });
|
|
82
|
-
await provider?.put(key, finalData);
|
|
83
|
-
await core.hooks.doAction("storage:uploaded", { key });
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
core.adapter.use("*", async (c, next) => {
|
|
87
|
-
c.set(exposeAs, storageService);
|
|
88
|
-
await next();
|
|
89
|
-
return;
|
|
90
|
-
});
|
|
91
|
-
core.hooks.doAction("storage:init", storageService);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
function orbitStorage(core, options) {
|
|
95
|
-
const orbit = new OrbitStorage(options);
|
|
96
|
-
orbit.install(core);
|
|
97
|
-
let provider = options.provider;
|
|
98
|
-
if (!provider && options.local) {
|
|
99
|
-
provider = new LocalStorageProvider(options.local.root, options.local.baseUrl);
|
|
100
|
-
}
|
|
101
|
-
if (!provider) {
|
|
102
|
-
throw new Error("[OrbitStorage] No provider configured.");
|
|
103
|
-
}
|
|
104
|
-
return {
|
|
105
|
-
...provider,
|
|
106
|
-
put: async (key, data) => {
|
|
107
|
-
const finalData = await core.hooks.applyFilters("storage:upload", data, { key });
|
|
108
|
-
await provider?.put(key, finalData);
|
|
109
|
-
await core.hooks.doAction("storage:uploaded", { key });
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
export {
|
|
114
|
-
orbitStorage as default,
|
|
115
|
-
OrbitStorage,
|
|
116
|
-
LocalStorageProvider
|
|
117
|
-
};
|