@deployanyway/doggo-log 0.0.0-stage → 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/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — Unreleased
4
+
5
+ - Six logging methods, level filtering, quiet mode, and custom prefixes.
6
+ - Optional emojis, ANSI colors, timestamps, and JSON output.
7
+ - CLI, tests, documentation, and Node 22/24 CI.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Deploy Anyway
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 CHANGED
@@ -1,4 +1,141 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
4
- If no other versions are published within 30 days, this package and version will be deleted.
1
+ # doggo-log
2
+
3
+ A tiny dog-themed logger with useful output and good manners.
4
+
5
+ ```text
6
+ 🐶 INFO Server started
7
+ 🐾 SUCCESS Tests passed
8
+ 🦴 WARN API is getting slow
9
+ 🚨 ERROR Database connection failed
10
+ ```
11
+
12
+ ## Installation
13
+
14
+ Version 0.1.0 has not been published to npm. Try from source with Node 22 or 24:
15
+
16
+ ```sh
17
+ git clone https://github.com/DeployAnyway/doggo-log.git
18
+ cd doggo-log
19
+ git checkout feature/initial-mvp
20
+ npm ci
21
+ node examples/basic.js
22
+ ```
23
+
24
+ After an approved release: `npm install @deployanyway/doggo-log`.
25
+
26
+ ## Quick start
27
+
28
+ ```js
29
+ import { doglog, createDogLogger } from "@deployanyway/doggo-log";
30
+
31
+ doglog.info("Server started");
32
+ doglog.success("Tests passed");
33
+ doglog.warn("API is getting slow");
34
+ doglog.error("Database connection failed");
35
+
36
+ const logger = createDogLogger({
37
+ timestamp: true,
38
+ level: "debug",
39
+ prefix: "app",
40
+ });
41
+ logger.debug("Listening on port %d", 3000);
42
+ ```
43
+
44
+ ## CLI example
45
+
46
+ ```sh
47
+ node bin/cli.js success "Tests passed" --no-emoji
48
+ node bin/cli.js info "Server started" --json --timestamp
49
+ ```
50
+
51
+ After publication: `npx @deployanyway/doggo-log info "Server started"`.
52
+
53
+ ## API
54
+
55
+ `doglog` is the default logger. `createDogLogger(options = {})` makes an independent
56
+ logger. Both expose `log`, `info`, `success`, `warn`, `error`, and `debug`.
57
+ Methods accept the same message arguments as Node's `util.format`, including
58
+ format placeholders, objects, and Error instances. Zero arguments log the label
59
+ alone. Each method returns its emitted string, or undefined if filtered/quiet.
60
+
61
+ Default output sends warn/error to stderr and other methods to stdout. Logging
62
+ an error does not set an exit code. The library never calls process.exit.
63
+ Errors from a custom output function propagate to the caller.
64
+
65
+ ## Options
66
+
67
+ | Option | Default | Behavior |
68
+ | ----------- | -------------- | ------------------------------------------------------ |
69
+ | `emoji` | true | Dog-themed level symbols |
70
+ | `color` | false | ANSI color for text lines; ignored for JSON |
71
+ | `timestamp` | false | UTC ISO timestamp |
72
+ | `json` | false | One JSON object per call; emoji/color omitted |
73
+ | `quiet` | false | Suppress all output |
74
+ | `prefix` | empty string | Text prefix or JSON prefix field |
75
+ | `level` | info | Minimum level |
76
+ | `write` | console output | Function `(line, level)` for each emitted line |
77
+ | `clock` | current Date | Function returning a valid Date when timestamp enabled |
78
+
79
+ Levels: debug (10), log/info/success (20), warn (30), error (40). Thresholds
80
+ include all levels with equal or higher ranks. At info, debug is suppressed.
81
+ At warn, only warn and error appear. JSON always includes `level` and `message`,
82
+ with `prefix` and `timestamp` included when enabled/nonempty. Object arguments
83
+ are formatted into the message string; they are not separate JSON fields.
84
+
85
+ Invalid options throw TypeError; unknown levels throw RangeError. Names are case
86
+ sensitive. Unknown option keys are ignored. Quiet/filtered calls skip message
87
+ formatting, clock calls, and output. No transports, rotation, telemetry, remote
88
+ service, or production dependencies are required.
89
+
90
+ ## CLI reference
91
+
92
+ `doggo-log <method> <message> [options]`
93
+
94
+ | Flag | Behavior |
95
+ | ----------------- | --------------------------------- |
96
+ | `--json` | JSON output |
97
+ | `--timestamp` | ISO timestamp |
98
+ | `--no-emoji` | Plain labels |
99
+ | `--color` | ANSI color |
100
+ | `--prefix text` | Prefix |
101
+ | `--level name` | Minimum level (CLI default debug) |
102
+ | `--quiet` | Suppress output |
103
+ | `--help`, `-h` | Usage |
104
+ | `--version`, `-v` | Version |
105
+
106
+ Quote messages containing shell punctuation. Use `--` before positional arguments
107
+ containing dash-prefixed text. CLI messages are strings, without placeholder
108
+ interpolation. Exit 0 means success (including filtered calls and error logging);
109
+ exit 2 means invalid arguments. No stdin support in this MVP.
110
+
111
+ ## Development and examples
112
+
113
+ ```sh
114
+ npm ci
115
+ node examples/basic.js
116
+ npm test
117
+ npm run lint
118
+ npm run format:check
119
+ npm pack --dry-run
120
+ ```
121
+
122
+ ES modules and Node's test runner. CI runs Node 22/24. Development tooling requires
123
+ Node 22.13+ or 24. Styles and behavior are separate for easy contributions.
124
+
125
+ ## Contributing
126
+
127
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
128
+
129
+ ## License
130
+
131
+ [MIT](LICENSE).
132
+
133
+ ## More from DeployAnyway
134
+
135
+ **Tools for developers who probably know better.**
136
+
137
+ - [error-translator](https://github.com/DeployAnyway/error-translator)
138
+ - [excuse-js](https://github.com/DeployAnyway/excuse-js)
139
+ - [doggo-log](https://github.com/DeployAnyway/doggo-log)
140
+ - [ship-it-meter](https://github.com/DeployAnyway/ship-it-meter)
141
+ - [bro-say](https://github.com/DeployAnyway/bro-say)
package/bin/cli.js ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from "node:util";
3
+ import { readFileSync } from "node:fs";
4
+ import { URL } from "node:url";
5
+ import { createDogLogger } from "../src/index.js";
6
+ import { levels } from "../src/levels.js";
7
+
8
+ try {
9
+ const { values, positionals } = parseArgs({
10
+ allowPositionals: true,
11
+ options: {
12
+ help: { type: "boolean", short: "h" },
13
+ version: { type: "boolean", short: "v" },
14
+ json: { type: "boolean" },
15
+ timestamp: { type: "boolean" },
16
+ quiet: { type: "boolean" },
17
+ color: { type: "boolean" },
18
+ "no-emoji": { type: "boolean" },
19
+ prefix: { type: "string" },
20
+ level: { type: "string", default: "debug" },
21
+ },
22
+ });
23
+ if (values.help) {
24
+ console.log(
25
+ "Usage: doggo-log <method> <message> [options]\n\nMethods: log, info, success, warn, error, debug\nOptions:\n --json Emit JSON\n --timestamp Include an ISO timestamp\n --no-emoji Disable emojis\n --color Enable ANSI colors\n --prefix text Add a prefix\n --level name Minimum level (CLI default: debug)\n --quiet Suppress output\n -h, --help Show help\n -v, --version Show version\n\nExit codes: 0 success; 2 invalid arguments. Logging an error exits 0.",
26
+ );
27
+ } else if (values.version) {
28
+ console.log(
29
+ JSON.parse(
30
+ readFileSync(new URL("../package.json", import.meta.url), "utf8"),
31
+ ).version,
32
+ );
33
+ } else {
34
+ const [method, ...message] = positionals;
35
+ if (!Object.hasOwn(levels, method ?? "") || !message.join(" ").trim())
36
+ throw new TypeError("Provide a valid method and nonempty message.");
37
+ const logger = createDogLogger({
38
+ emoji: !values["no-emoji"],
39
+ color: values.color ?? false,
40
+ timestamp: values.timestamp ?? false,
41
+ json: values.json ?? false,
42
+ quiet: values.quiet ?? false,
43
+ prefix: values.prefix ?? "",
44
+ level: values.level,
45
+ });
46
+ logger[method](message.join(" "));
47
+ }
48
+ } catch (error) {
49
+ console.error(`doggo-log: ${error.message}\nRun with --help for usage.`);
50
+ process.exitCode = 2;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,41 @@
1
- {
2
- "name": "@deployanyway/doggo-log",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "@deployanyway/doggo-log",
3
+ "version": "0.1.0",
4
+ "description": "A tiny dog-themed logger with useful output and good manners.",
5
+ "type": "module",
6
+ "exports": "./src/index.js",
7
+ "bin": {
8
+ "doggo-log": "./bin/cli.js"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "bin",
13
+ "README.md",
14
+ "LICENSE",
15
+ "CHANGELOG.md"
16
+ ],
17
+ "engines": {
18
+ "node": ">=22"
19
+ },
20
+ "scripts": {
21
+ "test": "node --test",
22
+ "lint": "eslint .",
23
+ "format": "prettier --write .",
24
+ "format:check": "prettier --check ."
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/DeployAnyway/doggo-log.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/DeployAnyway/doggo-log/issues"
32
+ },
33
+ "license": "MIT",
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "devDependencies": {
38
+ "eslint": "^10.12.0",
39
+ "prettier": "^3.6.2"
40
+ }
41
+ }
package/src/index.js ADDED
@@ -0,0 +1,80 @@
1
+ import { format } from "node:util";
2
+ import { levels } from "./levels.js";
3
+
4
+ /**
5
+ * Create a small logger. Methods return the emitted line, or undefined if filtered.
6
+ * @param {{emoji?: boolean, color?: boolean, timestamp?: boolean, json?: boolean, quiet?: boolean, prefix?: string, level?: string, write?: (line: string, level: string) => void, clock?: () => Date}} [options]
7
+ */
8
+ export function createDogLogger(options = {}) {
9
+ if (!options || typeof options !== "object" || Array.isArray(options))
10
+ throw new TypeError("Options must be an object.");
11
+ const config = {
12
+ emoji: true,
13
+ color: false,
14
+ timestamp: false,
15
+ json: false,
16
+ quiet: false,
17
+ prefix: "",
18
+ level: "info",
19
+ write: (line, level) =>
20
+ level === "warn" || level === "error"
21
+ ? console.error(line)
22
+ : console.log(line),
23
+ clock: () => new Date(),
24
+ ...options,
25
+ };
26
+ for (const key of ["emoji", "color", "timestamp", "json", "quiet"]) {
27
+ if (typeof config[key] !== "boolean")
28
+ throw new TypeError(`${key} must be a boolean.`);
29
+ }
30
+ if (typeof config.prefix !== "string")
31
+ throw new TypeError("prefix must be a string.");
32
+ if (typeof config.level !== "string" || !Object.hasOwn(levels, config.level))
33
+ throw new RangeError(
34
+ `level must be one of: ${Object.keys(levels).join(", ")}.`,
35
+ );
36
+ if (typeof config.write !== "function" || typeof config.clock !== "function")
37
+ throw new TypeError("write and clock must be functions.");
38
+ return Object.fromEntries(
39
+ Object.entries(levels).map(([level, style]) => [
40
+ level,
41
+ (...args) => {
42
+ if (config.quiet || style.rank < levels[config.level].rank)
43
+ return undefined;
44
+ const message = format(...args);
45
+ let timestamp;
46
+ if (config.timestamp) {
47
+ const date = config.clock();
48
+ if (!(date instanceof Date) || !Number.isFinite(date.getTime()))
49
+ throw new TypeError("clock must return a valid Date.");
50
+ timestamp = date.toISOString();
51
+ }
52
+ let line;
53
+ if (config.json) {
54
+ line = JSON.stringify({
55
+ level,
56
+ message,
57
+ ...(config.prefix ? { prefix: config.prefix } : {}),
58
+ ...(timestamp ? { timestamp } : {}),
59
+ });
60
+ } else {
61
+ line = [
62
+ timestamp,
63
+ config.prefix,
64
+ config.emoji ? style.emoji : undefined,
65
+ level.toUpperCase().padEnd(7),
66
+ message,
67
+ ]
68
+ .filter((part) => part !== undefined && part !== "")
69
+ .join(" ");
70
+ if (config.color) line = `\u001b[${style.color}m${line}\u001b[0m`;
71
+ }
72
+ config.write(line, level);
73
+ return line;
74
+ },
75
+ ]),
76
+ );
77
+ }
78
+
79
+ /** Default logger: emoji enabled, no timestamp/color, info threshold. */
80
+ export const doglog = createDogLogger();
package/src/levels.js ADDED
@@ -0,0 +1,8 @@
1
+ export const levels = {
2
+ debug: { rank: 10, emoji: "🔍", color: 90 },
3
+ log: { rank: 20, emoji: "🐶", color: 37 },
4
+ info: { rank: 20, emoji: "🐶", color: 36 },
5
+ success: { rank: 20, emoji: "🐾", color: 32 },
6
+ warn: { rank: 30, emoji: "🦴", color: 33 },
7
+ error: { rank: 40, emoji: "🚨", color: 31 },
8
+ };