@inflector/aura 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAS,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAIjE,cAAM,WAAW,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAQ;IACnB,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,SAAS,CAAQ;gBAEb,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAMxD,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wvBAUF;IACD,MAAM;;ovBAUL;IACD,MAAM;;wvBAUL;IACD,GAAG,GAAI,QAAQ,QAAQ,CAAC,IAAI,CAAC,gvBAa5B;IACD,OAAO,GAAI,QAAQ,QAAQ,CAAC,IAAI,CAAC,EAAE,gvBAalC;IACD,MAAM,GAAI,QAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;;wvBAUpC;IACD,KAAK;;4BAUJ;IACD,KAAK;;6BAUJ;IACD,SAAS,GAAI,UAAU,CAAC,CAAC,CAAC,EAAC;QAAC,MAAM,EAAC,MAAM,CAAC;QAAA,IAAI,EAAC,GAAG,CAAA;KAAC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAC;QAAC,MAAM,EAAC,MAAM,CAAC;QAAA,IAAI,EAAC,GAAG,CAAA;KAAC,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,gBAO5G;CACJ;AAED,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,EACzE,KAAK,MAAM,EACX,WAAW,MAAM,EACjB,QAAQ,CAAC,QAEe,CAAC,kCAY5B,CAAA"}
@@ -0,0 +1,100 @@
1
+ import { createFluentBuilder } from "./fluent";
2
+ import axios from "axios";
3
+ class RemoteTable {
4
+ URL;
5
+ Name;
6
+ WorkSpace;
7
+ constructor(url, name, workspace) {
8
+ this.URL = url;
9
+ this.Name = name;
10
+ this.WorkSpace = workspace;
11
+ }
12
+ Get = () => {
13
+ return createFluentBuilder(async (data) => {
14
+ return (await axios.post(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`, {
15
+ operation: 'Get',
16
+ settings: data,
17
+ })).data;
18
+ });
19
+ };
20
+ GetOne = () => {
21
+ return createFluentBuilder(async (data) => {
22
+ return (await axios.post(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`, {
23
+ operation: 'GetOne',
24
+ settings: data,
25
+ })).data;
26
+ });
27
+ };
28
+ Delete = () => {
29
+ return createFluentBuilder(async (data) => {
30
+ return (await axios.post(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`, {
31
+ operation: 'Delete',
32
+ settings: { ...data, returning: true },
33
+ })).data;
34
+ });
35
+ };
36
+ Add = (record) => {
37
+ return createFluentBuilder(async () => {
38
+ return (await axios.post(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`, {
39
+ operation: 'Add',
40
+ settings: {
41
+ returning: true
42
+ },
43
+ data: record
44
+ })).data;
45
+ });
46
+ };
47
+ AddMany = (record) => {
48
+ return createFluentBuilder(async () => {
49
+ return (await axios.post(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`, {
50
+ operation: 'AddMany',
51
+ settings: {
52
+ returning: true
53
+ },
54
+ data: record
55
+ })).data;
56
+ });
57
+ };
58
+ Update = (record) => {
59
+ return createFluentBuilder(async (data) => {
60
+ return (await axios.post(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`, {
61
+ operation: 'Update',
62
+ settings: { ...data, returning: true },
63
+ })).data;
64
+ });
65
+ };
66
+ Count = () => {
67
+ return createFluentBuilder(async (data) => {
68
+ return (await axios.post(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`, {
69
+ operation: 'Count',
70
+ settings: data,
71
+ })).data;
72
+ });
73
+ };
74
+ Exist = () => {
75
+ return createFluentBuilder(async (data) => {
76
+ return (await axios.post(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`, {
77
+ operation: 'Exist',
78
+ settings: data,
79
+ })).data;
80
+ });
81
+ };
82
+ Subscribe = (callback) => {
83
+ const eventSource = new EventSource(`${this.URL}/api/db/${this.WorkSpace}/${this.Name}`);
84
+ eventSource.addEventListener(this.Name, (event) => {
85
+ const { op, ...data } = JSON.parse(event.data);
86
+ callback({ action: op, data });
87
+ });
88
+ return () => eventSource.close();
89
+ };
90
+ }
91
+ export const AuraDatabase = (url, workspace, tables) => {
92
+ const Tables = {};
93
+ for (const key in tables) {
94
+ if (Object.prototype.hasOwnProperty.call(tables, key)) {
95
+ // @ts-ignore
96
+ Tables[key] = new RemoteTable(url, key, workspace);
97
+ }
98
+ }
99
+ return Tables;
100
+ };
@@ -0,0 +1,14 @@
1
+ export type SetFlag<State, Key extends keyof State> = {
2
+ [P in keyof State]: P extends Key ? true : State[P];
3
+ };
4
+ type MapToFalse<T> = {
5
+ [K in keyof T]: false;
6
+ };
7
+ type FluentStep<Schema, State extends {
8
+ [K in keyof Schema]: boolean | unknown;
9
+ }, Result> = {
10
+ [K in keyof Schema as State[K] extends true ? never : K]: Schema[K] extends boolean ? () => FluentStep<Schema, SetFlag<State, K>, Result> : Schema[K] extends any[] ? (...args: Schema[K]) => FluentStep<Schema, SetFlag<State, K>, Result> : (arg: Schema[K]) => FluentStep<Schema, SetFlag<State, K>, Result>;
11
+ } & PromiseLike<Result>;
12
+ export declare function createFluentBuilder<Schema, R = Schema>(onBuild?: (data: Schema) => R | Promise<R>): FluentStep<Schema, MapToFalse<Schema>, R>;
13
+ export {};
14
+ //# sourceMappingURL=fluent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fluent.d.ts","sourceRoot":"","sources":["../src/fluent.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,CAAC,KAAK,EAAE,GAAG,SAAS,MAAM,KAAK,IAAI;KACjD,CAAC,IAAI,MAAM,KAAK,GAAG,CAAC,SAAS,GAAG,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;CACpD,CAAC;AACF,KAAK,UAAU,CAAC,CAAC,IAAI;KAClB,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK;CACtB,CAAC;AACF,KAAK,UAAU,CACb,MAAM,EACN,KAAK,SAAS;KAAG,CAAC,IAAI,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO;CAAE,EACxD,MAAM,IACJ;KACD,CAAC,IAAI,MAAM,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS,IAAI,GACvC,KAAK,GACL,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,OAAO,GAC7B,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,GACnD,MAAM,CAAC,CAAC,CAAC,SAAS,GAAG,EAAE,GACvB,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,GACrE,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC;CACtE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAExB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EACpD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACzC,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAgC3C"}
package/dist/fluent.js ADDED
@@ -0,0 +1,29 @@
1
+ export function createFluentBuilder(onBuild) {
2
+ const data = {};
3
+ const handler = {
4
+ get(target, prop) {
5
+ if (prop === "then") {
6
+ return (resolve, reject) => {
7
+ const result = onBuild ? onBuild(target) : target;
8
+ Promise.resolve(result).then(resolve, reject);
9
+ };
10
+ }
11
+ return (...args) => {
12
+ // 1. No Args -> True (Flag)
13
+ if (args.length === 0) {
14
+ target[prop] = true;
15
+ }
16
+ // 2. One Arg -> Store value
17
+ else if (args.length === 1) {
18
+ target[prop] = args[0];
19
+ }
20
+ // 3. Multiple Args -> Store as Array/Tuple
21
+ else {
22
+ target[prop] = args;
23
+ }
24
+ return new Proxy(target, handler);
25
+ };
26
+ },
27
+ };
28
+ return new Proxy(data, handler);
29
+ }
@@ -0,0 +1,2 @@
1
+ export declare function createFunctionHandler(baseUrl: string, workspace: string, functionsFolder?: string): any;
2
+ //# sourceMappingURL=function.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../src/function.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,GAAG,CAiGvG"}
@@ -0,0 +1,90 @@
1
+ export function createFunctionHandler(baseUrl, workspace, functionsFolder) {
2
+ const handler = new Proxy({}, {
3
+ get(_, prop) {
4
+ return createNestedProxy([prop]);
5
+ }
6
+ });
7
+ function createNestedProxy(path) {
8
+ // Target function is just a placeholder
9
+ return new Proxy(() => { }, {
10
+ get(_, prop) {
11
+ return createNestedProxy([...path, prop]);
12
+ },
13
+ // 1. Remove 'async' here to prevent native Promise wrapping
14
+ apply(_, __, args) {
15
+ const url = [baseUrl, "api", "fn", workspace, ...path].join("/");
16
+ // 2. Start the fetch properly (without await)
17
+ const requestPromise = fetch(url, {
18
+ method: "POST",
19
+ body: JSON.stringify(args ?? {}),
20
+ headers: {
21
+ "Content-Type": "application/json",
22
+ "Accept": "text/event-stream,application/json",
23
+ },
24
+ });
25
+ // 3. Return a custom "Thenable" object immediately
26
+ return {
27
+ then(onFulfilled, onRejected) {
28
+ requestPromise.then(async (response) => {
29
+ const contentType = response.headers.get("Content-Type") || "";
30
+ // ─────────────────────────────────────────────
31
+ // SSE PATH
32
+ // ─────────────────────────────────────────────
33
+ if (contentType.includes("text/event-stream")) {
34
+ const reader = response.body.getReader();
35
+ const decoder = new TextDecoder("utf-8");
36
+ let buffer = "";
37
+ try {
38
+ while (true) {
39
+ const { value, done } = await reader.read();
40
+ if (done)
41
+ break;
42
+ buffer += decoder.decode(value, { stream: true });
43
+ // Split by SSE message delimiter
44
+ const parts = buffer.split("\n\n");
45
+ buffer = parts.pop() || ""; // Keep incomplete chunk
46
+ for (const part of parts) {
47
+ // Extract data lines, remove 'data: ' prefix, join with newline
48
+ const message = part
49
+ .split("\n")
50
+ .filter(line => line.trim().startsWith("data: "))
51
+ .map(line => line.replace(/^data: /, ""))
52
+ .join("\n");
53
+ if (message) {
54
+ try {
55
+ // Emit parsed JSON
56
+ onFulfilled(JSON.parse(message));
57
+ }
58
+ catch {
59
+ // Or emit raw string if parsing fails
60
+ onFulfilled(message);
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ catch (err) {
67
+ if (onRejected)
68
+ onRejected(err);
69
+ }
70
+ }
71
+ // ─────────────────────────────────────────────
72
+ // NORMAL JSON PATH
73
+ // ─────────────────────────────────────────────
74
+ else {
75
+ const data = await response.json();
76
+ onFulfilled(data.data ?? data);
77
+ }
78
+ }).catch((err) => {
79
+ if (onRejected)
80
+ onRejected(err);
81
+ });
82
+ // Return 'this' to allow chaining, though strictly custom behavior
83
+ return this;
84
+ }
85
+ };
86
+ },
87
+ });
88
+ }
89
+ return handler;
90
+ }
@@ -0,0 +1,21 @@
1
+ import { AuraAuth } from "./auth";
2
+ import { AuraDatabase } from "./database";
3
+ import { AuraStorage } from "./storage";
4
+ export * from "@inflector/optima/types";
5
+ export * from "./lib";
6
+ type CreateAuraConfig<T extends Record<string, any>> = {
7
+ config: {
8
+ Url: string;
9
+ WorkSpace: string;
10
+ [key: string]: any;
11
+ };
12
+ Tables: T;
13
+ };
14
+ type AuraInstance<F, T extends Record<string, any>> = {
15
+ Database: ReturnType<typeof AuraDatabase<T>>;
16
+ Function: F;
17
+ Storage: ReturnType<typeof AuraStorage>;
18
+ Auth: ReturnType<typeof AuraAuth>;
19
+ };
20
+ export declare const CreateAura: <F, T extends Record<string, any>>(Config: CreateAuraConfig<T>) => AuraInstance<F, T>;
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,cAAc,yBAAyB,CAAC;AACxC,cAAc,OAAO,CAAC;AAEtB,KAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACnD,MAAM,EAAE;QACJ,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACtB,CAAC;IACF,MAAM,EAAE,CAAC,CAAC;CACb,CAAC;AAEF,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IAClD,QAAQ,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,QAAQ,EAAE,CAAC,CAAC;IACZ,OAAO,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;IACxC,IAAI,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,UAAU,GACnB,CAAC,EACD,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAE7B,QAAQ,gBAAgB,CAAC,CAAC,CAAC,KAC5B,YAAY,CAAC,CAAC,EAAE,CAAC,CAQnB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ import { AuraAuth } from "./auth";
2
+ import { AuraDatabase } from "./database";
3
+ import { createFunctionHandler } from "./function";
4
+ import { AuraStorage } from "./storage";
5
+ export * from "@inflector/optima/types";
6
+ export * from "./lib";
7
+ export const CreateAura = (Config) => {
8
+ const auth = AuraAuth(Config.config.Url, Config.config.WorkSpace);
9
+ return {
10
+ Database: AuraDatabase(Config.config.Url, Config.config.WorkSpace, Config.Tables),
11
+ Function: createFunctionHandler(Config.config.Url, Config.config.WorkSpace),
12
+ Auth: auth,
13
+ Storage: AuraStorage(Config.config.Url, Config.config.WorkSpace, auth.Signal),
14
+ };
15
+ };
package/dist/lib.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export type AuraFunctionHandler<Args = any, Result = any> = (ctx: {
2
+ args: Args;
3
+ ctx: any;
4
+ secrets: Record<string, string>;
5
+ }) => Result | Promise<Result>;
6
+ export interface SSEHandler {
7
+ __isSSE: true;
8
+ handler: (send: (event: string, data: any) => void, close: () => void) => Promise<void> | void;
9
+ }
10
+ export declare function AuraFunction<Args = any, Result = any>(handler: AuraFunctionHandler<Args, Result>): AuraFunctionHandler<Args, Result>;
11
+ export declare function sse(handler: (send: (event: string, data: any) => void, close: () => void) => Promise<void> | void): SSEHandler;
12
+ //# sourceMappingURL=lib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,mBAAmB,CAAC,IAAI,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC;IAAA,OAAO,EAAC,MAAM,CAAC,MAAM,EAAC,MAAM,CAAC,CAAA;CAAE,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAEtJ,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,IAAI,CAAC;IACd,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAChG;AAED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,IAAI,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAC3D,OAAO,EAAE,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,GACzC,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAErC,MAAM,CAAC,OAAO,UAAU,GAAG,CACzB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAC7F,UAAU,CAAC"}
package/dist/lib.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ type FileAura = {
2
+ ID: string;
3
+ FileName: string;
4
+ MimeType: string;
5
+ Size: number;
6
+ Path: string;
7
+ UploadedBy?: string;
8
+ UploadedAt: Date;
9
+ };
10
+ export declare const AuraStorage: (url: string, workspace: string, userAtom: any) => {
11
+ Upload: (file?: File, config?: {
12
+ openSelector?: boolean;
13
+ allowedTypes?: string[];
14
+ }) => Promise<any>;
15
+ File: (id: string) => string;
16
+ Delete: (id: string) => Promise<any>;
17
+ Get: (id: string) => Promise<FileAura | undefined>;
18
+ List: () => Promise<FileAura[]>;
19
+ UploadMultiple: (files?: File[], config?: {
20
+ openSelector?: boolean;
21
+ allowedTypes?: string[];
22
+ }) => Promise<any[]>;
23
+ Exists: (id: string) => Promise<boolean | undefined>;
24
+ Download: (id: string, download?: boolean) => Promise<{
25
+ blob: any;
26
+ fileName: string;
27
+ mimeType: any;
28
+ }>;
29
+ };
30
+ export {};
31
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,GAAG;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,IAAI,CAAC;CACpB,CAAC;AAIF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,WAAW,MAAM,EAAE,UAAU,GAAG;oBAG1D,IAAI,WACH;QAAE,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE;eAgDhD,MAAM;iBAGE,MAAM;cAUT,MAAM;;6BAoBV,IAAI,EAAE,WACN;QAAE,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE;iBAuC5C,MAAM;mBAUJ,MAAM,aAAY,OAAO;;;;;CA6BrD,CAAA"}
@@ -0,0 +1,164 @@
1
+ import axios from "axios";
2
+ export const AuraStorage = (url, workspace, userAtom) => {
3
+ const UploadFn = async (file, config = {}) => {
4
+ if (!userAtom.get().data)
5
+ return;
6
+ // If no file is passed, or openSelector is true, open a file input dialog automatically
7
+ if (!file || config.openSelector) {
8
+ return new Promise(async (resolve, reject) => {
9
+ const input = document.createElement("input");
10
+ input.type = "file";
11
+ // Set allowedTypes if provided
12
+ if (config.allowedTypes && config.allowedTypes.length > 0) {
13
+ input.accept = config.allowedTypes.join(",");
14
+ }
15
+ input.style.display = "none";
16
+ document.body.appendChild(input);
17
+ input.onchange = async () => {
18
+ try {
19
+ const selectedFile = input.files?.[0];
20
+ if (!selectedFile) {
21
+ reject(new Error("No file selected"));
22
+ document.body.removeChild(input);
23
+ return;
24
+ }
25
+ const fd = new FormData();
26
+ fd.set("operation", "Upload");
27
+ fd.set("owner", userAtom.get().data.user.id);
28
+ fd.set("file", selectedFile);
29
+ const result = (await axios.post(url + "/api/storage/" + workspace, fd)).data;
30
+ resolve(result);
31
+ document.body.removeChild(input);
32
+ }
33
+ catch (e) {
34
+ reject(e);
35
+ document.body.removeChild(input);
36
+ }
37
+ };
38
+ input.click();
39
+ });
40
+ }
41
+ else {
42
+ const fd = new FormData();
43
+ fd.set("operation", "Upload");
44
+ fd.set("owner", userAtom.get().data.user.id);
45
+ fd.set("file", file);
46
+ return (await axios.post(url + "/api/storage/" + workspace, fd)).data;
47
+ }
48
+ };
49
+ return {
50
+ Upload: UploadFn,
51
+ File: (id) => {
52
+ return `${url}/api/storage/${workspace}/${id}`;
53
+ },
54
+ Delete: async (id) => {
55
+ if (!userAtom.get().data)
56
+ return;
57
+ return (await axios.post(url + "/api/storage/" + workspace, {
58
+ operation: "Delete",
59
+ settings: {
60
+ FileID: id,
61
+ Owner: userAtom.get().data.user.id
62
+ }
63
+ })).data;
64
+ },
65
+ Get: async (id) => {
66
+ if (!userAtom.get().data)
67
+ return;
68
+ return (await axios.post(url + "/api/storage/" + workspace, {
69
+ operation: "Get",
70
+ settings: {
71
+ FileID: id,
72
+ Owner: userAtom.get().data.user.id
73
+ }
74
+ })).data;
75
+ },
76
+ List: async () => {
77
+ if (!userAtom.get().data)
78
+ return [];
79
+ return (await axios.post(url + "/api/storage/" + workspace, {
80
+ operation: "List",
81
+ settings: {
82
+ Owner: userAtom.get().data.user.id
83
+ }
84
+ })).data;
85
+ },
86
+ UploadMultiple: async (files, config = {}) => {
87
+ // If files not passed or openSelector is true, open selector
88
+ if (config.openSelector || !files || files.length === 0) {
89
+ return await new Promise((resolve, reject) => {
90
+ const input = document.createElement("input");
91
+ input.type = "file";
92
+ input.multiple = true;
93
+ // Set allowedTypes if provided
94
+ if (config.allowedTypes && config.allowedTypes.length > 0) {
95
+ input.accept = config.allowedTypes.join(",");
96
+ }
97
+ input.style.display = "none";
98
+ document.body.appendChild(input);
99
+ input.onchange = async () => {
100
+ const selectedFiles = Array.from(input.files ?? []);
101
+ try {
102
+ if (selectedFiles.length === 0) {
103
+ reject(new Error("No files selected"));
104
+ document.body.removeChild(input);
105
+ return;
106
+ }
107
+ const uploadResults = await Promise.all(selectedFiles.map(f => UploadFn(f, config)));
108
+ resolve(uploadResults);
109
+ }
110
+ catch (e) {
111
+ reject(e);
112
+ }
113
+ finally {
114
+ document.body.removeChild(input);
115
+ }
116
+ };
117
+ input.click();
118
+ });
119
+ }
120
+ else {
121
+ // Use given files directly
122
+ return await Promise.all(files.map(f => UploadFn(f, config)));
123
+ }
124
+ },
125
+ Exists: async (id) => {
126
+ if (!userAtom.get().data)
127
+ return;
128
+ return (await axios.post(url + "/api/storage/" + workspace, {
129
+ operation: "Get",
130
+ settings: {
131
+ FileID: id,
132
+ Owner: userAtom.get().data.user.id
133
+ }
134
+ })).data;
135
+ },
136
+ Download: async (id, download = true) => {
137
+ try {
138
+ const response = await axios.get(`${url}/api/storage/${workspace}/${id}?download=${download ? '1' : '0'}`, {
139
+ responseType: "blob",
140
+ withCredentials: true
141
+ });
142
+ // Extract filename from content-disposition
143
+ const contentDisposition = response.headers["content-disposition"];
144
+ let fileName = id;
145
+ if (contentDisposition) {
146
+ const match = /filename="?([^"]+)"?/i.exec(contentDisposition);
147
+ if (match)
148
+ fileName = decodeURIComponent(match[1]);
149
+ }
150
+ return {
151
+ blob: response.data,
152
+ fileName,
153
+ mimeType: response.headers["content-type"] || "application/octet-stream"
154
+ };
155
+ }
156
+ catch (error) {
157
+ if (error.response && error.response.data && error.response.data.message) {
158
+ throw new Error(error.response.data.message);
159
+ }
160
+ throw new Error("File not found");
161
+ }
162
+ },
163
+ };
164
+ };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@inflector/aura",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "files": ["dist"],
14
+ "scripts": {
15
+ "build": "tsc"
16
+ },
17
+ "bin": {
18
+ "aura": "./dist/bin.js"
19
+ },
20
+ "browser": false,
21
+ "devDependencies": {
22
+ "@types/bun": "latest",
23
+ "@types/node": "^20.14.10",
24
+ "ts-node": "^10.9.2",
25
+ "tslib": "^2.8.1",
26
+ "typescript": "^5.8.3",
27
+ "rollup": "^4.0.0",
28
+ "rollup-plugin-esbuild": "^6.1.0",
29
+ "rollup-plugin-dts": "^6.1.0"
30
+ },
31
+ "peerDependencies": {
32
+ "typescript": "^5"
33
+ },
34
+ "dependencies": {
35
+ "@inflector/optima": "1.1.0",
36
+ "@nanostores/react": "^1.0.0",
37
+ "axios": "^1.13.2",
38
+ "better-auth": "^1.4.16",
39
+ "chalk": "^5.6.2",
40
+ "chokidar": "^5.0.0",
41
+ "eventsource": "^4.1.0",
42
+ "tsx": "^4.20.4",
43
+ "zod": "^3.25.67"
44
+ }
45
+ }