@ailuracode/alpine-core 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) ailuracode
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # @ailuracode/alpine-core
2
+
3
+ Lazy plugin registry and initializer for [Alpine.js](https://alpinejs.dev/) v3.
4
+
5
+ Use this package to register plugins without running them at import time, then initialize only the plugins you need — keeping bundles tree-shakeable and SSR-safe.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @ailuracode/alpine-core alpinejs
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```js
16
+ import Alpine from "alpinejs";
17
+ import {
18
+ createAlpinePlugin,
19
+ defineMagicPlugin,
20
+ defineStorePlugin,
21
+ initPlugins,
22
+ registerPlugin,
23
+ } from "@ailuracode/alpine-core";
24
+ import share from "@ailuracode/alpine-share";
25
+ import theme from "@ailuracode/alpine-theme";
26
+
27
+ registerPlugin(
28
+ "share",
29
+ defineMagicPlugin(["share"], share)
30
+ );
31
+
32
+ registerPlugin(
33
+ "theme",
34
+ defineStorePlugin(["theme"], theme({
35
+ onChange({ resolved }) {
36
+ document.documentElement.dataset.theme = resolved;
37
+ },
38
+ }))
39
+ );
40
+
41
+ // Sync entry (factory plugins must be resolved before registerPlugin)
42
+ Alpine.plugin(createAlpinePlugin(["share", "theme"]));
43
+ Alpine.start();
44
+ ```
45
+
46
+ ## Lazy dynamic imports
47
+
48
+ ```js
49
+ import { initPlugins, lazyPlugin, registerPlugin } from "@ailuracode/alpine-core";
50
+
51
+ registerPlugin(
52
+ "share",
53
+ lazyPlugin({
54
+ kind: "magic",
55
+ magics: ["share"],
56
+ import: () => import("@ailuracode/alpine-share"),
57
+ })
58
+ );
59
+
60
+ await initPlugins(Alpine, "share");
61
+ Alpine.start();
62
+ ```
63
+
64
+ ## API
65
+
66
+ | Export | Description |
67
+ |--------|-------------|
68
+ | `registerPlugin(name, definition)` | Register a plugin without initializing it |
69
+ | `initPlugins(Alpine, names?)` | Initialize all or selected plugins (async-safe) |
70
+ | `initPluginsSync(Alpine, names?)` | Initialize sync plugins only |
71
+ | `createAlpinePlugin(names?)` | Alpine.js bridge for sync plugins |
72
+ | `defineMagicPlugin(magics, loader)` | Helper for magic plugins |
73
+ | `defineStorePlugin(stores, loader)` | Helper for store plugins |
74
+ | `defineHybridPlugin(options)` | Helper for plugins that register both |
75
+ | `lazyPlugin(options)` | Helper for dynamic `import()` loaders |
76
+ | `isPluginInitialized(name)` | Whether a plugin has been initialized |
77
+ | `getRegisteredPlugins()` | List registered plugins |
78
+
79
+ ## Plugin kinds
80
+
81
+ - **magic** — registers Alpine magics such as `$share` or `$calendar`
82
+ - **store** — registers Alpine stores such as `$store.theme`
83
+ - **both** — registers multiple magics and/or stores in one plugin (e.g. `$wakelock`, `$idle`)
84
+
85
+ ## SSR
86
+
87
+ The core never touches `window` or `navigator` at import time. Plugin loaders run only when you call `initPlugins()` or `createAlpinePlugin()`.
88
+
89
+ ## TypeScript
90
+
91
+ ```ts
92
+ /// <reference types="@types/alpinejs" />
93
+ /// <reference types="@ailuracode/alpine-core" />
94
+ ```
95
+
96
+ Also reference individual plugin `global.d.ts` files for magic and store typings.
97
+
98
+ ## License
99
+
100
+ MIT
@@ -0,0 +1,3 @@
1
+ /// <reference types="@types/alpinejs" />
2
+
3
+ export {};
@@ -0,0 +1,97 @@
1
+ import AlpineType from 'alpinejs';
2
+
3
+ /** Alpine.js plugin callback registered with `Alpine.plugin()`. */
4
+ type AlpinePluginCallback = (Alpine: AlpineType.Alpine) => void;
5
+ /**
6
+ * Lazy plugin source. Resolved only when `initPlugins()` runs — never at import time.
7
+ * Supports sync callbacks, lazy factories, and dynamic `import()` loaders.
8
+ */
9
+ type PluginLoader = AlpinePluginCallback | (() => AlpinePluginCallback) | (() => Promise<AlpinePluginCallback>);
10
+ /** Plugin that registers one or more Alpine magics (`$share`, `$calendar`, …). */
11
+ interface MagicPluginDefinition {
12
+ readonly kind: "magic";
13
+ readonly magics: readonly string[];
14
+ readonly plugin: PluginLoader;
15
+ }
16
+ /** Plugin that registers one or more Alpine stores (`$store.theme`, …). */
17
+ interface StorePluginDefinition {
18
+ readonly kind: "store";
19
+ readonly stores: readonly string[];
20
+ readonly plugin: PluginLoader;
21
+ }
22
+ /** Plugin that registers both magics and stores (`$wakelock` + `$idle`, …). */
23
+ interface HybridPluginDefinition {
24
+ readonly kind: "both";
25
+ readonly magics?: readonly string[];
26
+ readonly stores?: readonly string[];
27
+ readonly plugin: PluginLoader;
28
+ }
29
+ type PluginDefinition = MagicPluginDefinition | StorePluginDefinition | HybridPluginDefinition;
30
+ interface RegisteredPlugin {
31
+ readonly name: string;
32
+ readonly definition: PluginDefinition;
33
+ }
34
+ interface PluginRegistryEntry {
35
+ readonly name: string;
36
+ readonly definition: PluginDefinition;
37
+ initialized: boolean;
38
+ }
39
+
40
+ /** Creates a magic plugin definition. */
41
+ declare function defineMagicPlugin(magics: readonly string[], plugin: PluginLoader): MagicPluginDefinition;
42
+ /** Creates a store plugin definition. */
43
+ declare function defineStorePlugin(stores: readonly string[], plugin: PluginLoader): StorePluginDefinition;
44
+ /** Creates a hybrid plugin definition for magics and stores together. */
45
+ declare function defineHybridPlugin(options: {
46
+ magics?: readonly string[];
47
+ stores?: readonly string[];
48
+ plugin: PluginLoader;
49
+ }): HybridPluginDefinition;
50
+ type LazyPluginModule = {
51
+ default: PluginLoader;
52
+ };
53
+ /** Creates a plugin definition backed by a dynamic `import()`. */
54
+ declare function lazyPlugin(definition: Omit<MagicPluginDefinition, "plugin"> & {
55
+ import: () => Promise<LazyPluginModule>;
56
+ }): MagicPluginDefinition;
57
+ declare function lazyPlugin(definition: Omit<StorePluginDefinition, "plugin"> & {
58
+ import: () => Promise<LazyPluginModule>;
59
+ }): StorePluginDefinition;
60
+ declare function lazyPlugin(definition: Omit<HybridPluginDefinition, "plugin"> & {
61
+ import: () => Promise<LazyPluginModule>;
62
+ }): HybridPluginDefinition;
63
+
64
+ declare class PluginLoaderError extends Error {
65
+ constructor(message: string);
66
+ }
67
+
68
+ /** Registers a plugin definition without initializing it. Safe to call at import time. */
69
+ declare function registerPlugin(name: string, definition: PluginDefinition): void;
70
+ /** Removes a plugin from the registry. Returns whether it existed. */
71
+ declare function unregisterPlugin(name: string): boolean;
72
+ /** Returns a registered plugin entry, if present. */
73
+ declare function getRegisteredPlugin(name: string): PluginRegistryEntry | undefined;
74
+ /** Returns all registered plugins in registration order. */
75
+ declare function getRegisteredPlugins(): readonly PluginRegistryEntry[];
76
+ /** Returns whether a plugin has been initialized with Alpine. */
77
+ declare function isPluginInitialized(name: string): boolean;
78
+ /** Clears the registry. Intended for tests. */
79
+ declare function resetPluginRegistry(): void;
80
+
81
+ /**
82
+ * Initializes registered plugins on demand. Supports async dynamic imports.
83
+ * Call before `Alpine.start()` in SSR and client entrypoints.
84
+ */
85
+ declare function initPlugins(Alpine: AlpineType.Alpine, names?: string | readonly string[]): Promise<readonly RegisteredPlugin[]>;
86
+ /**
87
+ * Initializes registered plugins synchronously.
88
+ * Throws when a plugin uses an async loader — use `initPlugins()` instead.
89
+ */
90
+ declare function initPluginsSync(Alpine: AlpineType.Alpine, names?: string | readonly string[]): readonly RegisteredPlugin[];
91
+ /**
92
+ * Returns an Alpine.js plugin callback that initializes the given registered plugins.
93
+ * Only supports sync loaders — use `initPlugins()` for dynamic imports.
94
+ */
95
+ declare function createAlpinePlugin(names?: string | readonly string[]): AlpineType.PluginCallback;
96
+
97
+ export { type AlpinePluginCallback, type HybridPluginDefinition, type MagicPluginDefinition, type PluginDefinition, type PluginLoader, PluginLoaderError, type PluginRegistryEntry, type RegisteredPlugin, type StorePluginDefinition, createAlpinePlugin, defineHybridPlugin, defineMagicPlugin, defineStorePlugin, getRegisteredPlugin, getRegisteredPlugins, initPlugins, initPluginsSync, isPluginInitialized, lazyPlugin, registerPlugin, resetPluginRegistry, unregisterPlugin };
package/dist/index.js ADDED
@@ -0,0 +1,227 @@
1
+ // src/loader.ts
2
+ var PluginLoaderError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "PluginLoaderError";
6
+ }
7
+ };
8
+ function isPluginCallback(value) {
9
+ return typeof value === "function";
10
+ }
11
+ function isLazyFactory(loader) {
12
+ return typeof loader === "function" && loader.length === 0;
13
+ }
14
+ async function resolvePluginLoader(loader) {
15
+ if (!isLazyFactory(loader)) {
16
+ return loader;
17
+ }
18
+ const candidate = loader();
19
+ const resolved = candidate instanceof Promise ? await candidate : candidate;
20
+ if (!isPluginCallback(resolved)) {
21
+ throw new PluginLoaderError("Plugin loader must resolve to a function");
22
+ }
23
+ return resolved;
24
+ }
25
+ function resolvePluginLoaderSync(loader) {
26
+ if (!isLazyFactory(loader)) {
27
+ return loader;
28
+ }
29
+ const candidate = loader();
30
+ if (candidate instanceof Promise) {
31
+ throw new PluginLoaderError("Async plugin loaders require initPlugins() before Alpine.start()");
32
+ }
33
+ if (!isPluginCallback(candidate)) {
34
+ throw new PluginLoaderError("Plugin loader must resolve to a function");
35
+ }
36
+ return candidate;
37
+ }
38
+
39
+ // src/registry.ts
40
+ var registry = /* @__PURE__ */ new Map();
41
+ function normalizePluginName(name) {
42
+ const normalized = name.trim();
43
+ if (!normalized) {
44
+ throw new Error("Plugin name must be a non-empty string");
45
+ }
46
+ return normalized;
47
+ }
48
+ function assertValidDefinition(definition) {
49
+ switch (definition.kind) {
50
+ case "magic": {
51
+ if (definition.magics.length === 0) {
52
+ throw new Error(`Magic plugin must declare at least one magic name`);
53
+ }
54
+ break;
55
+ }
56
+ case "store": {
57
+ if (definition.stores.length === 0) {
58
+ throw new Error(`Store plugin must declare at least one store name`);
59
+ }
60
+ break;
61
+ }
62
+ case "both": {
63
+ const hasMagics = (definition.magics?.length ?? 0) > 0;
64
+ const hasStores = (definition.stores?.length ?? 0) > 0;
65
+ if (!(hasMagics || hasStores)) {
66
+ throw new Error(`Hybrid plugin must declare at least one magic or store name`);
67
+ }
68
+ break;
69
+ }
70
+ default: {
71
+ const unknownKind = definition;
72
+ throw new Error(`Unknown plugin kind: ${String(unknownKind)}`);
73
+ }
74
+ }
75
+ }
76
+ function registerPlugin(name, definition) {
77
+ const normalizedName = normalizePluginName(name);
78
+ assertValidDefinition(definition);
79
+ if (registry.has(normalizedName)) {
80
+ throw new Error(`Plugin "${normalizedName}" is already registered`);
81
+ }
82
+ registry.set(normalizedName, {
83
+ name: normalizedName,
84
+ definition,
85
+ initialized: false
86
+ });
87
+ }
88
+ function unregisterPlugin(name) {
89
+ return registry.delete(normalizePluginName(name));
90
+ }
91
+ function getRegisteredPlugin(name) {
92
+ return registry.get(normalizePluginName(name));
93
+ }
94
+ function getRegisteredPlugins() {
95
+ return [...registry.values()];
96
+ }
97
+ function isPluginInitialized(name) {
98
+ return registry.get(normalizePluginName(name))?.initialized ?? false;
99
+ }
100
+ function markPluginInitialized(name) {
101
+ const entry = registry.get(normalizePluginName(name));
102
+ if (!entry) {
103
+ throw new Error(`Cannot mark unknown plugin "${name}" as initialized`);
104
+ }
105
+ entry.initialized = true;
106
+ }
107
+ function resetPluginRegistry() {
108
+ registry.clear();
109
+ }
110
+ function resolvePluginEntries(names) {
111
+ if (names === void 0) {
112
+ return [...getRegisteredPlugins()];
113
+ }
114
+ const requested = Array.isArray(names) ? names : [names];
115
+ if (requested.length === 0) {
116
+ return [];
117
+ }
118
+ const entries = [];
119
+ for (const name of requested) {
120
+ const entry = getRegisteredPlugin(name);
121
+ if (!entry) {
122
+ throw new Error(`Plugin "${name}" is not registered`);
123
+ }
124
+ entries.push(entry);
125
+ }
126
+ return entries;
127
+ }
128
+
129
+ // src/define.ts
130
+ function defineMagicPlugin(magics, plugin) {
131
+ return {
132
+ kind: "magic",
133
+ magics,
134
+ plugin
135
+ };
136
+ }
137
+ function defineStorePlugin(stores, plugin) {
138
+ return {
139
+ kind: "store",
140
+ stores,
141
+ plugin
142
+ };
143
+ }
144
+ function defineHybridPlugin(options) {
145
+ return {
146
+ kind: "both",
147
+ magics: options.magics,
148
+ stores: options.stores,
149
+ plugin: options.plugin
150
+ };
151
+ }
152
+ function lazyPlugin(definition) {
153
+ const { import: importModule, ...rest } = definition;
154
+ const plugin = async () => {
155
+ const module = await importModule();
156
+ return resolvePluginLoader(module.default);
157
+ };
158
+ switch (rest.kind) {
159
+ case "magic":
160
+ return defineMagicPlugin(rest.magics ?? [], plugin);
161
+ case "store":
162
+ return defineStorePlugin(rest.stores ?? [], plugin);
163
+ case "both":
164
+ return defineHybridPlugin({
165
+ magics: rest.magics,
166
+ stores: rest.stores,
167
+ plugin
168
+ });
169
+ }
170
+ }
171
+
172
+ // src/index.ts
173
+ function toRegisteredPlugin(entry) {
174
+ return {
175
+ name: entry.name,
176
+ definition: entry.definition
177
+ };
178
+ }
179
+ async function initializeEntry(Alpine, entry) {
180
+ if (entry.initialized) {
181
+ return;
182
+ }
183
+ const callback = await resolvePluginLoader(entry.definition.plugin);
184
+ Alpine.plugin(callback);
185
+ markPluginInitialized(entry.name);
186
+ }
187
+ async function initPlugins(Alpine, names) {
188
+ const entries = resolvePluginEntries(names);
189
+ for (const entry of entries) {
190
+ await initializeEntry(Alpine, entry);
191
+ }
192
+ return entries.map(toRegisteredPlugin);
193
+ }
194
+ function initPluginsSync(Alpine, names) {
195
+ const entries = resolvePluginEntries(names);
196
+ for (const entry of entries) {
197
+ if (entry.initialized) {
198
+ continue;
199
+ }
200
+ const callback = resolvePluginLoaderSync(entry.definition.plugin);
201
+ Alpine.plugin(callback);
202
+ markPluginInitialized(entry.name);
203
+ }
204
+ return entries.map(toRegisteredPlugin);
205
+ }
206
+ function createAlpinePlugin(names) {
207
+ return (Alpine) => {
208
+ initPluginsSync(Alpine, names);
209
+ };
210
+ }
211
+ export {
212
+ PluginLoaderError,
213
+ createAlpinePlugin,
214
+ defineHybridPlugin,
215
+ defineMagicPlugin,
216
+ defineStorePlugin,
217
+ getRegisteredPlugin,
218
+ getRegisteredPlugins,
219
+ initPlugins,
220
+ initPluginsSync,
221
+ isPluginInitialized,
222
+ lazyPlugin,
223
+ registerPlugin,
224
+ resetPluginRegistry,
225
+ unregisterPlugin
226
+ };
227
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/loader.ts","../src/registry.ts","../src/define.ts","../src/index.ts"],"sourcesContent":["import type { AlpinePluginCallback, PluginLoader } from \"./types.js\";\n\nexport class PluginLoaderError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PluginLoaderError\";\n }\n}\n\nfunction isPluginCallback(value: unknown): value is AlpinePluginCallback {\n return typeof value === \"function\";\n}\n\nfunction isLazyFactory(\n loader: PluginLoader\n): loader is (() => AlpinePluginCallback) | (() => Promise<AlpinePluginCallback>) {\n return typeof loader === \"function\" && loader.length === 0;\n}\n\n/** Resolves a lazy plugin loader to an Alpine plugin callback. */\nexport async function resolvePluginLoader(loader: PluginLoader): Promise<AlpinePluginCallback> {\n if (!isLazyFactory(loader)) {\n return loader;\n }\n\n const candidate = loader();\n const resolved = candidate instanceof Promise ? await candidate : candidate;\n\n if (!isPluginCallback(resolved)) {\n throw new PluginLoaderError(\"Plugin loader must resolve to a function\");\n }\n\n return resolved;\n}\n\n/** Resolves a lazy plugin loader synchronously. Throws when the loader is async. */\nexport function resolvePluginLoaderSync(loader: PluginLoader): AlpinePluginCallback {\n if (!isLazyFactory(loader)) {\n return loader;\n }\n\n const candidate = loader();\n\n if (candidate instanceof Promise) {\n throw new PluginLoaderError(\"Async plugin loaders require initPlugins() before Alpine.start()\");\n }\n\n if (!isPluginCallback(candidate)) {\n throw new PluginLoaderError(\"Plugin loader must resolve to a function\");\n }\n\n return candidate;\n}\n","import type { PluginDefinition, PluginRegistryEntry } from \"./types.js\";\n\nconst registry = new Map<string, PluginRegistryEntry>();\n\nfunction normalizePluginName(name: string): string {\n const normalized = name.trim();\n\n if (!normalized) {\n throw new Error(\"Plugin name must be a non-empty string\");\n }\n\n return normalized;\n}\n\nfunction assertValidDefinition(definition: PluginDefinition): void {\n switch (definition.kind) {\n case \"magic\": {\n if (definition.magics.length === 0) {\n throw new Error(`Magic plugin must declare at least one magic name`);\n }\n break;\n }\n case \"store\": {\n if (definition.stores.length === 0) {\n throw new Error(`Store plugin must declare at least one store name`);\n }\n break;\n }\n case \"both\": {\n const hasMagics = (definition.magics?.length ?? 0) > 0;\n const hasStores = (definition.stores?.length ?? 0) > 0;\n\n if (!(hasMagics || hasStores)) {\n throw new Error(`Hybrid plugin must declare at least one magic or store name`);\n }\n break;\n }\n default: {\n const unknownKind: never = definition;\n throw new Error(`Unknown plugin kind: ${String(unknownKind)}`);\n }\n }\n}\n\n/** Registers a plugin definition without initializing it. Safe to call at import time. */\nexport function registerPlugin(name: string, definition: PluginDefinition): void {\n const normalizedName = normalizePluginName(name);\n assertValidDefinition(definition);\n\n if (registry.has(normalizedName)) {\n throw new Error(`Plugin \"${normalizedName}\" is already registered`);\n }\n\n registry.set(normalizedName, {\n name: normalizedName,\n definition,\n initialized: false,\n });\n}\n\n/** Removes a plugin from the registry. Returns whether it existed. */\nexport function unregisterPlugin(name: string): boolean {\n return registry.delete(normalizePluginName(name));\n}\n\n/** Returns a registered plugin entry, if present. */\nexport function getRegisteredPlugin(name: string): PluginRegistryEntry | undefined {\n return registry.get(normalizePluginName(name));\n}\n\n/** Returns all registered plugins in registration order. */\nexport function getRegisteredPlugins(): readonly PluginRegistryEntry[] {\n return [...registry.values()];\n}\n\n/** Returns whether a plugin has been initialized with Alpine. */\nexport function isPluginInitialized(name: string): boolean {\n return registry.get(normalizePluginName(name))?.initialized ?? false;\n}\n\n/** Marks a plugin as initialized. */\nexport function markPluginInitialized(name: string): void {\n const entry = registry.get(normalizePluginName(name));\n\n if (!entry) {\n throw new Error(`Cannot mark unknown plugin \"${name}\" as initialized`);\n }\n\n entry.initialized = true;\n}\n\n/** Clears the registry. Intended for tests. */\nexport function resetPluginRegistry(): void {\n registry.clear();\n}\n\n/** Resolves plugin names to registry entries, preserving registration order. */\nexport function resolvePluginEntries(names?: string | readonly string[]): PluginRegistryEntry[] {\n if (names === undefined) {\n return [...getRegisteredPlugins()];\n }\n\n const requested = Array.isArray(names) ? names : [names];\n\n if (requested.length === 0) {\n return [];\n }\n\n const entries: PluginRegistryEntry[] = [];\n\n for (const name of requested) {\n const entry = getRegisteredPlugin(name);\n\n if (!entry) {\n throw new Error(`Plugin \"${name}\" is not registered`);\n }\n\n entries.push(entry);\n }\n\n return entries;\n}\n","import { resolvePluginLoader } from \"./loader.js\";\nimport type {\n HybridPluginDefinition,\n MagicPluginDefinition,\n PluginLoader,\n StorePluginDefinition,\n} from \"./types.js\";\n\n/** Creates a magic plugin definition. */\nexport function defineMagicPlugin(\n magics: readonly string[],\n plugin: PluginLoader\n): MagicPluginDefinition {\n return {\n kind: \"magic\",\n magics,\n plugin,\n };\n}\n\n/** Creates a store plugin definition. */\nexport function defineStorePlugin(\n stores: readonly string[],\n plugin: PluginLoader\n): StorePluginDefinition {\n return {\n kind: \"store\",\n stores,\n plugin,\n };\n}\n\n/** Creates a hybrid plugin definition for magics and stores together. */\nexport function defineHybridPlugin(options: {\n magics?: readonly string[];\n stores?: readonly string[];\n plugin: PluginLoader;\n}): HybridPluginDefinition {\n return {\n kind: \"both\",\n magics: options.magics,\n stores: options.stores,\n plugin: options.plugin,\n };\n}\n\ntype LazyPluginModule = {\n default: PluginLoader;\n};\n\n/** Creates a plugin definition backed by a dynamic `import()`. */\nexport function lazyPlugin(\n definition: Omit<MagicPluginDefinition, \"plugin\"> & {\n import: () => Promise<LazyPluginModule>;\n }\n): MagicPluginDefinition;\nexport function lazyPlugin(\n definition: Omit<StorePluginDefinition, \"plugin\"> & {\n import: () => Promise<LazyPluginModule>;\n }\n): StorePluginDefinition;\nexport function lazyPlugin(\n definition: Omit<HybridPluginDefinition, \"plugin\"> & {\n import: () => Promise<LazyPluginModule>;\n }\n): HybridPluginDefinition;\nexport function lazyPlugin(definition: {\n kind: \"magic\" | \"store\" | \"both\";\n magics?: readonly string[];\n stores?: readonly string[];\n import: () => Promise<LazyPluginModule>;\n}): MagicPluginDefinition | StorePluginDefinition | HybridPluginDefinition {\n const { import: importModule, ...rest } = definition;\n const plugin = async () => {\n const module = await importModule();\n return resolvePluginLoader(module.default);\n };\n\n switch (rest.kind) {\n case \"magic\":\n return defineMagicPlugin(rest.magics ?? [], plugin);\n case \"store\":\n return defineStorePlugin(rest.stores ?? [], plugin);\n case \"both\":\n return defineHybridPlugin({\n magics: rest.magics,\n stores: rest.stores,\n plugin,\n });\n }\n}\n","import type AlpineType from \"alpinejs\";\nimport { resolvePluginLoader, resolvePluginLoaderSync } from \"./loader.js\";\nimport { markPluginInitialized, resolvePluginEntries } from \"./registry.js\";\nimport type { PluginDefinition, RegisteredPlugin } from \"./types.js\";\n\nexport {\n defineHybridPlugin,\n defineMagicPlugin,\n defineStorePlugin,\n lazyPlugin,\n} from \"./define.js\";\nexport { PluginLoaderError } from \"./loader.js\";\nexport {\n getRegisteredPlugin,\n getRegisteredPlugins,\n isPluginInitialized,\n registerPlugin,\n resetPluginRegistry,\n unregisterPlugin,\n} from \"./registry.js\";\nexport type {\n AlpinePluginCallback,\n HybridPluginDefinition,\n MagicPluginDefinition,\n PluginDefinition,\n PluginLoader,\n PluginRegistryEntry,\n RegisteredPlugin,\n StorePluginDefinition,\n} from \"./types.js\";\n\nfunction toRegisteredPlugin(entry: {\n name: string;\n definition: PluginDefinition;\n}): RegisteredPlugin {\n return {\n name: entry.name,\n definition: entry.definition,\n };\n}\n\nasync function initializeEntry(\n Alpine: AlpineType.Alpine,\n entry: ReturnType<typeof resolvePluginEntries>[number]\n): Promise<void> {\n if (entry.initialized) {\n return;\n }\n\n const callback = await resolvePluginLoader(entry.definition.plugin);\n Alpine.plugin(callback);\n markPluginInitialized(entry.name);\n}\n\n/**\n * Initializes registered plugins on demand. Supports async dynamic imports.\n * Call before `Alpine.start()` in SSR and client entrypoints.\n */\nexport async function initPlugins(\n Alpine: AlpineType.Alpine,\n names?: string | readonly string[]\n): Promise<readonly RegisteredPlugin[]> {\n const entries = resolvePluginEntries(names);\n\n for (const entry of entries) {\n await initializeEntry(Alpine, entry);\n }\n\n return entries.map(toRegisteredPlugin);\n}\n\n/**\n * Initializes registered plugins synchronously.\n * Throws when a plugin uses an async loader — use `initPlugins()` instead.\n */\nexport function initPluginsSync(\n Alpine: AlpineType.Alpine,\n names?: string | readonly string[]\n): readonly RegisteredPlugin[] {\n const entries = resolvePluginEntries(names);\n\n for (const entry of entries) {\n if (entry.initialized) {\n continue;\n }\n\n const callback = resolvePluginLoaderSync(entry.definition.plugin);\n Alpine.plugin(callback);\n markPluginInitialized(entry.name);\n }\n\n return entries.map(toRegisteredPlugin);\n}\n\n/**\n * Returns an Alpine.js plugin callback that initializes the given registered plugins.\n * Only supports sync loaders — use `initPlugins()` for dynamic imports.\n */\nexport function createAlpinePlugin(names?: string | readonly string[]): AlpineType.PluginCallback {\n return (Alpine) => {\n initPluginsSync(Alpine, names);\n };\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@ailuracode/alpine-core",
3
+ "version": "0.1.0",
4
+ "description": "Lazy plugin registry and initializer for Alpine.js",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "ailuracode",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/ailuracode/alpine.git",
14
+ "directory": "packages/core"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/ailuracode/alpine/issues"
18
+ },
19
+ "homepage": "https://github.com/ailuracode/alpine/tree/master/packages/core#readme",
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "./global": {
30
+ "types": "./dist/global.d.ts"
31
+ }
32
+ },
33
+ "types": "./dist/global.d.ts",
34
+ "peerDependencies": {
35
+ "alpinejs": "^3.0.0",
36
+ "@types/alpinejs": "^3.13.11"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "@types/alpinejs": {
40
+ "optional": true
41
+ }
42
+ },
43
+ "keywords": [
44
+ "alpinejs",
45
+ "alpine",
46
+ "plugin",
47
+ "lazy",
48
+ "registry",
49
+ "tree-shaking"
50
+ ],
51
+ "scripts": {
52
+ "build": "tsup src/index.ts --format esm --dts --clean --sourcemap --out-dir dist && cp src/global.d.ts dist/global.d.ts",
53
+ "test": "vitest run --config ../../vitest.config.js test"
54
+ }
55
+ }