@holo-js/adapter-next 0.1.3 → 0.1.5
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/client.d.ts +4 -4
- package/dist/client.mjs +12 -10
- package/dist/config.d.ts +19 -0
- package/dist/config.mjs +133 -0
- package/dist/runtime.d.ts +137 -0
- package/dist/runtime.mjs +169 -0
- package/package.json +18 -5
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
export { ClientSubmitContext, ClientSubmitResult, FormFieldState, FormFieldTree, UseFormOptions, UseFormResult, ValidateOnMode } from '@holo-js/forms/client';
|
|
1
|
+
import { FormSchema, InferFormData } from '@holo-js/forms';
|
|
2
|
+
import { UseFormOptions, UseFormResult, InferFormFieldTree } from '@holo-js/forms/internal/client';
|
|
3
|
+
export { ClientSubmitContext, ClientSubmitResult, FormFieldState, FormFieldTree, UseFormOptions, UseFormResult, ValidateOnMode } from '@holo-js/forms/internal/client';
|
|
4
4
|
|
|
5
|
-
declare function useForm<TSchema extends
|
|
5
|
+
declare function useForm<TSchema extends FormSchema, TSuccess = unknown>(schemaDefinition: TSchema, options?: UseFormOptions<InferFormData<TSchema>, TSuccess>): UseFormResult<InferFormData<TSchema>, TSuccess, InferFormFieldTree<TSchema>>;
|
|
6
6
|
|
|
7
7
|
export { useForm };
|
package/dist/client.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
// src/client.ts
|
|
2
4
|
import { useEffect, useRef, useState } from "react";
|
|
3
5
|
import {
|
|
4
|
-
|
|
5
|
-
} from "@holo-js/forms/client";
|
|
6
|
+
createFormClient
|
|
7
|
+
} from "@holo-js/forms/internal/client";
|
|
6
8
|
function isPlainObject(value) {
|
|
7
9
|
return !!value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof Blob);
|
|
8
10
|
}
|
|
@@ -27,7 +29,7 @@ function areEqual(left, right) {
|
|
|
27
29
|
return false;
|
|
28
30
|
}
|
|
29
31
|
function areOptionsEqual(left, right) {
|
|
30
|
-
return left.action === right.action && left.method === right.method && left.
|
|
32
|
+
return left.action === right.action && left.method === right.method && left.validateOn === right.validateOn && Boolean(left.submitter) === Boolean(right.submitter) && areEqual(left.initialValues, right.initialValues) && areEqual(left.initialState, right.initialState);
|
|
31
33
|
}
|
|
32
34
|
function createSubmitterBridge(optionsRef) {
|
|
33
35
|
return (context) => {
|
|
@@ -39,11 +41,11 @@ function createSubmitterBridge(optionsRef) {
|
|
|
39
41
|
};
|
|
40
42
|
}
|
|
41
43
|
function useForm(schemaDefinition, options = {}) {
|
|
42
|
-
const formRef = useRef();
|
|
43
|
-
const previousSchemaRef = useRef();
|
|
44
|
-
const previousOptionsRef = useRef();
|
|
45
|
-
const latestOptionsRef = useRef();
|
|
46
|
-
const submitterBridgeRef = useRef();
|
|
44
|
+
const formRef = useRef(void 0);
|
|
45
|
+
const previousSchemaRef = useRef(void 0);
|
|
46
|
+
const previousOptionsRef = useRef(void 0);
|
|
47
|
+
const latestOptionsRef = useRef(void 0);
|
|
48
|
+
const submitterBridgeRef = useRef(void 0);
|
|
47
49
|
const [, setVersion] = useState(0);
|
|
48
50
|
latestOptionsRef.current = options;
|
|
49
51
|
if (options.submitter && !submitterBridgeRef.current) {
|
|
@@ -54,13 +56,13 @@ function useForm(schemaDefinition, options = {}) {
|
|
|
54
56
|
submitter: submitterBridgeRef.current
|
|
55
57
|
} : options;
|
|
56
58
|
if (!formRef.current || previousSchemaRef.current !== schemaDefinition) {
|
|
57
|
-
formRef.current =
|
|
59
|
+
formRef.current = createFormClient(schemaDefinition, resolvedOptions);
|
|
58
60
|
previousSchemaRef.current = schemaDefinition;
|
|
59
61
|
previousOptionsRef.current = options;
|
|
60
62
|
} else {
|
|
61
63
|
const previousOptions = previousOptionsRef.current;
|
|
62
64
|
if (!areOptionsEqual(previousOptions, options)) {
|
|
63
|
-
formRef.current =
|
|
65
|
+
formRef.current = createFormClient(schemaDefinition, resolvedOptions);
|
|
64
66
|
previousOptionsRef.current = options;
|
|
65
67
|
}
|
|
66
68
|
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface TurbopackIgnoreIssueRule {
|
|
2
|
+
readonly path: string | RegExp;
|
|
3
|
+
readonly title?: string | RegExp;
|
|
4
|
+
}
|
|
5
|
+
interface TurbopackConfig {
|
|
6
|
+
readonly ignoreIssue?: readonly TurbopackIgnoreIssueRule[];
|
|
7
|
+
readonly [key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
interface NextConfig {
|
|
10
|
+
readonly serverExternalPackages?: string[];
|
|
11
|
+
readonly outputFileTracingExcludes?: Record<string, string[]>;
|
|
12
|
+
readonly experimental?: Record<string, unknown>;
|
|
13
|
+
readonly turbopack?: TurbopackConfig;
|
|
14
|
+
readonly rewrites?: () => Promise<unknown>;
|
|
15
|
+
readonly [key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
declare function withHolo<TConfig extends NextConfig>(nextConfig?: TConfig): TConfig;
|
|
18
|
+
|
|
19
|
+
export { withHolo };
|
package/dist/config.mjs
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
var HOLO_SERVER_EXTERNAL_PACKAGES = [
|
|
5
|
+
"@holo-js/core",
|
|
6
|
+
"@holo-js/adapter-next",
|
|
7
|
+
"@holo-js/db",
|
|
8
|
+
"@holo-js/config",
|
|
9
|
+
"esbuild"
|
|
10
|
+
];
|
|
11
|
+
var HOLO_OPTIONAL_SERVER_EXTERNAL_PACKAGES = [
|
|
12
|
+
"@holo-js/auth",
|
|
13
|
+
"@holo-js/auth-clerk",
|
|
14
|
+
"@holo-js/auth-social",
|
|
15
|
+
"@holo-js/auth-social-apple",
|
|
16
|
+
"@holo-js/auth-social-discord",
|
|
17
|
+
"@holo-js/auth-social-facebook",
|
|
18
|
+
"@holo-js/auth-social-github",
|
|
19
|
+
"@holo-js/auth-social-google",
|
|
20
|
+
"@holo-js/auth-social-linkedin",
|
|
21
|
+
"@holo-js/auth-workos",
|
|
22
|
+
"@holo-js/authorization",
|
|
23
|
+
"@holo-js/broadcast",
|
|
24
|
+
"@holo-js/cache",
|
|
25
|
+
"@holo-js/cache-db",
|
|
26
|
+
"@holo-js/cache-redis",
|
|
27
|
+
"@holo-js/events",
|
|
28
|
+
"@holo-js/forms",
|
|
29
|
+
"@holo-js/mail",
|
|
30
|
+
"@holo-js/notifications",
|
|
31
|
+
"@holo-js/queue",
|
|
32
|
+
"@holo-js/queue-db",
|
|
33
|
+
"@holo-js/queue-redis",
|
|
34
|
+
"@holo-js/security",
|
|
35
|
+
"@holo-js/session",
|
|
36
|
+
"@holo-js/storage",
|
|
37
|
+
"@holo-js/storage-s3",
|
|
38
|
+
"@holo-js/validation"
|
|
39
|
+
];
|
|
40
|
+
var PACKAGE_DEPENDENCY_FIELDS = [
|
|
41
|
+
"dependencies",
|
|
42
|
+
"devDependencies",
|
|
43
|
+
"optionalDependencies",
|
|
44
|
+
"peerDependencies"
|
|
45
|
+
];
|
|
46
|
+
function isPackageDependencyMap(value) {
|
|
47
|
+
return value !== null && typeof value === "object" && Object.values(value).every((dependency) => typeof dependency === "string");
|
|
48
|
+
}
|
|
49
|
+
function readProjectPackageManifest() {
|
|
50
|
+
try {
|
|
51
|
+
const parsed = JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf8"));
|
|
52
|
+
if (!parsed || typeof parsed !== "object") {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const manifest = {};
|
|
56
|
+
for (const field of PACKAGE_DEPENDENCY_FIELDS) {
|
|
57
|
+
const dependencies = parsed[field];
|
|
58
|
+
if (isPackageDependencyMap(dependencies)) {
|
|
59
|
+
manifest[field] = dependencies;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return manifest;
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function isOptionalServerExternalPackageInstalled(packageName, manifest) {
|
|
68
|
+
return PACKAGE_DEPENDENCY_FIELDS.some((field) => Boolean(manifest?.[field]?.[packageName]));
|
|
69
|
+
}
|
|
70
|
+
function withHolo(nextConfig = {}) {
|
|
71
|
+
const existingExternal = nextConfig.serverExternalPackages ?? [];
|
|
72
|
+
const packageManifest = readProjectPackageManifest();
|
|
73
|
+
const installedOptionalExternal = HOLO_OPTIONAL_SERVER_EXTERNAL_PACKAGES.filter((packageName) => isOptionalServerExternalPackageInstalled(packageName, packageManifest));
|
|
74
|
+
const mergedExternal = [
|
|
75
|
+
.../* @__PURE__ */ new Set([...HOLO_SERVER_EXTERNAL_PACKAGES, ...installedOptionalExternal, ...existingExternal])
|
|
76
|
+
];
|
|
77
|
+
const existingExcludes = nextConfig.outputFileTracingExcludes ?? {};
|
|
78
|
+
const existingGlobalExcludes = existingExcludes["/*"] ?? [];
|
|
79
|
+
const mergedExcludes = {
|
|
80
|
+
...existingExcludes,
|
|
81
|
+
"/*": [.../* @__PURE__ */ new Set(["./next.config.ts", "./next.config.mjs", "./next.config.js", ...existingGlobalExcludes])]
|
|
82
|
+
};
|
|
83
|
+
const existingTurbopack = nextConfig.turbopack ?? {};
|
|
84
|
+
const existingIgnoreIssue = existingTurbopack.ignoreIssue ?? [];
|
|
85
|
+
const mergedTurbopack = {
|
|
86
|
+
...existingTurbopack,
|
|
87
|
+
ignoreIssue: [
|
|
88
|
+
...existingIgnoreIssue,
|
|
89
|
+
{
|
|
90
|
+
path: /next\.config\.(ts|mjs|js)$/,
|
|
91
|
+
title: /Encountered unexpected file in NFT list/
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
};
|
|
95
|
+
const userRewrites = nextConfig.rewrites;
|
|
96
|
+
return {
|
|
97
|
+
...nextConfig,
|
|
98
|
+
experimental: {
|
|
99
|
+
...nextConfig.experimental ?? {},
|
|
100
|
+
authInterrupts: true
|
|
101
|
+
},
|
|
102
|
+
serverExternalPackages: mergedExternal,
|
|
103
|
+
outputFileTracingExcludes: mergedExcludes,
|
|
104
|
+
turbopack: mergedTurbopack,
|
|
105
|
+
async rewrites() {
|
|
106
|
+
const userResult = await userRewrites?.call(this);
|
|
107
|
+
const raw = process.env.STORAGE_ROUTE_PREFIX?.trim() ?? "/storage";
|
|
108
|
+
const needsRewrite = raw && raw !== "/" && raw !== "/storage";
|
|
109
|
+
if (!needsRewrite) {
|
|
110
|
+
return userResult ?? [];
|
|
111
|
+
}
|
|
112
|
+
const storageRoutePrefix = `/${raw.replace(/^\/+|\/+$/g, "")}`;
|
|
113
|
+
const holoRewrite = {
|
|
114
|
+
source: `${storageRoutePrefix}/:path*`,
|
|
115
|
+
destination: "/storage/:path*"
|
|
116
|
+
};
|
|
117
|
+
if (Array.isArray(userResult)) {
|
|
118
|
+
return [...userResult, holoRewrite];
|
|
119
|
+
}
|
|
120
|
+
if (userResult && typeof userResult === "object" && !Array.isArray(userResult)) {
|
|
121
|
+
const shaped = userResult;
|
|
122
|
+
return {
|
|
123
|
+
...shaped,
|
|
124
|
+
beforeFiles: [...Array.isArray(shaped.beforeFiles) ? shaped.beforeFiles : [], holoRewrite]
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return [holoRewrite];
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export {
|
|
132
|
+
withHolo
|
|
133
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import * as _holo_js_core from '@holo-js/core';
|
|
2
|
+
import { CreateHoloOptions } from '@holo-js/core';
|
|
3
|
+
import { HoloConfigMap, LoadedHoloConfig, DotPath, ValueAtPath } from '@holo-js/config';
|
|
4
|
+
|
|
5
|
+
interface GeneratedModelRegistryEntry {
|
|
6
|
+
readonly sourcePath: string;
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly prunable: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface GeneratedMigrationRegistryEntry {
|
|
11
|
+
readonly sourcePath: string;
|
|
12
|
+
readonly name: string;
|
|
13
|
+
}
|
|
14
|
+
interface GeneratedSeederRegistryEntry {
|
|
15
|
+
readonly sourcePath: string;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
}
|
|
18
|
+
interface GeneratedCommandRegistryEntry {
|
|
19
|
+
readonly sourcePath: string;
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly aliases: readonly string[];
|
|
22
|
+
readonly description: string;
|
|
23
|
+
readonly usage?: string;
|
|
24
|
+
}
|
|
25
|
+
interface GeneratedJobRegistryEntry {
|
|
26
|
+
readonly sourcePath: string;
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly connection?: string;
|
|
29
|
+
readonly queue?: string;
|
|
30
|
+
readonly tries?: number;
|
|
31
|
+
readonly backoff?: number | readonly number[];
|
|
32
|
+
readonly timeout?: number;
|
|
33
|
+
}
|
|
34
|
+
interface GeneratedEventRegistryEntry {
|
|
35
|
+
readonly sourcePath: string;
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly exportName?: string;
|
|
38
|
+
}
|
|
39
|
+
interface GeneratedListenerRegistryEntry {
|
|
40
|
+
readonly sourcePath: string;
|
|
41
|
+
readonly id: string;
|
|
42
|
+
readonly eventNames: readonly string[];
|
|
43
|
+
readonly exportName?: string;
|
|
44
|
+
}
|
|
45
|
+
interface GeneratedBroadcastRegistryEntry {
|
|
46
|
+
readonly sourcePath: string;
|
|
47
|
+
readonly name: string;
|
|
48
|
+
readonly exportName?: string;
|
|
49
|
+
readonly channels: readonly {
|
|
50
|
+
readonly type: 'public' | 'private' | 'presence';
|
|
51
|
+
readonly pattern: string;
|
|
52
|
+
}[];
|
|
53
|
+
}
|
|
54
|
+
interface GeneratedChannelRegistryEntry {
|
|
55
|
+
readonly sourcePath: string;
|
|
56
|
+
readonly pattern: string;
|
|
57
|
+
readonly exportName?: string;
|
|
58
|
+
readonly type: 'private' | 'presence';
|
|
59
|
+
readonly params: readonly string[];
|
|
60
|
+
readonly whispers: readonly string[];
|
|
61
|
+
}
|
|
62
|
+
interface GeneratedAuthorizationPolicyRegistryEntry {
|
|
63
|
+
readonly sourcePath: string;
|
|
64
|
+
readonly name: string;
|
|
65
|
+
readonly exportName?: string;
|
|
66
|
+
readonly target: string;
|
|
67
|
+
readonly classActions: readonly string[];
|
|
68
|
+
readonly recordActions: readonly string[];
|
|
69
|
+
}
|
|
70
|
+
interface GeneratedAuthorizationAbilityRegistryEntry {
|
|
71
|
+
readonly sourcePath: string;
|
|
72
|
+
readonly name: string;
|
|
73
|
+
readonly exportName?: string;
|
|
74
|
+
}
|
|
75
|
+
interface GeneratedProjectRegistry {
|
|
76
|
+
readonly version: 1;
|
|
77
|
+
readonly generatedAt: string;
|
|
78
|
+
readonly paths: {
|
|
79
|
+
readonly models: string;
|
|
80
|
+
readonly migrations: string;
|
|
81
|
+
readonly seeders: string;
|
|
82
|
+
readonly commands: string;
|
|
83
|
+
readonly jobs: string;
|
|
84
|
+
readonly events: string;
|
|
85
|
+
readonly listeners: string;
|
|
86
|
+
readonly broadcast: string;
|
|
87
|
+
readonly channels: string;
|
|
88
|
+
readonly authorizationPolicies: string;
|
|
89
|
+
readonly authorizationAbilities: string;
|
|
90
|
+
readonly generatedSchema: string;
|
|
91
|
+
};
|
|
92
|
+
readonly models: readonly GeneratedModelRegistryEntry[];
|
|
93
|
+
readonly migrations: readonly GeneratedMigrationRegistryEntry[];
|
|
94
|
+
readonly seeders: readonly GeneratedSeederRegistryEntry[];
|
|
95
|
+
readonly commands: readonly GeneratedCommandRegistryEntry[];
|
|
96
|
+
readonly jobs: readonly GeneratedJobRegistryEntry[];
|
|
97
|
+
readonly events: readonly GeneratedEventRegistryEntry[];
|
|
98
|
+
readonly listeners: readonly GeneratedListenerRegistryEntry[];
|
|
99
|
+
readonly broadcast: readonly GeneratedBroadcastRegistryEntry[];
|
|
100
|
+
readonly channels: readonly GeneratedChannelRegistryEntry[];
|
|
101
|
+
readonly authorizationPolicies: readonly GeneratedAuthorizationPolicyRegistryEntry[];
|
|
102
|
+
readonly authorizationAbilities: readonly GeneratedAuthorizationAbilityRegistryEntry[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
type NextRequestLike = {
|
|
106
|
+
readonly cookies: {
|
|
107
|
+
get(name: string): {
|
|
108
|
+
readonly value: string;
|
|
109
|
+
} | undefined;
|
|
110
|
+
};
|
|
111
|
+
readonly headers: Headers;
|
|
112
|
+
};
|
|
113
|
+
declare function runWithNextRequest<TValue>(request: NextRequestLike, callback: () => TValue): TValue;
|
|
114
|
+
|
|
115
|
+
type NextHoloRuntimeOptions = CreateHoloOptions & {
|
|
116
|
+
readonly projectRoot: string;
|
|
117
|
+
};
|
|
118
|
+
declare function createNextHoloHelpers<TCustom extends HoloConfigMap = HoloConfigMap>(options: NextHoloRuntimeOptions): {
|
|
119
|
+
getApp(): Promise<{
|
|
120
|
+
projectRoot: string;
|
|
121
|
+
config: LoadedHoloConfig<TCustom>;
|
|
122
|
+
registry: GeneratedProjectRegistry | undefined;
|
|
123
|
+
runtime: _holo_js_core.HoloRuntime<TCustom>;
|
|
124
|
+
}>;
|
|
125
|
+
getProject(): Promise<{
|
|
126
|
+
projectRoot: string;
|
|
127
|
+
config: LoadedHoloConfig<TCustom>;
|
|
128
|
+
registry: GeneratedProjectRegistry | undefined;
|
|
129
|
+
runtime: _holo_js_core.HoloRuntime<TCustom>;
|
|
130
|
+
}>;
|
|
131
|
+
getSession(): Promise<_holo_js_core.HoloSessionRuntimeBinding | undefined>;
|
|
132
|
+
getAuth(): Promise<_holo_js_core.HoloAuthRuntimeBinding | undefined>;
|
|
133
|
+
useConfig: <TPath extends DotPath<LoadedHoloConfig<TCustom>["all"]>>(path: TPath) => Promise<ValueAtPath<LoadedHoloConfig<TCustom>["all"], TPath>>;
|
|
134
|
+
config: <TPath extends DotPath<LoadedHoloConfig<TCustom>["all"]>>(path: TPath) => Promise<ValueAtPath<LoadedHoloConfig<TCustom>["all"], TPath>>;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export { type NextHoloRuntimeOptions, type NextRequestLike, createNextHoloHelpers, runWithNextRequest };
|
package/dist/runtime.mjs
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// src/runtime.ts
|
|
2
|
+
import { cookies, headers } from "next/headers";
|
|
3
|
+
import { forbidden, notFound } from "next/navigation";
|
|
4
|
+
import { initializeHolo } from "@holo-js/core";
|
|
5
|
+
|
|
6
|
+
// src/request-context.ts
|
|
7
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
8
|
+
function getNextRequestStore() {
|
|
9
|
+
const globals = globalThis;
|
|
10
|
+
globals.__holoNextAuthRequestStore ??= new AsyncLocalStorage();
|
|
11
|
+
return globals.__holoNextAuthRequestStore;
|
|
12
|
+
}
|
|
13
|
+
function getCurrentNextRequest() {
|
|
14
|
+
return getNextRequestStore().getStore();
|
|
15
|
+
}
|
|
16
|
+
function runWithNextRequest(request, callback) {
|
|
17
|
+
return getNextRequestStore().run(request, callback);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/runtime.ts
|
|
21
|
+
function safeDecodeCookieSegment(value) {
|
|
22
|
+
try {
|
|
23
|
+
return decodeURIComponent(value);
|
|
24
|
+
} catch {
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function parseResponseCookie(cookie) {
|
|
29
|
+
const [nameValue, ...attributes] = cookie.split(";");
|
|
30
|
+
const separator = nameValue?.indexOf("=") ?? -1;
|
|
31
|
+
if (!nameValue || separator <= 0) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const options = {};
|
|
35
|
+
for (const rawAttribute of attributes) {
|
|
36
|
+
const attribute = rawAttribute.trim();
|
|
37
|
+
if (!attribute) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const attributeSeparator = attribute.indexOf("=");
|
|
41
|
+
const key = (attributeSeparator === -1 ? attribute : attribute.slice(0, attributeSeparator)).trim().toLowerCase();
|
|
42
|
+
const value = attributeSeparator === -1 ? "" : attribute.slice(attributeSeparator + 1).trim();
|
|
43
|
+
switch (key) {
|
|
44
|
+
case "path":
|
|
45
|
+
options.path = value;
|
|
46
|
+
break;
|
|
47
|
+
case "domain":
|
|
48
|
+
options.domain = value;
|
|
49
|
+
break;
|
|
50
|
+
case "max-age": {
|
|
51
|
+
const maxAge = Number(value);
|
|
52
|
+
if (Number.isFinite(maxAge)) {
|
|
53
|
+
options.maxAge = maxAge;
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
case "expires": {
|
|
58
|
+
const expires = new Date(value);
|
|
59
|
+
if (!Number.isNaN(expires.getTime())) {
|
|
60
|
+
options.expires = expires;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case "secure":
|
|
65
|
+
options.secure = true;
|
|
66
|
+
break;
|
|
67
|
+
case "httponly":
|
|
68
|
+
options.httpOnly = true;
|
|
69
|
+
break;
|
|
70
|
+
case "samesite":
|
|
71
|
+
if (value.toLowerCase() === "lax" || value.toLowerCase() === "strict" || value.toLowerCase() === "none") {
|
|
72
|
+
options.sameSite = value.toLowerCase();
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case "partitioned":
|
|
76
|
+
options.partitioned = true;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
name: safeDecodeCookieSegment(nameValue.slice(0, separator)),
|
|
82
|
+
value: safeDecodeCookieSegment(nameValue.slice(separator + 1)),
|
|
83
|
+
options
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function resolveNextAuthRequestAccessors() {
|
|
87
|
+
return {
|
|
88
|
+
async getCookie(name) {
|
|
89
|
+
const request = getCurrentNextRequest();
|
|
90
|
+
if (request) {
|
|
91
|
+
return request.cookies.get(name)?.value;
|
|
92
|
+
}
|
|
93
|
+
const store = await cookies();
|
|
94
|
+
return store.get(name)?.value;
|
|
95
|
+
},
|
|
96
|
+
async getHeader(name) {
|
|
97
|
+
const request = getCurrentNextRequest();
|
|
98
|
+
if (request) {
|
|
99
|
+
return request.headers.get(name) ?? void 0;
|
|
100
|
+
}
|
|
101
|
+
const requestHeaders = await headers();
|
|
102
|
+
return requestHeaders.get(name) ?? void 0;
|
|
103
|
+
},
|
|
104
|
+
async appendResponseCookie(cookie) {
|
|
105
|
+
const parsed = parseResponseCookie(cookie);
|
|
106
|
+
if (!parsed) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const store = await cookies();
|
|
110
|
+
store.set(parsed.name, parsed.value, parsed.options);
|
|
111
|
+
},
|
|
112
|
+
async redirectResponse(url) {
|
|
113
|
+
const { redirect } = await import("next/navigation");
|
|
114
|
+
redirect(url);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function createNextHoloHelpers(options) {
|
|
119
|
+
const resolveRuntime = async () => await initializeHolo(options.projectRoot, {
|
|
120
|
+
...options,
|
|
121
|
+
authRequest: options.authRequest ?? resolveNextAuthRequestAccessors(),
|
|
122
|
+
authorizationError: options.authorizationError ?? {
|
|
123
|
+
createError(decision) {
|
|
124
|
+
if (decision.status === 404) {
|
|
125
|
+
notFound();
|
|
126
|
+
}
|
|
127
|
+
forbidden();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
const useConfig = async (path) => {
|
|
132
|
+
const runtime = await resolveRuntime();
|
|
133
|
+
return runtime.config(path);
|
|
134
|
+
};
|
|
135
|
+
return {
|
|
136
|
+
async getApp() {
|
|
137
|
+
const runtime = await resolveRuntime();
|
|
138
|
+
return {
|
|
139
|
+
projectRoot: runtime.projectRoot,
|
|
140
|
+
config: runtime.loadedConfig,
|
|
141
|
+
registry: runtime.registry,
|
|
142
|
+
runtime
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
async getProject() {
|
|
146
|
+
const runtime = await resolveRuntime();
|
|
147
|
+
return {
|
|
148
|
+
projectRoot: runtime.projectRoot,
|
|
149
|
+
config: runtime.loadedConfig,
|
|
150
|
+
registry: runtime.registry,
|
|
151
|
+
runtime
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
async getSession() {
|
|
155
|
+
const runtime = await resolveRuntime();
|
|
156
|
+
return runtime.session;
|
|
157
|
+
},
|
|
158
|
+
async getAuth() {
|
|
159
|
+
const runtime = await resolveRuntime();
|
|
160
|
+
return runtime.auth;
|
|
161
|
+
},
|
|
162
|
+
useConfig,
|
|
163
|
+
config: useConfig
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
export {
|
|
167
|
+
createNextHoloHelpers,
|
|
168
|
+
runWithNextRequest
|
|
169
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/adapter-next",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Holo-JS Framework - Next.js adapter",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,10 +10,20 @@
|
|
|
10
10
|
"import": "./dist/index.mjs",
|
|
11
11
|
"default": "./dist/index.mjs"
|
|
12
12
|
},
|
|
13
|
+
"./config": {
|
|
14
|
+
"types": "./dist/config.d.ts",
|
|
15
|
+
"import": "./dist/config.mjs",
|
|
16
|
+
"default": "./dist/config.mjs"
|
|
17
|
+
},
|
|
13
18
|
"./client": {
|
|
14
19
|
"types": "./dist/client.d.ts",
|
|
15
20
|
"import": "./dist/client.mjs",
|
|
16
21
|
"default": "./dist/client.mjs"
|
|
22
|
+
},
|
|
23
|
+
"./runtime": {
|
|
24
|
+
"types": "./dist/runtime.d.ts",
|
|
25
|
+
"import": "./dist/runtime.mjs",
|
|
26
|
+
"default": "./dist/runtime.mjs"
|
|
17
27
|
}
|
|
18
28
|
},
|
|
19
29
|
"main": "./dist/index.mjs",
|
|
@@ -28,11 +38,13 @@
|
|
|
28
38
|
"test": "vitest --run"
|
|
29
39
|
},
|
|
30
40
|
"dependencies": {
|
|
31
|
-
"@holo-js/config": "^0.1.
|
|
32
|
-
"@holo-js/core": "^0.1.
|
|
41
|
+
"@holo-js/config": "^0.1.5",
|
|
42
|
+
"@holo-js/core": "^0.1.5"
|
|
33
43
|
},
|
|
34
44
|
"peerDependencies": {
|
|
35
|
-
"@holo-js/forms": "^0.1.
|
|
45
|
+
"@holo-js/forms": "^0.1.5",
|
|
46
|
+
"next": "^16.2.4",
|
|
47
|
+
"react": "^19.2.6"
|
|
36
48
|
},
|
|
37
49
|
"peerDependenciesMeta": {
|
|
38
50
|
"@holo-js/forms": {
|
|
@@ -41,8 +53,9 @@
|
|
|
41
53
|
},
|
|
42
54
|
"devDependencies": {
|
|
43
55
|
"@types/node": "^22.10.2",
|
|
56
|
+
"next": "^16.2.4",
|
|
44
57
|
"tsup": "^8.3.5",
|
|
45
58
|
"typescript": "^5.7.2",
|
|
46
|
-
"vitest": "^
|
|
59
|
+
"vitest": "^4.1.5"
|
|
47
60
|
}
|
|
48
61
|
}
|