@pikku/core 0.12.139 → 0.12.141
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/CHANGELOG.md +14 -0
- package/dist/lifecycle.d.ts +6 -0
- package/dist/lifecycle.js +58 -0
- package/dist/services/scoped-secret-service.d.ts +1 -0
- package/dist/services/scoped-secret-service.js +3 -0
- package/dist/services/secret-service.d.ts +6 -0
- package/dist/services/typed-secret-service.d.ts +1 -0
- package/dist/services/typed-secret-service.js +7 -0
- package/dist/testing/service-tests/secret-service-tests.js +9 -0
- package/dist/utils.d.ts +2 -5
- package/dist/utils.js +1 -38
- package/dist/wirings/cli/cli-runner.js +24 -9
- package/dist/wirings/http/http-runner.js +4 -0
- package/dist/wirings/http/http.types.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-response.js +12 -0
- package/dist/wirings/http/web-request.js +7 -0
- package/package.json +2 -1
- package/src/public-surface.json +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 0.12.141
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- b04e444: Fix CLI commands that come from an addon package. Auth and permissions set on such a command are now merged into the addon's own function instead of replacing it, and the command's input is shaped by the addon's own schema (for example a comma list becomes an array). The inspector now also resolves `...refCLI('addon:contract')`, spreads and `defineCLICommands` identifiers inside a command's `subcommands`.
|
|
6
|
+
- d3d8a98: Graceful shutdown ignores repeat signals. A second SIGTERM or SIGINT arriving while `beforeStop` and the service teardown are still running no longer falls through to the default handler and kills the process mid-cleanup. `@pikku/core/lifecycle` is a new entry point holding `onShutdownSignals`, `stopSingletonServices` and `pikkuServerLifecycle` (the latter two stay re-exported from `utils`), which the server runtimes now share.
|
|
7
|
+
- 658da50: `SecretService` gains an optional `setEncryptedSecret(key, sealed)` for stores that hold a sealing key, so a browser can seal a secret and the caller's process never sees the plaintext.
|
|
8
|
+
|
|
9
|
+
## 0.12.140
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- f396538: Event-stream responses pass through `applyWebResponse` without being read, so an SSE route can proxy another stream. HTTP responses gain `onClose`, which `executeRoute` uses to tell an SSE route's event hub when the client leaves. `pikku all` wires the console's `/meta/stream` route to `console:streamMetaChanges`.
|
|
14
|
+
|
|
1
15
|
## 0.12.139
|
|
2
16
|
|
|
3
17
|
### Patch Changes
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CoreSingletonServices, ServerLifecycle } from './types/core.types.js';
|
|
2
|
+
/** Stops addon package services first, then the parent singleton services. */
|
|
3
|
+
export declare const stopSingletonServices: () => Promise<void>;
|
|
4
|
+
/** Wrap server lifecycle hooks so the inspector can discover them. */
|
|
5
|
+
export declare const pikkuServerLifecycle: <SS extends CoreSingletonServices = CoreSingletonServices>(lifecycle: ServerLifecycle<SS>) => ServerLifecycle<SS>;
|
|
6
|
+
export declare const onShutdownSignals: (run: (signal: NodeJS.Signals) => void | Promise<void>, signals?: NodeJS.Signals[]) => (() => void);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { getSingletonServices, getAllPackageStates } from './pikku-state.js';
|
|
2
|
+
const stopService = async (logger, name, service) => {
|
|
3
|
+
const stop = service?.stop;
|
|
4
|
+
if (stop) {
|
|
5
|
+
logger.info(`Stopping singleton service: ${name}`);
|
|
6
|
+
try {
|
|
7
|
+
await stop.call(service);
|
|
8
|
+
}
|
|
9
|
+
catch (e) {
|
|
10
|
+
logger.error(`Error stopping service ${name}:`, e);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/** Stops addon package services first, then the parent singleton services. */
|
|
15
|
+
export const stopSingletonServices = async () => {
|
|
16
|
+
const singletonServices = getSingletonServices();
|
|
17
|
+
const logger = singletonServices.logger;
|
|
18
|
+
const stateMap = getAllPackageStates();
|
|
19
|
+
if (stateMap.size > 0) {
|
|
20
|
+
for (const [packageName, packageState] of stateMap) {
|
|
21
|
+
if (packageName === '__main__')
|
|
22
|
+
continue;
|
|
23
|
+
const packageServices = packageState.package?.singletonServices;
|
|
24
|
+
if (packageServices) {
|
|
25
|
+
logger.info(`Stopping singleton services for package: ${packageName}`);
|
|
26
|
+
for (const [name, service] of Object.entries(packageServices)) {
|
|
27
|
+
await stopService(logger, `${packageName}/${name}`, service);
|
|
28
|
+
}
|
|
29
|
+
packageState.package.singletonServices = null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const [name, service] of Object.entries(singletonServices)) {
|
|
34
|
+
await stopService(logger, name, service);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/** Wrap server lifecycle hooks so the inspector can discover them. */
|
|
38
|
+
export const pikkuServerLifecycle = (lifecycle) => lifecycle;
|
|
39
|
+
export const onShutdownSignals = (run, signals = ['SIGINT', 'SIGTERM']) => {
|
|
40
|
+
const proc = typeof process !== 'undefined' ? process : undefined;
|
|
41
|
+
if (!proc?.on)
|
|
42
|
+
return () => { };
|
|
43
|
+
let stopping = false;
|
|
44
|
+
const handlers = signals.map((signal) => {
|
|
45
|
+
const handler = () => {
|
|
46
|
+
if (stopping)
|
|
47
|
+
return;
|
|
48
|
+
stopping = true;
|
|
49
|
+
void run(signal);
|
|
50
|
+
};
|
|
51
|
+
proc.on(signal, handler);
|
|
52
|
+
return [signal, handler];
|
|
53
|
+
});
|
|
54
|
+
return () => {
|
|
55
|
+
for (const [signal, handler] of handlers)
|
|
56
|
+
proc.off(signal, handler);
|
|
57
|
+
};
|
|
58
|
+
};
|
|
@@ -8,6 +8,7 @@ export declare class ScopedSecretService implements SecretService {
|
|
|
8
8
|
getSecret<T = string>(key: string): Promise<SecretValue<T>>;
|
|
9
9
|
hasSecret(key: string): Promise<boolean>;
|
|
10
10
|
setSecret(_key: string, _value: unknown): Promise<void>;
|
|
11
|
+
setEncryptedSecret(_key: string, _sealed: string): Promise<void>;
|
|
11
12
|
deleteSecret(_key: string): Promise<void>;
|
|
12
13
|
getSecrets<T extends Record<string, unknown> = Record<string, unknown>>(keys: (keyof T & string)[]): Promise<Partial<SecretValues<T>>>;
|
|
13
14
|
}
|
|
@@ -21,6 +21,9 @@ export class ScopedSecretService {
|
|
|
21
21
|
async setSecret(_key, _value) {
|
|
22
22
|
throw new Error('setSecret is not allowed in scoped secret service');
|
|
23
23
|
}
|
|
24
|
+
async setEncryptedSecret(_key, _sealed) {
|
|
25
|
+
throw new Error('setEncryptedSecret is not allowed in scoped secret service');
|
|
26
|
+
}
|
|
24
27
|
async deleteSecret(_key) {
|
|
25
28
|
throw new Error('deleteSecret is not allowed in scoped secret service');
|
|
26
29
|
}
|
|
@@ -13,6 +13,12 @@ export interface SecretService {
|
|
|
13
13
|
/** Answers for any key, including a disallowed one — it must not throw. */
|
|
14
14
|
hasSecret(key: string): Promise<boolean>;
|
|
15
15
|
setSecret(key: string, value: unknown): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Stores a value sealed to this service's public key, so the plaintext never
|
|
18
|
+
* reaches the caller's process. `sealed` is the serialized envelope, opaque
|
|
19
|
+
* here. Optional: only stores that hold a sealing key implement it.
|
|
20
|
+
*/
|
|
21
|
+
setEncryptedSecret?(key: string, sealed: string): Promise<void>;
|
|
16
22
|
deleteSecret(key: string): Promise<void>;
|
|
17
23
|
/**
|
|
18
24
|
* Missing keys are omitted rather than throwing, hence `Partial<T>`: callers
|
|
@@ -41,6 +41,7 @@ export declare class TypedSecretService<TMap = Record<string, unknown>> implemen
|
|
|
41
41
|
getSecret<T = string>(key: string): Promise<SecretValue<T>>;
|
|
42
42
|
hasSecret(key: string): Promise<boolean>;
|
|
43
43
|
setSecret<K extends string>(key: K, value: K extends keyof TMap ? TMap[K] : unknown): Promise<void>;
|
|
44
|
+
setEncryptedSecret(key: string, sealed: string): Promise<void>;
|
|
44
45
|
deleteSecret(key: string): Promise<void>;
|
|
45
46
|
getSecrets<T extends Record<string, unknown> = Record<string, unknown>>(keys: (keyof T & string)[]): Promise<Partial<SecretValues<T>>>;
|
|
46
47
|
getAllStatus(): Promise<CredentialStatus[]>;
|
|
@@ -33,6 +33,13 @@ export class TypedSecretService {
|
|
|
33
33
|
await this.secrets.setSecret(key, value);
|
|
34
34
|
this.cache.delete(key);
|
|
35
35
|
}
|
|
36
|
+
async setEncryptedSecret(key, sealed) {
|
|
37
|
+
if (!this.secrets.setEncryptedSecret) {
|
|
38
|
+
throw new Error('This secret service does not accept sealed secrets');
|
|
39
|
+
}
|
|
40
|
+
await this.secrets.setEncryptedSecret(key, sealed);
|
|
41
|
+
this.cache.delete(key);
|
|
42
|
+
}
|
|
36
43
|
async deleteSecret(key) {
|
|
37
44
|
await this.secrets.deleteSecret(key);
|
|
38
45
|
this.cache.delete(key);
|
|
@@ -48,6 +48,15 @@ export const defineSecretServiceTests = (name, secretService) => {
|
|
|
48
48
|
await service.deleteSecret('to-delete');
|
|
49
49
|
assert.strictEqual(await service.hasSecret('to-delete'), false);
|
|
50
50
|
});
|
|
51
|
+
test('setEncryptedSecret stores a sealed value without opening it', async (t) => {
|
|
52
|
+
const service = await factory({ key: kek });
|
|
53
|
+
if (!service.setEncryptedSecret) {
|
|
54
|
+
t.skip('store does not accept sealed secrets');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
await service.setEncryptedSecret('sealed-key', 'opaque-envelope');
|
|
58
|
+
assert.strictEqual(await service.hasSecret('sealed-key'), true);
|
|
59
|
+
});
|
|
51
60
|
test('rotateKEK re-wraps all secrets', async () => {
|
|
52
61
|
const newKEK = 'new-key-encryption-key-rotated!';
|
|
53
62
|
const oldService = await factory({ key: kek });
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Logger } from './services/logger.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { WireServices } from './types/core.types.js';
|
|
3
3
|
export declare const closeWireServices: (logger: Logger, wireServices: WireServices) => Promise<void>;
|
|
4
4
|
export declare const createWeakUID: () => string;
|
|
5
5
|
export declare const isSerializable: (data: any) => boolean;
|
|
@@ -12,10 +12,7 @@ export declare const getTagGroups: <T>(tagGroups: Record<string, T>, tag: string
|
|
|
12
12
|
*/
|
|
13
13
|
export declare const parseJson: <T = any>(input: string | Uint8Array) => T;
|
|
14
14
|
export declare const freezeDedupe: <T>(arr?: readonly T[] | T[] | undefined) => readonly T[];
|
|
15
|
-
|
|
16
|
-
export declare const stopSingletonServices: () => Promise<void>;
|
|
17
|
-
/** Wrap server lifecycle hooks so the inspector can discover them. */
|
|
18
|
-
export declare const pikkuServerLifecycle: <SS extends CoreSingletonServices = CoreSingletonServices>(lifecycle: ServerLifecycle<SS>) => ServerLifecycle<SS>;
|
|
15
|
+
export { stopSingletonServices, pikkuServerLifecycle } from './lifecycle.js';
|
|
19
16
|
export type MakeRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
|
|
20
17
|
export type JSONPrimitive = string | number | boolean | null | undefined;
|
|
21
18
|
export type JSONValue = JSONPrimitive | JSONValue[] | {
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getSingletonServices, getAllPackageStates } from './pikku-state.js';
|
|
2
1
|
import { BadRequestError } from './errors/errors.js';
|
|
3
2
|
export const closeWireServices = async (logger, wireServices) => {
|
|
4
3
|
await Promise.all(Object.values(wireServices).map(async (service) => {
|
|
@@ -77,42 +76,6 @@ export const freezeDedupe = (arr) => {
|
|
|
77
76
|
}
|
|
78
77
|
return Object.freeze(out);
|
|
79
78
|
};
|
|
80
|
-
|
|
81
|
-
const stop = service?.stop;
|
|
82
|
-
if (stop) {
|
|
83
|
-
logger.info(`Stopping singleton service: ${name}`);
|
|
84
|
-
try {
|
|
85
|
-
await stop.call(service);
|
|
86
|
-
}
|
|
87
|
-
catch (e) {
|
|
88
|
-
logger.error(`Error stopping service ${name}:`, e);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
/** Stops addon package services first, then the parent singleton services. */
|
|
93
|
-
export const stopSingletonServices = async () => {
|
|
94
|
-
const singletonServices = getSingletonServices();
|
|
95
|
-
const logger = singletonServices.logger;
|
|
96
|
-
const stateMap = getAllPackageStates();
|
|
97
|
-
if (stateMap.size > 0) {
|
|
98
|
-
for (const [packageName, packageState] of stateMap) {
|
|
99
|
-
if (packageName === '__main__')
|
|
100
|
-
continue;
|
|
101
|
-
const packageServices = packageState.package?.singletonServices;
|
|
102
|
-
if (packageServices) {
|
|
103
|
-
logger.info(`Stopping singleton services for package: ${packageName}`);
|
|
104
|
-
for (const [name, service] of Object.entries(packageServices)) {
|
|
105
|
-
await stopService(logger, `${packageName}/${name}`, service);
|
|
106
|
-
}
|
|
107
|
-
packageState.package.singletonServices = null;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
for (const [name, service] of Object.entries(singletonServices)) {
|
|
112
|
-
await stopService(logger, name, service);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
/** Wrap server lifecycle hooks so the inspector can discover them. */
|
|
116
|
-
export const pikkuServerLifecycle = (lifecycle) => lifecycle;
|
|
79
|
+
export { stopSingletonServices, pikkuServerLifecycle } from './lifecycle.js';
|
|
117
80
|
export { getDurationInMilliseconds, getRelativeTimeOffset, getRelativeTimeOffsetFromNow, parseDurationString, } from './time-utils.js';
|
|
118
81
|
export { formatVersionedId, isVersionedId, parseVersionedId, } from './version.js';
|
|
@@ -95,11 +95,26 @@ function registerCLICommands(commands, path = [], inheritedOptions = {}, program
|
|
|
95
95
|
const unwrapped = unwrapFunc(command);
|
|
96
96
|
const commandAuth = typeof command === 'object' ? command.auth : undefined;
|
|
97
97
|
const commandPermissions = typeof command === 'object' ? command.permissions : undefined;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
if (currentMeta?.packageName && !funcName.includes(':')) {
|
|
99
|
+
if (commandAuth !== undefined || commandPermissions !== undefined) {
|
|
100
|
+
const registered = pikkuState(currentMeta.packageName, 'function', 'functions');
|
|
101
|
+
const existing = registered.get(funcName);
|
|
102
|
+
if (existing) {
|
|
103
|
+
registered.set(funcName, {
|
|
104
|
+
...existing,
|
|
105
|
+
auth: commandAuth ?? existing.auth,
|
|
106
|
+
permissions: commandPermissions ?? existing.permissions,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!currentMeta?.packageName || funcName.includes(':')) {
|
|
112
|
+
addFunction(funcName, {
|
|
113
|
+
...unwrapped,
|
|
114
|
+
auth: commandAuth ?? unwrapped.auth,
|
|
115
|
+
permissions: commandPermissions ?? unwrapped.permissions,
|
|
116
|
+
}, currentMeta?.packageName);
|
|
117
|
+
}
|
|
103
118
|
if (typeof command === 'object' && command.render) {
|
|
104
119
|
if (programs[program]) {
|
|
105
120
|
programs[program].renderers[commandId] = command.render;
|
|
@@ -110,11 +125,11 @@ function registerCLICommands(commands, path = [], inheritedOptions = {}, program
|
|
|
110
125
|
}
|
|
111
126
|
}
|
|
112
127
|
}
|
|
113
|
-
function pluckCLIData(mergedData, funcName, availableOptions) {
|
|
114
|
-
const funcMeta = pikkuState(null, 'function', 'meta')[funcName];
|
|
128
|
+
function pluckCLIData(mergedData, funcName, availableOptions, packageName) {
|
|
129
|
+
const funcMeta = pikkuState(packageName ?? null, 'function', 'meta')[funcName];
|
|
115
130
|
const schemaName = funcMeta?.inputSchemaName;
|
|
116
131
|
const schema = schemaName
|
|
117
|
-
? pikkuState(funcMeta?.packageName ?? null, 'misc', 'schemas').get(schemaName)
|
|
132
|
+
? pikkuState(packageName ?? funcMeta?.packageName ?? null, 'misc', 'schemas').get(schemaName)
|
|
118
133
|
: null;
|
|
119
134
|
if (schema && schema.properties) {
|
|
120
135
|
const result = {};
|
|
@@ -172,7 +187,7 @@ export async function runCLICommand({ program, commandPath, data, singletonServi
|
|
|
172
187
|
}
|
|
173
188
|
const commandId = commandPath.join('.');
|
|
174
189
|
const availableOptions = programData?.commandOptions?.[commandId] || {};
|
|
175
|
-
const pluckedData = () => pluckCLIData(data, funcName, availableOptions);
|
|
190
|
+
const pluckedData = () => pluckCLIData(data, funcName, availableOptions, currentCommand.packageName);
|
|
176
191
|
const renderer = programData?.renderers[commandId] || programData?.defaultRenderer;
|
|
177
192
|
let cliState;
|
|
178
193
|
const channel = {
|
|
@@ -164,6 +164,10 @@ const executeRoute = async (services, matchedRoute, http, options) => {
|
|
|
164
164
|
await originalClose();
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
|
+
response.onClose?.(() => {
|
|
168
|
+
channel.state = 'closed';
|
|
169
|
+
singletonServices.eventHub?.onChannelClosed(channelId);
|
|
170
|
+
});
|
|
167
171
|
}
|
|
168
172
|
const wire = {
|
|
169
173
|
traceId: requestId,
|
|
@@ -185,6 +185,7 @@ export interface PikkuHTTPResponse<Out = unknown> {
|
|
|
185
185
|
send?(data: string | ArrayBuffer | ArrayBufferView): this;
|
|
186
186
|
redirect(location: string, status?: number): this;
|
|
187
187
|
close?: () => void;
|
|
188
|
+
onClose?: (callback: () => void) => void;
|
|
188
189
|
setMode?: (mode: 'stream') => void;
|
|
189
190
|
flushHeaders?: () => void;
|
|
190
191
|
}
|
|
@@ -14,6 +14,7 @@ export declare class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
|
|
|
14
14
|
send(data: any): this;
|
|
15
15
|
redirect(location: string, status?: number): this;
|
|
16
16
|
close(): this;
|
|
17
|
+
onClose(callback: () => void): void;
|
|
17
18
|
toResponse(args?: Record<string, any>): Response;
|
|
18
19
|
private createStream;
|
|
19
20
|
}
|
|
@@ -8,6 +8,7 @@ export class PikkuFetchHTTPResponse {
|
|
|
8
8
|
#send = null;
|
|
9
9
|
#close = null;
|
|
10
10
|
#cancelStream = null;
|
|
11
|
+
#onClose = [];
|
|
11
12
|
setMode(mode) {
|
|
12
13
|
this.#responseMode = 'stream';
|
|
13
14
|
if (mode === 'stream') {
|
|
@@ -95,6 +96,15 @@ export class PikkuFetchHTTPResponse {
|
|
|
95
96
|
}
|
|
96
97
|
return this;
|
|
97
98
|
}
|
|
99
|
+
onClose(callback) {
|
|
100
|
+
this.#onClose.push(callback);
|
|
101
|
+
}
|
|
102
|
+
#closed() {
|
|
103
|
+
const callbacks = this.#onClose;
|
|
104
|
+
this.#onClose = [];
|
|
105
|
+
for (const callback of callbacks)
|
|
106
|
+
callback();
|
|
107
|
+
}
|
|
98
108
|
toResponse(args) {
|
|
99
109
|
const cookieHeader = Array.from(this.#cookies.entries()).map(([name, { value, flags }]) => stringifySetCookie({ name, value, ...flags }, flags));
|
|
100
110
|
cookieHeader.forEach((cookie) => this.#headers.append('Set-Cookie', cookie));
|
|
@@ -119,9 +129,11 @@ export class PikkuFetchHTTPResponse {
|
|
|
119
129
|
return;
|
|
120
130
|
closed = true;
|
|
121
131
|
controller.close();
|
|
132
|
+
this.#closed();
|
|
122
133
|
};
|
|
123
134
|
this.#cancelStream = () => {
|
|
124
135
|
closed = true;
|
|
136
|
+
this.#closed();
|
|
125
137
|
};
|
|
126
138
|
this.#send = send;
|
|
127
139
|
this.#close = close;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
|
|
1
2
|
export function toWebRequest(req, baseUrl) {
|
|
2
3
|
const proto = req.header('x-forwarded-proto') ?? 'http';
|
|
3
4
|
const host = req.header('x-forwarded-host') ?? req.header('host') ?? 'localhost';
|
|
@@ -120,6 +121,12 @@ export async function applyWebResponse(res, webResponse) {
|
|
|
120
121
|
if (setCookieValues.length > 0) {
|
|
121
122
|
res.header('Set-Cookie', setCookieValues);
|
|
122
123
|
}
|
|
124
|
+
if (webResponse.body &&
|
|
125
|
+
res instanceof PikkuFetchHTTPResponse &&
|
|
126
|
+
webResponse.headers.get('content-type')?.startsWith('text/event-stream')) {
|
|
127
|
+
res.send(webResponse.body);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
123
130
|
const body = await readBody(webResponse);
|
|
124
131
|
if (body !== null) {
|
|
125
132
|
if (res.send) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/core",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.141",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/pikkujs/pikku.git",
|
|
@@ -87,6 +87,7 @@
|
|
|
87
87
|
"./state": "./dist/pikku-state.js",
|
|
88
88
|
"./classification": "./dist/classification/index.js",
|
|
89
89
|
"./utils": "./dist/utils.js",
|
|
90
|
+
"./lifecycle": "./dist/lifecycle.js",
|
|
90
91
|
"./schema": "./dist/schema.js",
|
|
91
92
|
"./testing": "./dist/testing/index.js",
|
|
92
93
|
"./dev": "./dist/dev/hot-reload.js"
|
package/src/public-surface.json
CHANGED